diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..ca8b63cc4 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,130 @@ +name: Build + +on: + workflow_dispatch: + push: + paths-ignore: + - '.github/ISSUE_TEMPLATE/*.yml' + - '.github/actions/pullrequest.yml' + - '.idea/copyright/*.xml' + - '.gitignore' + - 'CONTRIBUTING.md' + - 'LICENSE' + - 'Jenkinsfile ' + - 'README.md' + - 'licenseheader.txt' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout repository and submodules + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Validate Gradle Wrapper + uses: gradle/wrapper-validation-action@v1 + + - uses: actions/setup-java@v3 + with: + java-version: 17 + distribution: temurin + + - name: Build + uses: gradle/gradle-build-action@v2 + with: + arguments: build + gradle-home-cache-cleanup: true + + - name: Archive artifacts (Geyser Fabric) + uses: actions/upload-artifact@v3 + if: success() + with: + name: Geyser Fabric + path: bootstrap/fabric/build/libs/Geyser-Fabric.jar + if-no-files-found: error + - name: Archive artifacts (Geyser Standalone) + uses: actions/upload-artifact@v3 + if: success() + with: + name: Geyser Standalone + path: bootstrap/standalone/build/libs/Geyser-Standalone.jar + if-no-files-found: error + - name: Archive artifacts (Geyser Spigot) + uses: actions/upload-artifact@v3 + if: success() + with: + name: Geyser Spigot + path: bootstrap/spigot/build/libs/Geyser-Spigot.jar + if-no-files-found: error + - name: Archive artifacts (Geyser BungeeCord) + uses: actions/upload-artifact@v3 + if: success() + with: + name: Geyser BungeeCord + path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + if-no-files-found: error + - name: Archive artifacts (Geyser Sponge) + uses: actions/upload-artifact@v3 + if: success() + with: + name: Geyser Sponge + path: bootstrap/sponge/build/libs/Geyser-Sponge.jar + if-no-files-found: error + - name: Archive artifacts (Geyser Velocity) + uses: actions/upload-artifact@v3 + if: success() + with: + name: Geyser Velocity + path: bootstrap/velocity/build/libs/Geyser-Velocity.jar + if-no-files-found: error + + - name: Publish to Maven Repository + if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + uses: gradle/gradle-build-action@v2 + env: + ORG_GRADLE_PROJECT_geysermcUsername: ${{ vars.DEPLOY_USER }} + ORG_GRADLE_PROJECT_geysermcPassword: ${{ secrets.DEPLOY_PASS }} + with: + arguments: publish + + - name: Publish to Downloads API + if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + shell: bash + env: + DOWNLOADS_USERNAME: ${{ vars.DOWNLOADS_USERNAME }} + DOWNLOADS_PRIVATE_KEY: ${{ secrets.DOWNLOADS_PRIVATE_KEY }} + DOWNLOADS_SERVER_IP: ${{ secrets.DOWNLOADS_SERVER_IP }} + run: | + # Save the private key to a file + echo "$DOWNLOADS_PRIVATE_KEY" > id_ecdsa + chmod 600 id_ecdsa + # Set the project + project=geyser + # Get the version from gradle.properties + version=$(cat gradle.properties | grep -o "version=[0-9\\.]*" | cut -d"=" -f2) + # Create the build folder + ssh -o StrictHostKeyChecking=no -i id_ecdsa $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP mkdir -p "~/uploads/$project/$GITHUB_RUN_NUMBER/" + # Copy over artifacts + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" bootstrap/**/build/libs/Geyser-*.jar $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ + # Run the build script + # Push the metadata + echo "{\"project\": \"$project\", \"version\": \"$version\", \"id\": $GITHUB_RUN_NUMBER, \"commit\": \"$GITHUB_SHA\"}" > metadata.json + rsync -P -e "ssh -o StrictHostKeyChecking=no -i id_ecdsa" metadata.json $DOWNLOADS_USERNAME@$DOWNLOADS_SERVER_IP:~/uploads/$project/$GITHUB_RUN_NUMBER/ + + - name: Publish to Modrinth + uses: gradle/gradle-build-action@v2 + if: ${{ success() && github.repository == 'GeyserMC/Geyser' && github.ref_name == 'master' }} + env: + MODRINTH_TOKEN: ${{ secrets.MODRINTH_TOKEN }} + with: + arguments: fabric:modrinth + gradle-home-cache-cleanup: true + + - name: Notify Discord + if: ${{ (success() || failure()) && github.repository == 'GeyserMC/Geyser' }} + uses: Tim203/actions-git-discord-webhook@main + with: + webhook_url: ${{ secrets.DISCORD_WEBHOOK }} + status: ${{ job.status }} diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 39e9fe188..9567fb414 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -1,58 +1,96 @@ name: Build Pull Request -on: [pull_request] +on: + pull_request: + paths-ignore: + - '.github/ISSUE_TEMPLATE/*.yml' + - '.idea/copyright/*.xml' + - '.gitignore' + - 'CONTRIBUTING.md' + - 'LICENSE' + - 'Jenkinsfile ' + - 'README.md' + - 'licenseheader.txt' jobs: build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - name: Set up JDK 17 uses: actions/setup-java@v1 with: - distribution: 'temurin' java-version: 17 - cache: 'gradle' - - name: submodules-init - uses: snickerbockers/submodules-init@v4 - - name: Build with Gradle - run: ./gradlew build + distribution: temurin + + - name: Check if the author has forked the API repo + uses: Kas-tle/ForkFinder@v1.0.1 + id: find_forks + with: + owner: GeyserMC + repo: api + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Use author's API repo if it exists + if: steps.find_forks.outputs.target_branch_found == 'true' + env: + API_FORK_URL: ${{ steps.find_forks.outputs.user_fork_url }} + API_FORK_BRANCH: ${{ github.event.pull_request.head.ref }} + run: | + git clone "${API_FORK_URL}" --single-branch --branch "${API_FORK_BRANCH}" api + cd api + ./gradlew publishToMavenLocal + + - name: Checkout repository and submodules + uses: actions/checkout@v3 + with: + submodules: recursive + path: geyser + + - name: Build Geyser + uses: gradle/gradle-build-action@v2 + with: + arguments: build + build-root-directory: geyser - name: Archive artifacts (Geyser Fabric) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: success() with: name: Geyser Fabric - path: bootstrap/fabric/build/libs/Geyser-Fabric.jar + path: geyser/bootstrap/fabric/build/libs/Geyser-Fabric.jar + if-no-files-found: error - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: success() with: name: Geyser Standalone - path: bootstrap/standalone/build/libs/Geyser-Standalone.jar + path: geyser/bootstrap/standalone/build/libs/Geyser-Standalone.jar + if-no-files-found: error - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: success() with: name: Geyser Spigot - path: bootstrap/spigot/build/libs/Geyser-Spigot.jar + path: geyser/bootstrap/spigot/build/libs/Geyser-Spigot.jar + if-no-files-found: error - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: success() with: name: Geyser BungeeCord - path: bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + path: geyser/bootstrap/bungeecord/build/libs/Geyser-BungeeCord.jar + if-no-files-found: error - name: Archive artifacts (Geyser Sponge) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: success() with: name: Geyser Sponge - path: bootstrap/sponge/build/libs/Geyser-Sponge.jar + path: geyser/bootstrap/sponge/build/libs/Geyser-Sponge.jar + if-no-files-found: error - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 if: success() with: name: Geyser Velocity - path: bootstrap/velocity/build/libs/Geyser-Velocity.jar + path: geyser/bootstrap/velocity/build/libs/Geyser-Velocity.jar + if-no-files-found: error diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce6894845..dac8a9a07 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,4 +48,6 @@ Make sure to comment your code where possible. The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`. -We have a rundown of all the tools you need to develop over on our [wiki](https://github.com/GeyserMC/Geyser/wiki/Developer-Guide). If you have any questions, please feel free to reach out to our [Discord](https://discord.gg/geysermc)! +We have a rundown of all the tools you need to develop over on our [wiki](https://wiki.geysermc.org/other/developer-guide/). If you have any questions, please feel free to reach out to our [Discord](https://discord.gg/geysermc)! + +If you're making a pull request that also depends on changes to [the base API](https://github.com/GeyserMC/api), simply fork the API repo and create a branch with the same name as your Geyser PR. The pull request [action](https://github.com/GeyserMC/Geyser/blob/master/.github/workflows/pullrequest.yml) will automatically use your API changes while building your changes to Geyser. \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 072f99154..5c2eada3d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -24,80 +24,9 @@ pipeline { } } } - - stage ('Deploy') { - when { - anyOf { - branch "master" - } - } - - steps { - rtGradleDeployer( - id: "GRADLE_DEPLOYER", - serverId: "opencollab-artifactory", - releaseRepo: "maven-releases", - snapshotRepo: "maven-snapshots" - ) - rtGradleResolver( - id: "GRADLE_RESOLVER", - serverId: "opencollab-artifactory" - ) - rtGradleRun( - usesPlugin: true, - tool: 'Gradle 7', - rootDir: "", - useWrapper: true, - buildFile: 'build.gradle.kts', - tasks: 'artifactoryPublish', - deployerId: "GRADLE_DEPLOYER", - resolverId: "GRADLE_RESOLVER" - ) - rtPublishBuildInfo( - serverId: "opencollab-artifactory" - ) - } - } } post { - always { - script { - def changeLogSets = currentBuild.changeSets - def message = "**Changes:**" - - if (changeLogSets.size() == 0) { - message += "\n*No changes.*" - } else { - def repositoryUrl = scm.userRemoteConfigs[0].url.replace(".git", "") - def count = 0; - def extra = 0; - for (int i = 0; i < changeLogSets.size(); i++) { - def entries = changeLogSets[i].items - for (int j = 0; j < entries.length; j++) { - if (count <= 10) { - def entry = entries[j] - def commitId = entry.commitId.substring(0, 6) - message += "\n - [`${commitId}`](${repositoryUrl}/commit/${entry.commitId}) ${entry.msg}" - count++ - } else { - extra++; - } - } - } - - if (extra != 0) { - message += "\n - ${extra} more commits" - } - } - - env.changes = message - } - deleteDir() - withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { - discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Geyser)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK - } - } success { script { if (env.BRANCH_NAME == 'master') { diff --git a/README.md b/README.md index b36235e36..77e2671f9 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,6 @@ Geyser -[![forthebadge made-with-java](https://forthebadge.com/images/badges/made-with-java.svg)](https://java.com/) - [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Build Status](https://ci.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](https://discord.gg/geysermc) [![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/) @@ -17,7 +14,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! -### Currently supporting Minecraft Bedrock 1.19.20 - 1.19.60 and Minecraft Java 1.19.3. +### Currently supporting Minecraft Bedrock 1.19.30 - 1.19.71 and Minecraft Java 1.19.4. ## Setting Up Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. @@ -27,7 +24,7 @@ Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Ge ## Links: - Website: https://geysermc.org - Docs: https://wiki.geysermc.org/geyser/ -- Download: https://ci.geysermc.org +- Download: https://geysermc.org/download - Discord: https://discord.gg/geysermc - Donate: https://opencollective.com/geysermc - Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock diff --git a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/BedrockEmoteEvent.java b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/ClientEmoteEvent.java similarity index 92% rename from api/src/main/java/org/geysermc/geyser/api/event/bedrock/BedrockEmoteEvent.java rename to api/src/main/java/org/geysermc/geyser/api/event/bedrock/ClientEmoteEvent.java index efe3f12d6..35b6a9e73 100644 --- a/api/src/main/java/org/geysermc/geyser/api/event/bedrock/BedrockEmoteEvent.java +++ b/api/src/main/java/org/geysermc/geyser/api/event/bedrock/ClientEmoteEvent.java @@ -33,11 +33,11 @@ import org.geysermc.geyser.api.event.connection.ConnectionEvent; /** * Called whenever a Bedrock player performs an emote on their end, before it is broadcasted to the rest of the server. */ -public final class BedrockEmoteEvent extends ConnectionEvent implements Cancellable { +public final class ClientEmoteEvent extends ConnectionEvent implements Cancellable { private final String emoteId; private boolean cancelled; - public BedrockEmoteEvent(@NonNull GeyserConnection connection, @NonNull String emoteId) { + public ClientEmoteEvent(@NonNull GeyserConnection connection, @NonNull String emoteId) { super(connection); this.emoteId = emoteId; } diff --git a/bootstrap/fabric/build.gradle.kts b/bootstrap/fabric/build.gradle.kts index 743b75a26..35270df80 100644 --- a/bootstrap/fabric/build.gradle.kts +++ b/bootstrap/fabric/build.gradle.kts @@ -1,5 +1,6 @@ plugins { id("fabric-loom") version "1.0-SNAPSHOT" + id("com.modrinth.minotaur") version "2.+" } java { @@ -65,6 +66,22 @@ tasks { relocate("org.yaml", "org.geysermc.relocate.yaml") // https://github.com/CardboardPowered/cardboard/issues/139 relocate("com.fasterxml.jackson", "org.geysermc.relocate.jackson") relocate("net.kyori", "org.geysermc.relocate.kyori") + + dependencies { + // Exclude everything EXCEPT KQueue and some DNS stuff required for HAProxyc + exclude(dependency("io.netty:netty-transport-classes-epoll:.*")) + exclude(dependency("io.netty:netty-transport-native-epoll:.*")) + exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) + exclude(dependency("io.netty:netty-transport-native-kqueue:.*")) + exclude(dependency("io.netty:netty-handler:.*")) + exclude(dependency("io.netty:netty-common:.*")) + exclude(dependency("io.netty:netty-buffer:.*")) + exclude(dependency("io.netty:netty-resolver:.*")) + exclude(dependency("io.netty:netty-transport:.*")) + exclude(dependency("io.netty:netty-codec:.*")) + exclude(dependency("io.netty:netty-resolver-dns:.*")) + exclude(dependency("io.netty:netty-resolver-dns-native-macos:.*")) + } } remapJar { @@ -74,4 +91,23 @@ tasks { archiveClassifier.set("") archiveVersion.set("") } +} + +modrinth { + token.set(System.getenv("MODRINTH_TOKEN")) // Even though this is the default value, apparently this prevents GitHub Actions caching the token? + projectId.set("wKkoqHrH") + versionNumber.set(project.version as String + "-" + System.getenv("GITHUB_RUN_NUMBER")) + versionType.set("beta") + changelog.set("A changelog can be found at https://github.com/GeyserMC/Geyser/commits") + + syncBodyFrom.set(rootProject.file("README.md").readText()) + + uploadFile.set(tasks.getByPath("remapJar")) + gameVersions.addAll("1.19", "1.19.1", "1.19.2", "1.19.3", "1.19.4") + + loaders.add("fabric") + + dependencies { + required.project("fabric-api") + } } \ No newline at end of file diff --git a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java index 108d88e8b..454a9167e 100644 --- a/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java +++ b/bootstrap/fabric/src/main/java/org/geysermc/geyser/platform/fabric/world/GeyserFabricWorldManager.java @@ -25,13 +25,7 @@ package org.geysermc.geyser.platform.fabric.world; -import org.cloudburstmc.math.vector.Vector3i; -<<<<<<< HEAD -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; -======= ->>>>>>> d1febe0b3904d52cdc6301711950f22d1caf09b5 +import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.core.BlockPos; import net.minecraft.nbt.*; @@ -43,19 +37,20 @@ import net.minecraft.world.item.WrittenBookItem; import net.minecraft.world.level.block.entity.BannerBlockEntity; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.LecternBlockEntity; +import net.minecraft.world.level.chunk.LevelChunk; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; +import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.level.GeyserWorldManager; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.util.BlockEntityUtils; import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; public class GeyserFabricWorldManager extends GeyserWorldManager { private final MinecraftServer server; @@ -65,69 +60,91 @@ public class GeyserFabricWorldManager extends GeyserWorldManager { } @Override - public boolean shouldExpectLecternHandled() { + public boolean shouldExpectLecternHandled(GeyserSession session) { return true; } @Override - public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { - Runnable lecternGet = () -> { - // Mostly a reimplementation of Spigot lectern support + public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) { + server.execute(() -> { ServerPlayer player = getPlayer(session); - if (player != null) { - BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z)); - if (!(blockEntity instanceof LecternBlockEntity lectern)) { - return; - } - - if (!lectern.hasBook()) { - if (!isChunkLoad) { - BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); - } - return; - } - - ItemStack book = lectern.getBook(); - int pageCount = WrittenBookItem.getPageCount(book); - boolean hasBookPages = pageCount > 0; - NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1); - lecternTag.putInt("page", lectern.getPage() / 2); - NbtMapBuilder bookTag = NbtMap.builder() - .putByte("Count", (byte) book.getCount()) - .putShort("Damage", (short) 0) - .putString("Name", "minecraft:writable_book"); - List pages = new ArrayList<>(hasBookPages ? pageCount : 1); - if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) { - ListTag listTag = book.getTag().getList("pages", 8); - - for (int i = 0; i < listTag.size(); i++) { - String page = listTag.getString(i); - NbtMapBuilder pageBuilder = NbtMap.builder() - .putString("photoname", "") - .putString("text", page); - pages.add(pageBuilder.build()); - } - } else { - // Empty page - NbtMapBuilder pageBuilder = NbtMap.builder() - .putString("photoname", "") - .putString("text", ""); - pages.add(pageBuilder.build()); - } - - bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); - lecternTag.putCompound("book", bookTag.build()); - NbtMap blockEntityTag = lecternTag.build(); - BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); + if (player == null) { + return; } - }; - if (isChunkLoad) { - // Hacky hacks to allow lectern loading to be delayed - session.scheduleInEventLoop(() -> server.execute(lecternGet), 1, TimeUnit.SECONDS); - } else { - server.execute(lecternGet); + + LevelChunk chunk = player.getLevel().getChunk(x, z); + final int chunkBlockX = x << 4; + final int chunkBlockZ = z << 4; + for (int i = 0; i < blockEntityInfos.size(); i++) { + BlockEntityInfo blockEntityInfo = blockEntityInfos.get(i); + BlockEntity blockEntity = chunk.getBlockEntity(new BlockPos(chunkBlockX + blockEntityInfo.getX(), + blockEntityInfo.getY(), chunkBlockZ + blockEntityInfo.getZ())); + sendLecternData(session, blockEntity, true); + } + }); + } + + @Override + public void sendLecternData(GeyserSession session, int x, int y, int z) { + server.execute(() -> { + ServerPlayer player = getPlayer(session); + if (player == null) { + return; + } + + BlockEntity blockEntity = player.level.getBlockEntity(new BlockPos(x, y, z)); + sendLecternData(session, blockEntity, false); + }); + } + + private void sendLecternData(GeyserSession session, BlockEntity blockEntity, boolean isChunkLoad) { + if (!(blockEntity instanceof LecternBlockEntity lectern)) { + return; } - return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); + + int x = blockEntity.getBlockPos().getX(); + int y = blockEntity.getBlockPos().getY(); + int z = blockEntity.getBlockPos().getZ(); + + if (!lectern.hasBook()) { + if (!isChunkLoad) { + BlockEntityUtils.updateBlockEntity(session, LecternUtils.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); + } + return; + } + + ItemStack book = lectern.getBook(); + int pageCount = WrittenBookItem.getPageCount(book); + boolean hasBookPages = pageCount > 0; + NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, hasBookPages ? pageCount : 1); + lecternTag.putInt("page", lectern.getPage() / 2); + NbtMapBuilder bookTag = NbtMap.builder() + .putByte("Count", (byte) book.getCount()) + .putShort("Damage", (short) 0) + .putString("Name", "minecraft:writable_book"); + List pages = new ArrayList<>(hasBookPages ? pageCount : 1); + if (hasBookPages && WritableBookItem.makeSureTagIsValid(book.getTag())) { + ListTag listTag = book.getTag().getList("pages", 8); + + for (int i = 0; i < listTag.size(); i++) { + String page = listTag.getString(i); + NbtMapBuilder pageBuilder = NbtMap.builder() + .putString("photoname", "") + .putString("text", page); + pages.add(pageBuilder.build()); + } + } else { + // Empty page + NbtMapBuilder pageBuilder = NbtMap.builder() + .putString("photoname", "") + .putString("text", ""); + pages.add(pageBuilder.build()); + } + + bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); + lecternTag.putCompound("book", bookTag.build()); + NbtMap blockEntityTag = lecternTag.build(); + BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); } @Override diff --git a/bootstrap/spigot/build.gradle.kts b/bootstrap/spigot/build.gradle.kts index b5ef4e69e..aa7958732 100644 --- a/bootstrap/spigot/build.gradle.kts +++ b/bootstrap/spigot/build.gradle.kts @@ -1,5 +1,8 @@ dependencies { api(projects.core) + api(libs.erosion.bukkit.common) { + isTransitive = false + } implementation(libs.adapters.spigot) @@ -7,8 +10,8 @@ dependencies { implementation(libs.adventure.text.serializer.bungeecord) - // Both paper-api and paper-mojangapi only provide Java 17 versions for 1.19 - compileOnly(libs.paper.api) { + // Both folia-api and paper-mojangapi only provide Java 17 versions for 1.19 + compileOnly(libs.folia.api) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) } @@ -44,6 +47,7 @@ tasks.withType { // We cannot shade Netty, or else native libraries will not load // Needed because older Spigot builds do not provide the haproxy module + exclude(dependency("io.netty:netty-transport-classes-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-epoll:.*")) exclude(dependency("io.netty:netty-transport-native-unix-common:.*")) exclude(dependency("io.netty:netty-transport-native-kqueue:.*")) diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java index 36dd81d44..bb0f30e70 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserPaperPingPassthrough.java @@ -59,13 +59,13 @@ public final class GeyserPaperPingPassthrough implements IGeyserPingPassthrough // runtime because we still have to shade in our own Adventure class. For now. PaperServerListPingEvent event; if (OLD_CONSTRUCTOR != null) { - // Approximately pre-1.19 + // 1.19, removed in 1.19.4 event = OLD_CONSTRUCTOR.newInstance(new GeyserStatusClient(inetSocketAddress), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers(), Bukkit.getVersion(), GameProtocol.getJavaProtocolVersion(), null); } else { event = new PaperServerListPingEvent(new GeyserStatusClient(inetSocketAddress), - Bukkit.getMotd(), Bukkit.shouldSendChatPreviews(), Bukkit.getOnlinePlayers().size(), + Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers(), Bukkit.getVersion(), GameProtocol.getJavaProtocolVersion(), null); } Bukkit.getPluginManager().callEvent(event); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java index 634d1f8a8..1e6a0ad6c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPingPassthrough.java @@ -66,7 +66,7 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough { private static class GeyserPingEvent extends ServerListPingEvent { public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) { - super(address, motd, Bukkit.shouldSendChatPreviews(), numPlayers, maxPlayers); + super("", address, motd, numPlayers, maxPlayers); } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java index 3185f2d30..67e31fea2 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/ReflectedNames.java @@ -60,16 +60,16 @@ public final class ReflectedNames { } static Constructor getOldPaperPingConstructor() { - if (getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, boolean.class, int.class, + if (getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, int.class, int.class, String.class, int.class, CachedServerIcon.class) != null) { - // @NotNull StatusClient client, @NotNull String motd, boolean shouldSendChatPreviews, int numPlayers, int maxPlayers, + // @NotNull StatusClient client, @NotNull String motd, int numPlayers, int maxPlayers, // @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon // New constructor is present return null; } - // @NotNull StatusClient client, @NotNull String motd, int numPlayers, int maxPlayers, + // @NotNull StatusClient client, @NotNull String motd, boolean shouldSendChatPreviews, int numPlayers, int maxPlayers, // @NotNull String version, int protocolVersion, @Nullable CachedServerIcon favicon - return getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, int.class, int.class, + return getConstructor(PaperServerListPingEvent.class, StatusClient.class, String.class, boolean.class, int.class, int.class, String.class, int.class, CachedServerIcon.class); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java index 50caf8db2..01b0be9f2 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserPistonListener.java @@ -27,8 +27,8 @@ package org.geysermc.geyser.platform.spigot.world; import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; import org.cloudburstmc.math.vector.Vector3i; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -85,7 +85,7 @@ public class GeyserPistonListener implements Listener { PistonValueType type = isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING; boolean sticky = event.isSticky(); - Object2IntMap attachedBlocks = new Object2IntOpenHashMap<>(); + Object2IntMap attachedBlocks = new Object2IntArrayMap<>(); boolean blocksFilled = false; for (Map.Entry entry : geyser.getSessionManager().getSessions().entrySet()) { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java index 5ea67a42f..d54926a5b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotWorldManager.java @@ -25,33 +25,28 @@ package org.geysermc.geyser.platform.spigot.world.manager; +import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.World; -import org.bukkit.block.*; -import org.bukkit.block.banner.Pattern; +import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BookMeta; import org.bukkit.plugin.Plugin; -import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; -import org.cloudburstmc.nbt.NbtType; +import org.geysermc.erosion.bukkit.BukkitLecterns; +import org.geysermc.erosion.bukkit.BukkitUtils; +import org.geysermc.erosion.bukkit.PickBlockUtils; +import org.geysermc.erosion.bukkit.SchedulerUtils; import org.geysermc.geyser.level.GameRule; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; -import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator; import org.geysermc.geyser.util.BlockEntityUtils; import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -60,9 +55,11 @@ import java.util.concurrent.CompletableFuture; */ public class GeyserSpigotWorldManager extends WorldManager { private final Plugin plugin; + private final BukkitLecterns lecterns; public GeyserSpigotWorldManager(Plugin plugin) { this.plugin = plugin; + this.lecterns = new BukkitLecterns(plugin); } @Override @@ -81,6 +78,12 @@ public class GeyserSpigotWorldManager extends WorldManager { } public int getBlockNetworkId(Block block) { + if (SchedulerUtils.FOLIA && !Bukkit.isOwnedByCurrentRegion(block)) { + // Terrible behavior, but this is basically what's always been happening behind the scenes anyway. + CompletableFuture blockData = new CompletableFuture<>(); + Bukkit.getRegionScheduler().execute(this.plugin, block.getLocation(), () -> blockData.complete(block.getBlockData().getAsString())); + return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(blockData.join(), BlockStateValues.JAVA_AIR_ID); + } return BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(block.getBlockData().getAsString(), BlockStateValues.JAVA_AIR_ID); } @@ -90,71 +93,64 @@ public class GeyserSpigotWorldManager extends WorldManager { } @Override - public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { - // Run as a task to prevent async issues - Runnable lecternInfoGet = () -> { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return; - } - - Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); - if (!(block.getState() instanceof Lectern lectern)) { - session.getGeyser().getLogger().error("Lectern expected at: " + Vector3i.from(x, y, z).toString() + " but was not! " + block.toString()); - return; - } - - ItemStack itemStack = lectern.getInventory().getItem(0); - if (itemStack == null || !(itemStack.getItemMeta() instanceof BookMeta bookMeta)) { - if (!isChunkLoad) { - // We need to update the lectern since it's not going to be updated otherwise - BlockEntityUtils.updateBlockEntity(session, LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(), Vector3i.from(x, y, z)); - } - // We don't care; return - return; - } - - // On the count: allow the book to show/open even there are no pages. We know there is a book here, after all, and this matches Java behavior - boolean hasBookPages = bookMeta.getPageCount() > 0; - NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, hasBookPages ? bookMeta.getPageCount() : 1); - lecternTag.putInt("page", lectern.getPage() / 2); - NbtMapBuilder bookTag = NbtMap.builder() - .putByte("Count", (byte) itemStack.getAmount()) - .putShort("Damage", (short) 0) - .putString("Name", "minecraft:writable_book"); - List pages = new ArrayList<>(bookMeta.getPageCount()); - if (hasBookPages) { - for (String page : bookMeta.getPages()) { - NbtMapBuilder pageBuilder = NbtMap.builder() - .putString("photoname", "") - .putString("text", page); - pages.add(pageBuilder.build()); - } - } else { - // Empty page - NbtMapBuilder pageBuilder = NbtMap.builder() - .putString("photoname", "") - .putString("text", ""); - pages.add(pageBuilder.build()); - } - - bookTag.putCompound("tag", NbtMap.builder().putList("pages", NbtType.COMPOUND, pages).build()); - lecternTag.putCompound("book", bookTag.build()); - NbtMap blockEntityTag = lecternTag.build(); - BlockEntityUtils.updateBlockEntity(session, blockEntityTag, Vector3i.from(x, y, z)); - }; - - if (isChunkLoad) { - // Delay to ensure the chunk is sent first, and then the lectern data - Bukkit.getScheduler().runTaskLater(this.plugin, lecternInfoGet, 5); - } else { - Bukkit.getScheduler().runTask(this.plugin, lecternInfoGet); + public void sendLecternData(GeyserSession session, int x, int y, int z) { + Player bukkitPlayer; + if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { + return; + } + + Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); + // Run as a task to prevent async issues + SchedulerUtils.runTask(this.plugin, () -> sendLecternData(session, block, false), block); + } + + public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) { + Player bukkitPlayer; + if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { + return; + } + if (SchedulerUtils.FOLIA) { + Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z); + if (chunk == null) { + return; + } + Bukkit.getRegionScheduler().execute(this.plugin, bukkitPlayer.getWorld(), x, z, () -> + sendLecternData(session, chunk, blockEntityInfos)); + } else { + Bukkit.getScheduler().runTask(this.plugin, () -> { + Chunk chunk = getChunk(bukkitPlayer.getWorld(), x, z); + if (chunk == null) { + return; + } + sendLecternData(session, chunk, blockEntityInfos); + }); + } + } + + private Chunk getChunk(World world, int x, int z) { + if (!world.isChunkLoaded(x, z)) { + return null; + } + return world.getChunkAt(x, z); + } + + private void sendLecternData(GeyserSession session, Chunk chunk, List blockEntityInfos) { + for (int i = 0; i < blockEntityInfos.size(); i++) { + BlockEntityInfo info = blockEntityInfos.get(i); + Block block = chunk.getBlock(info.getX(), info.getY(), info.getZ()); + sendLecternData(session, block, true); + } + } + + private void sendLecternData(GeyserSession session, Block block, boolean isChunkLoad) { + NbtMap blockEntityTag = this.lecterns.getLecternData(block, isChunkLoad); + if (blockEntityTag != null) { + BlockEntityUtils.updateBlockEntity(session, blockEntityTag, BukkitUtils.getVector(block.getLocation())); } - return LecternInventoryTranslator.getBaseLecternTag(x, y, z, 0).build(); // Will be updated later } @Override - public boolean shouldExpectLecternHandled() { + public boolean shouldExpectLecternHandled(GeyserSession session) { return true; } @@ -184,42 +180,18 @@ public class GeyserSpigotWorldManager extends WorldManager { @Override public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { CompletableFuture<@Nullable CompoundTag> future = new CompletableFuture<>(); + Player bukkitPlayer; + if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { + future.complete(null); + return future; + } + Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); // Paper 1.19.3 complains about async access otherwise. // java.lang.IllegalStateException: Tile is null, asynchronous access? - Bukkit.getScheduler().runTask(this.plugin, () -> { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUuid())) == null) { - future.complete(null); - return; - } - - Block block = bukkitPlayer.getWorld().getBlockAt(x, y, z); - BlockState state = block.getState(); - if (state instanceof Banner banner) { - ListTag list = new ListTag("Patterns"); - for (int i = 0; i < banner.numberOfPatterns(); i++) { - Pattern pattern = banner.getPattern(i); - list.add(BannerTranslator.getJavaPatternTag(pattern.getPattern().getIdentifier(), pattern.getColor().ordinal())); - } - - CompoundTag root = addToBlockEntityTag(list); - - future.complete(root); - return; - } - future.complete(null); - }); + SchedulerUtils.runTask(this.plugin, () -> future.complete(PickBlockUtils.pickBlock(block)), block); return future; } - private CompoundTag addToBlockEntityTag(Tag tag) { - CompoundTag compoundTag = new CompoundTag(""); - CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(tag); - compoundTag.put(blockEntityTag); - return compoundTag; - } - /** * This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id * to the current one. diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml index e28b8981d..6e81ccdb6 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/spigot/src/main/resources/plugin.yml @@ -5,7 +5,12 @@ website: ${url} version: ${version} softdepend: ["ViaVersion", "floodgate"] api-version: 1.13 +folia-supported: true commands: geyser: description: The main command for Geyser. - usage: /geyser \ No newline at end of file + usage: /geyser + permission: geyser.command +permissions: + geyser.command: + default: true diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts index e21806660..3d1fb47f7 100644 --- a/build-logic/build.gradle.kts +++ b/build-logic/build.gradle.kts @@ -1,5 +1,3 @@ -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - plugins { `kotlin-dsl` } @@ -10,17 +8,10 @@ repositories { } dependencies { - implementation("net.kyori", "indra-common", "2.0.6") - implementation("org.jfrog.buildinfo", "build-info-extractor-gradle", "4.26.1") + implementation("net.kyori", "indra-common", "3.0.1") implementation("com.github.johnrengelman", "shadow", "7.1.3-SNAPSHOT") // Within the gradle plugin classpath, there is a version conflict between loom and some other // plugin for databind. This fixes it: minimum 2.13.2 is required by loom. implementation("com.fasterxml.jackson.core:jackson-databind:2.14.0") } - -tasks.withType { - kotlinOptions { - jvmTarget = "16" - } -} diff --git a/build-logic/src/main/kotlin/extensions.kt b/build-logic/src/main/kotlin/extensions.kt index 0c01913d2..1e1732852 100644 --- a/build-logic/src/main/kotlin/extensions.kt +++ b/build-logic/src/main/kotlin/extensions.kt @@ -30,9 +30,6 @@ import org.gradle.api.artifacts.ProjectDependency import org.gradle.api.provider.Provider import org.gradle.kotlin.dsl.named -fun Project.isSnapshot(): Boolean = - version.toString().endsWith("-SNAPSHOT") - fun Project.relocate(pattern: String) { tasks.named("shadowJar") { relocate(pattern, "org.geysermc.geyser.shaded.$pattern") diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 44a74db3d..709867300 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -1,12 +1,25 @@ plugins { `java-library` - `maven-publish` + id("net.kyori.indra") } dependencies { compileOnly("org.checkerframework", "checker-qual", "3.19.0") } +indra { + github("GeyserMC", "Geyser") { + ci(true) + issues(true) + scm(true) + } + mitLicense() + + javaVersions { + target(16) + } +} + tasks { processResources { // Spigot, BungeeCord, Velocity, Sponge, Fabric @@ -21,14 +34,4 @@ tasks { ) } } - compileJava { - options.encoding = Charsets.UTF_8.name() - } -} - -java { - sourceCompatibility = JavaVersion.VERSION_16 - targetCompatibility = JavaVersion.VERSION_16 - - withSourcesJar() } diff --git a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts index 7525f97fa..036ee803c 100644 --- a/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.publish-conventions.gradle.kts @@ -1,33 +1,9 @@ plugins { id("geyser.shadow-conventions") - id("com.jfrog.artifactory") - id("maven-publish") + id("net.kyori.indra.publishing") } -publishing { - publications { - create("mavenJava") { - groupId = project.group as String - artifactId = project.name - version = project.version as String - - from(components["java"]) - } - } -} - -artifactory { - setContextUrl("https://repo.opencollab.dev/artifactory") - publish { - repository { - setRepoKey(if (isSnapshot()) "maven-snapshots" else "maven-releases") - setMavenCompatible(true) - } - defaults { - publications("mavenJava") - setPublishArtifacts(true) - setPublishPom(true) - setPublishIvy(false) - } - } +indra { + publishSnapshotsTo("geysermc", "https://repo.opencollab.dev/maven-snapshots") + publishReleasesTo("geysermc", "https://repo.opencollab.dev/maven-releases") } diff --git a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts index 395beb104..dde85c33a 100644 --- a/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.shadow-conventions.gradle.kts @@ -24,6 +24,11 @@ tasks { exclude(dependency(string)) } } + + sJar.dependencies { + exclude(dependency("org.checkerframework:checker-qual:.*")) + exclude(dependency("org.jetbrains:annotations:.*")) + } } } named("build") { diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 2c1e1fc1e..444a393fa 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -29,10 +29,6 @@ dependencies { exclude("com.github.GeyserMC", "mcauthlib") } - api(libs.packetlib) { - exclude("io.netty", "netty-all") - } - implementation(libs.raknet) { exclude("io.netty", "*"); } @@ -51,6 +47,10 @@ dependencies { // Adventure text serialization api(libs.bundles.adventure) + api(libs.erosion.common) { + isTransitive = false + } + // Test testImplementation(libs.junit) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 73ea88f37..e9c567473 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -47,6 +47,7 @@ import org.geysermc.api.Geyser; import org.geysermc.common.PlatformType; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormBuilder; +import org.geysermc.erosion.packet.Packets; import org.geysermc.floodgate.crypto.AesCipher; import org.geysermc.floodgate.crypto.AesKeyProducer; import org.geysermc.floodgate.crypto.Base64Topping; @@ -64,6 +65,7 @@ import org.geysermc.geyser.api.network.RemoteServer; import org.geysermc.geyser.command.GeyserCommandManager; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.erosion.UnixSocketClientListener; import org.geysermc.geyser.event.GeyserEventBus; import org.geysermc.geyser.extension.GeyserExtensionManager; import org.geysermc.geyser.level.WorldManager; @@ -137,6 +139,8 @@ public class GeyserImpl implements GeyserApi { private FloodgateSkinUploader skinUploader; private NewsHandler newsHandler; + private UnixSocketClientListener erosionUnixListener; + private volatile boolean shuttingDown = false; private ScheduledExecutorService scheduledThread; @@ -290,6 +294,14 @@ public class GeyserImpl implements GeyserApi { this.newsHandler = new NewsHandler(BRANCH, this.buildNumber()); + Packets.initGeyser(); + + if (Epoll.isAvailable()) { + this.erosionUnixListener = new UnixSocketClientListener(); + } else { + logger.debug("Epoll is not available; Erosion's Unix socket handling will not work."); + } + CooldownUtils.setDefaultShowCooldown(config.getShowCooldown()); DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether @@ -542,6 +554,10 @@ public class GeyserImpl implements GeyserApi { newsHandler.shutdown(); this.commandManager().getCommands().clear(); + if (this.erosionUnixListener != null) { + this.erosionUnixListener.close(); + } + ResourcePack.PACKS.clear(); this.eventBus.fire(new GeyserShutdownEvent(this.extensionManager, this.eventBus)); diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java index 3258e8d22..6188e6924 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/OffhandCommand.java @@ -25,10 +25,6 @@ package org.geysermc.geyser.command.defaults; -import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; -import org.cloudburstmc.math.vector.Vector3i; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.command.GeyserCommandSource; @@ -46,9 +42,7 @@ public class OffhandCommand extends GeyserCommand { return; } - ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, - Direction.DOWN, 0); - session.sendDownstreamPacket(releaseItemPacket); + session.requestOffhandSwap(); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java index 4843df72b..ea4c31876 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -83,8 +83,6 @@ public interface GeyserConfiguration { boolean isDisableBedrockScaffolding(); - boolean isAlwaysQuickChangeArmor(); - EmoteOffhandWorkaroundOption getEmoteOffhandWorkaround(); String getDefaultLocale(); diff --git a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java index dc675319b..bbfa37ec2 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -111,9 +111,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("disable-bedrock-scaffolding") private boolean disableBedrockScaffolding = false; - @JsonProperty("always-quick-change-armor") - private boolean alwaysQuickChangeArmor = false; - @JsonDeserialize(using = EmoteOffhandWorkaroundOption.Deserializer.class) @JsonProperty("emote-offhand-workaround") private EmoteOffhandWorkaroundOption emoteOffhandWorkaround = EmoteOffhandWorkaroundOption.DISABLED; diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index c3b1d49c4..9c7e19853 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -148,6 +148,7 @@ public final class EntityDefinitions { public static final EntityDefinition STRAY; public static final EntityDefinition STRIDER; public static final EntityDefinition TADPOLE; + public static final EntityDefinition TEXT_DISPLAY; public static final EntityDefinition TNT; public static final EntityDefinition TNT_MINECART; public static final EntityDefinition TRADER_LLAMA; @@ -295,6 +296,28 @@ public final class EntityDefinitions { .addTranslator(MetadataType.INT, TNTEntity::setFuseLength) .build(); + EntityDefinition displayBase = EntityDefinition.inherited(entityBase.factory(), entityBase) + .addTranslator(null) // Interpolation start ticks + .addTranslator(null) // Interpolation duration ID + .addTranslator(null) // Translation + .addTranslator(null) // Scale + .addTranslator(null) // Left rotation + .addTranslator(null) // Right rotation + .addTranslator(null) // Billboard render constraints + .addTranslator(null) // Brightness override + .addTranslator(null) // View range + .addTranslator(null) // Shadow radius + .addTranslator(null) // Shadow strength + .addTranslator(null) // Width + .addTranslator(null) // Height + .addTranslator(null) // Glow color override + .build(); + TEXT_DISPLAY = EntityDefinition.inherited(TextDisplayEntity::new, displayBase) + .type(EntityType.TEXT_DISPLAY) + .identifier("minecraft:armor_stand") + .addTranslator(MetadataType.CHAT, TextDisplayEntity::setText) + .build(); + EntityDefinition fireballBase = EntityDefinition.inherited(FireballEntity::new, entityBase) .addTranslator(null) // Item .build(); @@ -486,7 +509,7 @@ public final class EntityDefinitions { ENDERMAN = EntityDefinition.inherited(EndermanEntity::new, mobEntityBase) .type(EntityType.ENDERMAN) .height(2.9f).width(0.6f) - .addTranslator(MetadataType.BLOCK_STATE, EndermanEntity::setCarriedBlock) + .addTranslator(MetadataType.OPTIONAL_BLOCK_STATE, EndermanEntity::setCarriedBlock) .addTranslator(MetadataType.BOOLEAN, EndermanEntity::setScreaming) .addTranslator(MetadataType.BOOLEAN, EndermanEntity::setAngry) .build(); @@ -858,7 +881,6 @@ public final class EntityDefinitions { { EntityDefinition abstractHorseEntityBase = EntityDefinition.inherited(AbstractHorseEntity::new, ageableEntityBase) .addTranslator(MetadataType.BYTE, AbstractHorseEntity::setHorseFlags) - .addTranslator(null) // UUID of owner .build(); CAMEL = EntityDefinition.inherited(CamelEntity::new, abstractHorseEntityBase) .type(EntityType.CAMEL) diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java index f9da5c69f..1bf6e581e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java @@ -124,7 +124,11 @@ public class BoatEntity extends Entity { public void setVariant(IntEntityMetadata entityMetadata) { variant = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityDataTypes.VARIANT, variant); + dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) { + case 6, 7 -> variant - 1; // Dark oak and mangrove + case 5, 8 -> 0; // TODO temp until 1.20. Cherry and bamboo + default -> variant; + }); } public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java index 2885cfd23..bcbff16ce 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FishingHookEntity.java @@ -30,12 +30,11 @@ import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import lombok.Getter; +import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.level.block.BlockPositionIterator; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.physics.BoundingBox; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.util.BlockUtils; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java index 19125a0a8..bb67a60f6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemEntity.java @@ -40,11 +40,12 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; import java.util.UUID; +import java.util.concurrent.CompletableFuture; public class ItemEntity extends ThrowableEntity { protected ItemData item; - private int waterLevel = -1; + private CompletableFuture waterLevel = CompletableFuture.completedFuture(-1); public ItemEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); @@ -111,15 +112,15 @@ public class ItemEntity extends ThrowableEntity { @Override protected void moveAbsoluteImmediate(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { float offset = definition.offset(); - if (waterLevel == 0) { // Item is in a full block of water + if (waterLevel.join() == 0) { // Item is in a full block of water // Move the item entity down so it doesn't float above the water offset = -definition.offset(); } super.moveAbsoluteImmediate(position.add(0, offset, 0), 0, 0, 0, isOnGround, teleported); this.position = position; - int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt()); - waterLevel = BlockStateValues.getWaterLevel(block); + waterLevel = session.getGeyser().getWorldManager().getBlockAtAsync(session, position.getFloorX(), position.getFloorY(), position.getFloorZ()) + .thenApply(BlockStateValues::getWaterLevel); } @Override @@ -144,6 +145,6 @@ public class ItemEntity extends ThrowableEntity { @Override protected boolean isInWater() { - return waterLevel != -1; + return waterLevel.join() != -1; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java index d4f1ae762..98c2edd00 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TNTEntity.java @@ -43,7 +43,7 @@ public class TNTEntity extends Entity implements Tickable { } public void setFuseLength(IntEntityMetadata entityMetadata) { - currentTick = ((IntEntityMetadata) entityMetadata).getPrimitiveValue(); + currentTick = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.IGNITED, true); dirtyMetadata.put(EntityDataTypes.FUSE_TIME, currentTick); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java new file mode 100644 index 000000000..f2671f7a9 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TextDisplayEntity.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.entity.type; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import net.kyori.adventure.text.Component; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.text.MessageTranslator; + +import java.util.UUID; + +// Note: 1.19.4 requires that the billboard is set to something in order to show, on Java Edition +public class TextDisplayEntity extends Entity { + public TextDisplayEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); + } + + @Override + protected void initializeMetadata() { + super.initializeMetadata(); + // Remove armor stand body + this.dirtyMetadata.put(EntityDataTypes.SCALE, 0f); + this.dirtyMetadata.put(EntityDataTypes.NAMETAG_ALWAYS_SHOW, (byte) 1); + } + + public void setText(EntityMetadata entityMetadata) { + this.dirtyMetadata.put(EntityDataTypes.NAME, MessageTranslator.convertMessage(entityMetadata.getValue())); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java index 7e1a39dd5..80a5af442 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SquidEntity.java @@ -34,12 +34,13 @@ import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; +import java.util.concurrent.CompletableFuture; public class SquidEntity extends WaterEntity implements Tickable { private float targetPitch; private float targetYaw; - private boolean inWater; + private CompletableFuture inWater = CompletableFuture.completedFuture(Boolean.FALSE); public SquidEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); @@ -50,7 +51,7 @@ public class SquidEntity extends WaterEntity implements Tickable { boolean pitchChanged; boolean yawChanged; float oldPitch = pitch; - if (inWater) { + if (inWater.join()) { float oldYaw = yaw; pitch += (targetPitch - pitch) * 0.1f; yaw += (targetYaw - yaw) * 0.1f; @@ -93,7 +94,7 @@ public class SquidEntity extends WaterEntity implements Tickable { @Override public void setYaw(float yaw) { // Let the Java server control yaw when the squid is out of water - if (!inWater) { + if (!inWater.join()) { this.yaw = yaw; } } @@ -127,10 +128,10 @@ public class SquidEntity extends WaterEntity implements Tickable { private void checkInWater() { if (getFlag(EntityFlag.RIDING)) { - inWater = false; + inWater = CompletableFuture.completedFuture(false); } else { - int block = session.getGeyser().getWorldManager().getBlockAt(session, position.toInt()); - inWater = BlockStateValues.getWaterLevel(block) != -1; + inWater = session.getGeyser().getWorldManager().getBlockAtAsync(session, position.toInt()) + .thenApply(block -> BlockStateValues.getWaterLevel(block) != -1); } } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java index 0634f4727..0d52b7a35 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java @@ -25,9 +25,8 @@ package org.geysermc.geyser.entity.type.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.OptionalIntMetadataType; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; @@ -37,7 +36,6 @@ import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; -import java.util.OptionalInt; import java.util.UUID; public class EndermanEntity extends MonsterEntity { @@ -46,13 +44,8 @@ public class EndermanEntity extends MonsterEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } - public void setCarriedBlock(EntityMetadata entityMetadata) { - BlockDefinition bedrockBlockId; - if (entityMetadata.getValue().isPresent()) { - bedrockBlockId = session.getBlockMappings().getBedrockBlock(entityMetadata.getValue().getAsInt()); - } else { - bedrockBlockId = session.getBlockMappings().getBedrockAir(); - } + public void setCarriedBlock(IntEntityMetadata entityMetadata) { + BlockDefinition bedrockBlockId = session.getBlockMappings().getBedrockBlock(entityMetadata.getPrimitiveValue()); dirtyMetadata.put(EntityDataTypes.CARRY_BLOCK_STATE, bedrockBlockId); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java index ee622dc42..27dd45f40 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ShulkerEntity.java @@ -43,6 +43,15 @@ public class ShulkerEntity extends GolemEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); // Indicate that invisibility should be fixed through the resource pack setFlag(EntityFlag.BRIBED, true); + + } + + @Override + protected void initializeMetadata() { + super.initializeMetadata(); + // As of 1.19.4, it seems Java no longer sends the shulker color if it's the default color on initial spawn + // We still need the special case for 16 color in setShulkerColor though as it will send it for an entity metadata update + dirtyMetadata.put(EntityDataTypes.VARIANT, 16); } public void setAttachedFace(EntityMetadata entityMetadata) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java index 547c9c559..b060758ae 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java @@ -247,7 +247,10 @@ public class PlayerEntity extends LivingEntity { @Override public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { - return bedPosition = super.setBedPosition(entityMetadata); + bedPosition = super.setBedPosition(entityMetadata); + // Fixes https://github.com/GeyserMC/Geyser/issues/3595 on vanilla 1.19.3 servers - did not happen on Paper + entityMetadata.getValue().ifPresent(pos -> this.setPosition(pos.toFloat())); + return bedPosition; } public void setAbsorptionHearts(FloatEntityMetadata entityMetadata) { diff --git a/core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java b/core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java new file mode 100644 index 000000000..eabed8f7b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/erosion/AbstractGeyserboundPacketHandler.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.erosion; + +import org.geysermc.erosion.packet.geyserbound.*; +import org.geysermc.geyser.session.GeyserSession; +import org.jetbrains.annotations.Nullable; + +public abstract class AbstractGeyserboundPacketHandler implements GeyserboundPacketHandler { + protected final GeyserSession session; + + public AbstractGeyserboundPacketHandler(GeyserSession session) { + this.session = session; + } + + @Override + public void handleBatchBlockId(GeyserboundBatchBlockIdPacket packet) { + illegalPacket(packet); + } + + @Override + public void handleBlockEntity(GeyserboundBlockEntityPacket packet) { + illegalPacket(packet); + } + + @Override + public void handleBlockId(GeyserboundBlockIdPacket packet) { + illegalPacket(packet); + } + + @Override + public void handleBlockLookupFail(GeyserboundBlockLookupFailPacket packet) { + illegalPacket(packet); + } + + @Override + public void handleBlockPlace(GeyserboundBlockPlacePacket packet) { + illegalPacket(packet); + } + + @Override + public void handlePistonEvent(GeyserboundPistonEventPacket packet) { + illegalPacket(packet); + } + + @Override + public void handlePickBlock(GeyserboundPickBlockPacket packet) { + illegalPacket(packet); + } + + /** + * Is this handler actually listening to any packets? + */ + public abstract boolean isActive(); + + @Nullable + public abstract GeyserboundPacketHandlerImpl getAsActive(); + + public void close() { + } + + protected final void illegalPacket(GeyserboundPacket packet) { + session.getGeyser().getLogger().warning("Illegal packet sent from backend server! " + packet); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java new file mode 100644 index 000000000..610917adc --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserErosionPacketSender.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.erosion; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import org.geysermc.erosion.Constants; +import org.geysermc.erosion.packet.ErosionPacketSender; +import org.geysermc.erosion.packet.Packets; +import org.geysermc.erosion.packet.backendbound.BackendboundPacket; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.PluginMessageUtils; + +import java.io.IOException; + +public record GeyserErosionPacketSender(GeyserSession session) implements ErosionPacketSender { + + @Override + public void sendPacket(BackendboundPacket packet) { + ByteBuf buf = Unpooled.buffer(); + try { + Packets.encode(buf, packet); + byte[] bytes = new byte[buf.readableBytes()]; + buf.readBytes(bytes); + PluginMessageUtils.sendMessage(session, Constants.PLUGIN_MESSAGE, bytes); + } catch (IOException e) { + e.printStackTrace(); + } finally { + buf.release(); + } + } + + @Override + public void setChannel(Channel channel) { + } +} diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java new file mode 100644 index 000000000..196595383 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundHandshakePacketHandler.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.erosion; + +import io.netty.channel.Channel; +import org.geysermc.erosion.netty.NettyPacketSender; +import org.geysermc.erosion.packet.ErosionPacketHandler; +import org.geysermc.erosion.packet.geyserbound.GeyserboundHandshakePacket; +import org.geysermc.geyser.session.GeyserSession; +import org.jetbrains.annotations.Nullable; + +public final class GeyserboundHandshakePacketHandler extends AbstractGeyserboundPacketHandler { + + public GeyserboundHandshakePacketHandler(GeyserSession session) { + super(session); + } + + @Override + public void handleHandshake(GeyserboundHandshakePacket packet) { + boolean useTcp = packet.getTransportType().getSocketAddress() == null; + GeyserboundPacketHandlerImpl handler = new GeyserboundPacketHandlerImpl(session, useTcp ? new GeyserErosionPacketSender(session) : new NettyPacketSender<>()); + session.setErosionHandler(handler); + if (!useTcp) { + if (session.getGeyser().getErosionUnixListener() == null) { + session.disconnect("Erosion configurations using Unix socket handling are not supported on this hardware!"); + return; + } + session.getGeyser().getErosionUnixListener().createClient(handler, packet.getTransportType().getSocketAddress()); + } else { + handler.onConnect(); + } + session.ensureInEventLoop(() -> session.getChunkCache().clear()); + } + + @Override + public boolean isActive() { + return false; + } + + @Override + public @Nullable GeyserboundPacketHandlerImpl getAsActive() { + return null; + } + + @Override + public ErosionPacketHandler setChannel(Channel channel) { + return null; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java new file mode 100644 index 000000000..3ae458f63 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/erosion/GeyserboundPacketHandlerImpl.java @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.erosion; + +import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValueType; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import io.netty.channel.Channel; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import lombok.Getter; +import lombok.Setter; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.protocol.bedrock.data.SoundEvent; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; +import org.geysermc.erosion.packet.ErosionPacketHandler; +import org.geysermc.erosion.packet.ErosionPacketSender; +import org.geysermc.erosion.packet.backendbound.BackendboundInitializePacket; +import org.geysermc.erosion.packet.backendbound.BackendboundPacket; +import org.geysermc.erosion.packet.geyserbound.*; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.physics.Direction; +import org.geysermc.geyser.network.GameProtocol; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.PistonCache; +import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; +import org.geysermc.geyser.util.BlockEntityUtils; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; + +public final class GeyserboundPacketHandlerImpl extends AbstractGeyserboundPacketHandler { + private final ErosionPacketSender packetSender; + @Setter + private CompletableFuture pendingLookup = null; + @Getter + private final Int2ObjectMap> asyncPendingLookups = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>(4)); + @Setter + private CompletableFuture pendingBatchLookup = null; + @Setter + private CompletableFuture pickBlockLookup = null; + + private final AtomicInteger nextTransactionId = new AtomicInteger(1); + + public GeyserboundPacketHandlerImpl(GeyserSession session, ErosionPacketSender packetSender) { + super(session); + this.packetSender = packetSender; + } + + @Override + public void handleBatchBlockId(GeyserboundBatchBlockIdPacket packet) { + if (this.pendingBatchLookup != null) { + this.pendingBatchLookup.complete(packet.getBlocks()); + } else { + session.getGeyser().getLogger().warning("Batch block ID packet received with no future to complete."); + } + } + + @Override + public void handleBlockEntity(GeyserboundBlockEntityPacket packet) { + NbtMap nbt = packet.getNbt(); + BlockEntityUtils.updateBlockEntity(session, nbt, Vector3i.from(nbt.getInt("x"), nbt.getInt("y"), nbt.getInt("z"))); + } + + @Override + public void handleBlockId(GeyserboundBlockIdPacket packet) { + if (packet.getTransactionId() == 0) { + if (this.pendingLookup != null) { + this.pendingLookup.complete(packet.getBlockId()); + return; + } + } + CompletableFuture future = this.asyncPendingLookups.remove(packet.getTransactionId()); + if (future != null) { + future.complete(packet.getBlockId()); + return; + } + session.getGeyser().getLogger().warning("Block ID packet received with no future to complete."); + } + + @Override + public void handleBlockLookupFail(GeyserboundBlockLookupFailPacket packet) { + if (packet.getTransactionId() == 0) { + if (this.pendingBatchLookup != null) { + this.pendingBatchLookup.complete(null); + return; + } + } + int transactionId = packet.getTransactionId() - 1; + if (transactionId == 0) { + if (this.pendingLookup != null) { + this.pendingLookup.complete(0); + } + } + CompletableFuture future = this.asyncPendingLookups.remove(transactionId); + if (future != null) { + future.complete(BlockStateValues.JAVA_AIR_ID); + } + } + + @Override + public void handleBlockPlace(GeyserboundBlockPlacePacket packet) { + LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket(); + placeBlockSoundPacket.setSound(SoundEvent.PLACE); + placeBlockSoundPacket.setPosition(packet.getPos().toFloat()); + placeBlockSoundPacket.setBabySound(false); + placeBlockSoundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(packet.getBlockId())); + placeBlockSoundPacket.setIdentifier(":"); + session.sendUpstreamPacket(placeBlockSoundPacket); + session.setLastBlockPlacePosition(null); + session.setLastBlockPlacedId(null); + } + + @Override + public void handlePickBlock(GeyserboundPickBlockPacket packet) { + if (this.pickBlockLookup != null) { + this.pickBlockLookup.complete(packet.getTag()); + } + } + + @Override + public void handlePistonEvent(GeyserboundPistonEventPacket packet) { + Direction orientation = BlockStateValues.getPistonOrientation(packet.getBlockId()); + Vector3i position = packet.getPos(); + boolean isExtend = packet.isExtend(); + + var stream = packet.getAttachedBlocks() + .object2IntEntrySet() + .stream() + .filter(entry -> BlockStateValues.canPistonMoveBlock(entry.getIntValue(), isExtend)); + Object2IntMap attachedBlocks = new Object2IntArrayMap<>(); + stream.forEach(entry -> attachedBlocks.put(entry.getKey(), entry.getIntValue())); + + session.executeInEventLoop(() -> { + PistonCache pistonCache = session.getPistonCache(); + PistonBlockEntity blockEntity = pistonCache.getPistons().computeIfAbsent(position, pos -> + new PistonBlockEntity(session, position, orientation, packet.isSticky(), !isExtend)); + blockEntity.setAction(isExtend ? PistonValueType.PUSHING : PistonValueType.PULLING, attachedBlocks); + }); + } + + @Override + public void handleHandshake(GeyserboundHandshakePacket packet) { + this.close(); + var handler = new GeyserboundHandshakePacketHandler(this.session); + session.setErosionHandler(handler); + handler.handleHandshake(packet); + } + + @Override + public boolean isActive() { + return true; + } + + @Override + public GeyserboundPacketHandlerImpl getAsActive() { + return this; + } + + @Override + public void onConnect() { + sendPacket(new BackendboundInitializePacket(session.getPlayerEntity().getUuid(), GameProtocol.getJavaProtocolVersion())); + } + + public void sendPacket(BackendboundPacket packet) { + this.packetSender.sendPacket(packet); + } + + public void close() { + this.packetSender.close(); + } + + public int getNextTransactionId() { + return nextTransactionId.getAndIncrement(); + } + + @Override + public ErosionPacketHandler setChannel(Channel channel) { + this.packetSender.setChannel(channel); + return this; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java b/core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java new file mode 100644 index 000000000..a236099df --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/erosion/UnixSocketClientListener.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org + * + * 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. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.erosion; + +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.epoll.EpollDomainSocketChannel; +import io.netty.channel.epoll.EpollEventLoopGroup; +import org.geysermc.erosion.netty.impl.AbstractUnixSocketListener; +import org.geysermc.erosion.packet.geyserbound.GeyserboundPacketHandler; + +import java.net.SocketAddress; + +public final class UnixSocketClientListener extends AbstractUnixSocketListener { + private EventLoopGroup eventLoopGroup; + + public void initializeEventLoopGroup() { + if (this.eventLoopGroup == null) { + this.eventLoopGroup = new EpollEventLoopGroup(); + } + } + + public void createClient(GeyserboundPacketHandler handler, SocketAddress address) { + initializeEventLoopGroup(); + (new Bootstrap() + .channel(EpollDomainSocketChannel.class) + .handler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) { + initPipeline(ch, handler); + } + }) + .group(this.eventLoopGroup.next()) + .connect(address)) + .syncUninterruptibly() + .channel(); + } + + @Override + public void close() { + if (this.eventLoopGroup != null) { + this.eventLoopGroup.shutdownGracefully(); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java index 9f8c603e1..1dbde84f4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -91,6 +91,10 @@ public abstract class Inventory { @Setter private boolean pending = false; + @Getter + @Setter + private boolean displayed = false; + protected Inventory(int id, int size, ContainerType containerType) { this("Inventory", id, size, containerType); } diff --git a/core/src/main/java/org/geysermc/geyser/item/Items.java b/core/src/main/java/org/geysermc/geyser/item/Items.java index 8c7a43223..ad13faf19 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -63,6 +63,7 @@ public final class Items { public static final Item BIRCH_PLANKS = register(new Item("birch_planks", builder())); public static final Item JUNGLE_PLANKS = register(new Item("jungle_planks", builder())); public static final Item ACACIA_PLANKS = register(new Item("acacia_planks", builder())); + public static final Item CHERRY_PLANKS = register(new Item("cherry_planks", builder())); public static final Item DARK_OAK_PLANKS = register(new Item("dark_oak_planks", builder())); public static final Item MANGROVE_PLANKS = register(new Item("mangrove_planks", builder())); public static final Item BAMBOO_PLANKS = register(new Item("bamboo_planks", builder())); @@ -74,10 +75,12 @@ public final class Items { public static final Item BIRCH_SAPLING = register(new Item("birch_sapling", builder())); public static final Item JUNGLE_SAPLING = register(new Item("jungle_sapling", builder())); public static final Item ACACIA_SAPLING = register(new Item("acacia_sapling", builder())); + public static final Item CHERRY_SAPLING = register(new Item("cherry_sapling", builder())); public static final Item DARK_OAK_SAPLING = register(new Item("dark_oak_sapling", builder())); public static final Item MANGROVE_PROPAGULE = register(new Item("mangrove_propagule", builder())); public static final Item BEDROCK = register(new Item("bedrock", builder())); public static final Item SAND = register(new Item("sand", builder())); + public static final Item SUSPICIOUS_SAND = register(new Item("suspicious_sand", builder())); public static final Item RED_SAND = register(new Item("red_sand", builder())); public static final Item GRAVEL = register(new Item("gravel", builder())); public static final Item COAL_ORE = register(new Item("coal_ore", builder())); @@ -146,6 +149,7 @@ public final class Items { public static final Item BIRCH_LOG = register(new Item("birch_log", builder())); public static final Item JUNGLE_LOG = register(new Item("jungle_log", builder())); public static final Item ACACIA_LOG = register(new Item("acacia_log", builder())); + public static final Item CHERRY_LOG = register(new Item("cherry_log", builder())); public static final Item DARK_OAK_LOG = register(new Item("dark_oak_log", builder())); public static final Item MANGROVE_LOG = register(new Item("mangrove_log", builder())); public static final Item MANGROVE_ROOTS = register(new Item("mangrove_roots", builder())); @@ -158,6 +162,7 @@ public final class Items { public static final Item STRIPPED_BIRCH_LOG = register(new Item("stripped_birch_log", builder())); public static final Item STRIPPED_JUNGLE_LOG = register(new Item("stripped_jungle_log", builder())); public static final Item STRIPPED_ACACIA_LOG = register(new Item("stripped_acacia_log", builder())); + public static final Item STRIPPED_CHERRY_LOG = register(new Item("stripped_cherry_log", builder())); public static final Item STRIPPED_DARK_OAK_LOG = register(new Item("stripped_dark_oak_log", builder())); public static final Item STRIPPED_MANGROVE_LOG = register(new Item("stripped_mangrove_log", builder())); public static final Item STRIPPED_CRIMSON_STEM = register(new Item("stripped_crimson_stem", builder())); @@ -167,6 +172,7 @@ public final class Items { public static final Item STRIPPED_BIRCH_WOOD = register(new Item("stripped_birch_wood", builder())); public static final Item STRIPPED_JUNGLE_WOOD = register(new Item("stripped_jungle_wood", builder())); public static final Item STRIPPED_ACACIA_WOOD = register(new Item("stripped_acacia_wood", builder())); + public static final Item STRIPPED_CHERRY_WOOD = register(new Item("stripped_cherry_wood", builder())); public static final Item STRIPPED_DARK_OAK_WOOD = register(new Item("stripped_dark_oak_wood", builder())); public static final Item STRIPPED_MANGROVE_WOOD = register(new Item("stripped_mangrove_wood", builder())); public static final Item STRIPPED_CRIMSON_HYPHAE = register(new Item("stripped_crimson_hyphae", builder())); @@ -177,6 +183,7 @@ public final class Items { public static final Item BIRCH_WOOD = register(new Item("birch_wood", builder())); public static final Item JUNGLE_WOOD = register(new Item("jungle_wood", builder())); public static final Item ACACIA_WOOD = register(new Item("acacia_wood", builder())); + public static final Item CHERRY_WOOD = register(new Item("cherry_wood", builder())); public static final Item DARK_OAK_WOOD = register(new Item("dark_oak_wood", builder())); public static final Item MANGROVE_WOOD = register(new Item("mangrove_wood", builder())); public static final Item CRIMSON_HYPHAE = register(new Item("crimson_hyphae", builder())); @@ -186,6 +193,7 @@ public final class Items { public static final Item BIRCH_LEAVES = register(new Item("birch_leaves", builder())); public static final Item JUNGLE_LEAVES = register(new Item("jungle_leaves", builder())); public static final Item ACACIA_LEAVES = register(new Item("acacia_leaves", builder())); + public static final Item CHERRY_LEAVES = register(new Item("cherry_leaves", builder())); public static final Item DARK_OAK_LEAVES = register(new Item("dark_oak_leaves", builder())); public static final Item MANGROVE_LEAVES = register(new Item("mangrove_leaves", builder())); public static final Item AZALEA_LEAVES = register(new Item("azalea_leaves", builder())); @@ -235,6 +243,7 @@ public final class Items { public static final Item CORNFLOWER = register(new Item("cornflower", builder())); public static final Item LILY_OF_THE_VALLEY = register(new Item("lily_of_the_valley", builder())); public static final Item WITHER_ROSE = register(new Item("wither_rose", builder())); + public static final Item TORCHFLOWER = register(new Item("torchflower", builder())); public static final Item SPORE_BLOSSOM = register(new Item("spore_blossom", builder())); public static final Item BROWN_MUSHROOM = register(new Item("brown_mushroom", builder())); public static final Item RED_MUSHROOM = register(new Item("red_mushroom", builder())); @@ -248,6 +257,7 @@ public final class Items { public static final Item SUGAR_CANE = register(new Item("sugar_cane", builder())); public static final Item KELP = register(new Item("kelp", builder())); public static final Item MOSS_CARPET = register(new Item("moss_carpet", builder())); + public static final Item PINK_PETALS = register(new Item("pink_petals", builder())); public static final Item MOSS_BLOCK = register(new Item("moss_block", builder())); public static final Item HANGING_ROOTS = register(new Item("hanging_roots", builder())); public static final Item BIG_DRIPLEAF = register(new Item("big_dripleaf", builder())); @@ -258,6 +268,7 @@ public final class Items { public static final Item BIRCH_SLAB = register(new Item("birch_slab", builder())); public static final Item JUNGLE_SLAB = register(new Item("jungle_slab", builder())); public static final Item ACACIA_SLAB = register(new Item("acacia_slab", builder())); + public static final Item CHERRY_SLAB = register(new Item("cherry_slab", builder())); public static final Item DARK_OAK_SLAB = register(new Item("dark_oak_slab", builder())); public static final Item MANGROVE_SLAB = register(new Item("mangrove_slab", builder())); public static final Item BAMBOO_SLAB = register(new Item("bamboo_slab", builder())); @@ -288,6 +299,7 @@ public final class Items { public static final Item BRICKS = register(new Item("bricks", builder())); public static final Item BOOKSHELF = register(new Item("bookshelf", builder())); public static final Item CHISELED_BOOKSHELF = register(new Item("chiseled_bookshelf", builder())); + public static final Item DECORATED_POT = register(new Item("decorated_pot", builder().stackSize(1))); public static final Item MOSSY_COBBLESTONE = register(new Item("mossy_cobblestone", builder())); public static final Item OBSIDIAN = register(new Item("obsidian", builder())); public static final Item TORCH = register(new Item("torch", builder())); @@ -315,6 +327,7 @@ public final class Items { public static final Item BIRCH_FENCE = register(new Item("birch_fence", builder())); public static final Item JUNGLE_FENCE = register(new Item("jungle_fence", builder())); public static final Item ACACIA_FENCE = register(new Item("acacia_fence", builder())); + public static final Item CHERRY_FENCE = register(new Item("cherry_fence", builder())); public static final Item DARK_OAK_FENCE = register(new Item("dark_oak_fence", builder())); public static final Item MANGROVE_FENCE = register(new Item("mangrove_fence", builder())); public static final Item BAMBOO_FENCE = register(new Item("bamboo_fence", builder())); @@ -386,6 +399,7 @@ public final class Items { public static final Item BIRCH_STAIRS = register(new Item("birch_stairs", builder())); public static final Item JUNGLE_STAIRS = register(new Item("jungle_stairs", builder())); public static final Item ACACIA_STAIRS = register(new Item("acacia_stairs", builder())); + public static final Item CHERRY_STAIRS = register(new Item("cherry_stairs", builder())); public static final Item DARK_OAK_STAIRS = register(new Item("dark_oak_stairs", builder())); public static final Item MANGROVE_STAIRS = register(new Item("mangrove_stairs", builder())); public static final Item BAMBOO_STAIRS = register(new Item("bamboo_stairs", builder())); @@ -684,6 +698,7 @@ public final class Items { public static final Item BIRCH_BUTTON = register(new Item("birch_button", builder())); public static final Item JUNGLE_BUTTON = register(new Item("jungle_button", builder())); public static final Item ACACIA_BUTTON = register(new Item("acacia_button", builder())); + public static final Item CHERRY_BUTTON = register(new Item("cherry_button", builder())); public static final Item DARK_OAK_BUTTON = register(new Item("dark_oak_button", builder())); public static final Item MANGROVE_BUTTON = register(new Item("mangrove_button", builder())); public static final Item BAMBOO_BUTTON = register(new Item("bamboo_button", builder())); @@ -698,6 +713,7 @@ public final class Items { public static final Item BIRCH_PRESSURE_PLATE = register(new Item("birch_pressure_plate", builder())); public static final Item JUNGLE_PRESSURE_PLATE = register(new Item("jungle_pressure_plate", builder())); public static final Item ACACIA_PRESSURE_PLATE = register(new Item("acacia_pressure_plate", builder())); + public static final Item CHERRY_PRESSURE_PLATE = register(new Item("cherry_pressure_plate", builder())); public static final Item DARK_OAK_PRESSURE_PLATE = register(new Item("dark_oak_pressure_plate", builder())); public static final Item MANGROVE_PRESSURE_PLATE = register(new Item("mangrove_pressure_plate", builder())); public static final Item BAMBOO_PRESSURE_PLATE = register(new Item("bamboo_pressure_plate", builder())); @@ -709,6 +725,7 @@ public final class Items { public static final Item BIRCH_DOOR = register(new Item("birch_door", builder())); public static final Item JUNGLE_DOOR = register(new Item("jungle_door", builder())); public static final Item ACACIA_DOOR = register(new Item("acacia_door", builder())); + public static final Item CHERRY_DOOR = register(new Item("cherry_door", builder())); public static final Item DARK_OAK_DOOR = register(new Item("dark_oak_door", builder())); public static final Item MANGROVE_DOOR = register(new Item("mangrove_door", builder())); public static final Item BAMBOO_DOOR = register(new Item("bamboo_door", builder())); @@ -720,6 +737,7 @@ public final class Items { public static final Item BIRCH_TRAPDOOR = register(new Item("birch_trapdoor", builder())); public static final Item JUNGLE_TRAPDOOR = register(new Item("jungle_trapdoor", builder())); public static final Item ACACIA_TRAPDOOR = register(new Item("acacia_trapdoor", builder())); + public static final Item CHERRY_TRAPDOOR = register(new Item("cherry_trapdoor", builder())); public static final Item DARK_OAK_TRAPDOOR = register(new Item("dark_oak_trapdoor", builder())); public static final Item MANGROVE_TRAPDOOR = register(new Item("mangrove_trapdoor", builder())); public static final Item BAMBOO_TRAPDOOR = register(new Item("bamboo_trapdoor", builder())); @@ -730,6 +748,7 @@ public final class Items { public static final Item BIRCH_FENCE_GATE = register(new Item("birch_fence_gate", builder())); public static final Item JUNGLE_FENCE_GATE = register(new Item("jungle_fence_gate", builder())); public static final Item ACACIA_FENCE_GATE = register(new Item("acacia_fence_gate", builder())); + public static final Item CHERRY_FENCE_GATE = register(new Item("cherry_fence_gate", builder())); public static final Item DARK_OAK_FENCE_GATE = register(new Item("dark_oak_fence_gate", builder())); public static final Item MANGROVE_FENCE_GATE = register(new Item("mangrove_fence_gate", builder())); public static final Item BAMBOO_FENCE_GATE = register(new Item("bamboo_fence_gate", builder())); @@ -758,6 +777,8 @@ public final class Items { public static final Item JUNGLE_CHEST_BOAT = register(new Item("jungle_chest_boat", builder().stackSize(1))); public static final Item ACACIA_BOAT = register(new Item("acacia_boat", builder().stackSize(1))); public static final Item ACACIA_CHEST_BOAT = register(new Item("acacia_chest_boat", builder().stackSize(1))); + public static final Item CHERRY_BOAT = register(new Item("cherry_boat", builder().stackSize(1))); + public static final Item CHERRY_CHEST_BOAT = register(new Item("cherry_chest_boat", builder().stackSize(1))); public static final Item DARK_OAK_BOAT = register(new Item("dark_oak_boat", builder().stackSize(1))); public static final Item DARK_OAK_CHEST_BOAT = register(new Item("dark_oak_chest_boat", builder().stackSize(1))); public static final Item MANGROVE_BOAT = register(new Item("mangrove_boat", builder().stackSize(1))); @@ -861,6 +882,7 @@ public final class Items { public static final Item BIRCH_SIGN = register(new Item("birch_sign", builder().stackSize(16))); public static final Item JUNGLE_SIGN = register(new Item("jungle_sign", builder().stackSize(16))); public static final Item ACACIA_SIGN = register(new Item("acacia_sign", builder().stackSize(16))); + public static final Item CHERRY_SIGN = register(new Item("cherry_sign", builder().stackSize(16))); public static final Item DARK_OAK_SIGN = register(new Item("dark_oak_sign", builder().stackSize(16))); public static final Item MANGROVE_SIGN = register(new Item("mangrove_sign", builder().stackSize(16))); public static final Item BAMBOO_SIGN = register(new Item("bamboo_sign", builder().stackSize(16))); @@ -871,6 +893,7 @@ public final class Items { public static final Item BIRCH_HANGING_SIGN = register(new Item("birch_hanging_sign", builder().stackSize(16))); public static final Item JUNGLE_HANGING_SIGN = register(new Item("jungle_hanging_sign", builder().stackSize(16))); public static final Item ACACIA_HANGING_SIGN = register(new Item("acacia_hanging_sign", builder().stackSize(16))); + public static final Item CHERRY_HANGING_SIGN = register(new Item("cherry_hanging_sign", builder().stackSize(16))); public static final Item DARK_OAK_HANGING_SIGN = register(new Item("dark_oak_hanging_sign", builder().stackSize(16))); public static final Item MANGROVE_HANGING_SIGN = register(new Item("mangrove_hanging_sign", builder().stackSize(16))); public static final Item BAMBOO_HANGING_SIGN = register(new Item("bamboo_hanging_sign", builder().stackSize(16))); @@ -1028,6 +1051,7 @@ public final class Items { public static final SpawnEggItem SKELETON_SPAWN_EGG = register(new SpawnEggItem("skeleton_spawn_egg", builder())); public static final SpawnEggItem SKELETON_HORSE_SPAWN_EGG = register(new SpawnEggItem("skeleton_horse_spawn_egg", builder())); public static final SpawnEggItem SLIME_SPAWN_EGG = register(new SpawnEggItem("slime_spawn_egg", builder())); + public static final SpawnEggItem SNIFFER_SPAWN_EGG = register(new SpawnEggItem("sniffer_spawn_egg", builder())); public static final SpawnEggItem SNOW_GOLEM_SPAWN_EGG = register(new SpawnEggItem("snow_golem_spawn_egg", builder())); public static final SpawnEggItem SPIDER_SPAWN_EGG = register(new SpawnEggItem("spider_spawn_egg", builder())); public static final SpawnEggItem SQUID_SPAWN_EGG = register(new SpawnEggItem("squid_spawn_egg", builder())); @@ -1113,6 +1137,7 @@ public final class Items { public static final Item END_CRYSTAL = register(new Item("end_crystal", builder())); public static final Item CHORUS_FRUIT = register(new Item("chorus_fruit", builder())); public static final Item POPPED_CHORUS_FRUIT = register(new Item("popped_chorus_fruit", builder())); + public static final Item TORCHFLOWER_SEEDS = register(new Item("torchflower_seeds", builder())); public static final Item BEETROOT = register(new Item("beetroot", builder())); public static final Item BEETROOT_SEEDS = register(new Item("beetroot_seeds", builder())); public static final Item BEETROOT_SOUP = register(new Item("beetroot_soup", builder().stackSize(1))); @@ -1221,6 +1246,23 @@ public final class Items { public static final Item PEARLESCENT_FROGLIGHT = register(new Item("pearlescent_froglight", builder())); public static final Item FROGSPAWN = register(new Item("frogspawn", builder())); public static final Item ECHO_SHARD = register(new Item("echo_shard", builder())); + public static final Item BRUSH = register(new Item("brush", builder().stackSize(1).maxDamage(64))); + public static final Item NETHERITE_UPGRADE_SMITHING_TEMPLATE = register(new Item("netherite_upgrade_smithing_template", builder())); + public static final Item SENTRY_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("sentry_armor_trim_smithing_template", builder())); + public static final Item DUNE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("dune_armor_trim_smithing_template", builder())); + public static final Item COAST_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("coast_armor_trim_smithing_template", builder())); + public static final Item WILD_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("wild_armor_trim_smithing_template", builder())); + public static final Item WARD_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("ward_armor_trim_smithing_template", builder())); + public static final Item EYE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("eye_armor_trim_smithing_template", builder())); + public static final Item VEX_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("vex_armor_trim_smithing_template", builder())); + public static final Item TIDE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("tide_armor_trim_smithing_template", builder())); + public static final Item SNOUT_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("snout_armor_trim_smithing_template", builder())); + public static final Item RIB_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("rib_armor_trim_smithing_template", builder())); + public static final Item SPIRE_ARMOR_TRIM_SMITHING_TEMPLATE = register(new Item("spire_armor_trim_smithing_template", builder())); + public static final Item POTTERY_SHARD_ARCHER = register(new Item("pottery_shard_archer", builder())); + public static final Item POTTERY_SHARD_PRIZE = register(new Item("pottery_shard_prize", builder())); + public static final Item POTTERY_SHARD_ARMS_UP = register(new Item("pottery_shard_arms_up", builder())); + public static final Item POTTERY_SHARD_SKULL = register(new Item("pottery_shard_skull", builder())); private static T register(T item) { return register(item, Registries.JAVA_ITEMS.get().size()); diff --git a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java index 674e8c3f4..ee144acc6 100644 --- a/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java +++ b/core/src/main/java/org/geysermc/geyser/item/components/ToolTier.java @@ -43,7 +43,7 @@ public enum ToolTier { DIAMOND(8, () -> Collections.singleton(Items.DIAMOND)), NETHERITE(9, () -> Collections.singleton(Items.NETHERITE_INGOT)); - public static final ToolTier[] VALUES = values(); + private static final ToolTier[] VALUES = values(); private final int speed; private final Supplier> repairIngredients; diff --git a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java index b2251ff0f..338473fc5 100644 --- a/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java +++ b/core/src/main/java/org/geysermc/geyser/item/type/PotionItem.java @@ -28,11 +28,13 @@ package org.geysermc.geyser.item.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; +import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.translator.inventory.item.CustomItemTranslator; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; public class PotionItem extends Item { @@ -45,15 +47,23 @@ public class PotionItem extends Item { if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings); Tag potionTag = itemStack.getNbt().get("Potion"); if (potionTag instanceof StringTag) { - Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); - if (potion != null) { + ItemDefinition customItemDefinition = CustomItemTranslator.getCustomItem(itemStack.getNbt(), mapping); + if (customItemDefinition == null) { + Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); + if (potion != null) { + return ItemData.builder() + .definition(mapping.getBedrockDefinition()) + .damage(potion.getBedrockId()) + .count(itemStack.getAmount()) + .tag(ItemTranslator.translateNbtToBedrock(itemStack.getNbt())); + } + GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); + } else { return ItemData.builder() - .definition(mapping.getBedrockDefinition()) - .damage(potion.getBedrockId()) + .definition(customItemDefinition) .count(itemStack.getAmount()) .tag(ItemTranslator.translateNbtToBedrock(itemStack.getNbt())); } - GeyserImpl.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); } return super.translateToBedrock(itemStack, mapping, mappings); } diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java index 210269876..8d4b3f2e6 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -25,25 +25,63 @@ package org.geysermc.geyser.level; +import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; -import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.erosion.packet.backendbound.*; +import org.geysermc.erosion.util.BlockPositionIterator; +import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.session.cache.ChunkCache; -import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; +import org.geysermc.geyser.util.BlockEntityUtils; +import org.jetbrains.annotations.Nullable; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.concurrent.CompletableFuture; public class GeyserWorldManager extends WorldManager { private final Object2ObjectMap gameruleCache = new Object2ObjectOpenHashMap<>(); @Override public int getBlockAt(GeyserSession session, int x, int y, int z) { - ChunkCache chunkCache = session.getChunkCache(); - if (chunkCache != null) { // Chunk cache can be null if the session is closed asynchronously - return chunkCache.getBlockAt(x, y, z); + var erosionHandler = session.getErosionHandler().getAsActive(); + if (erosionHandler == null) { + return session.getChunkCache().getBlockAt(x, y, z); } - return BlockStateValues.JAVA_AIR_ID; + CompletableFuture future = new CompletableFuture<>(); // Boxes + erosionHandler.setPendingLookup(future); + erosionHandler.sendPacket(new BackendboundBlockRequestPacket(0, Vector3i.from(x, y, z))); + return future.join(); + } + + @Override + public CompletableFuture getBlockAtAsync(GeyserSession session, int x, int y, int z) { + var erosionHandler = session.getErosionHandler().getAsActive(); + if (erosionHandler == null) { + return super.getBlockAtAsync(session, x, y, z); + } + CompletableFuture future = new CompletableFuture<>(); // Boxes + int transactionId = erosionHandler.getNextTransactionId(); + erosionHandler.getAsyncPendingLookups().put(transactionId, future); + erosionHandler.sendPacket(new BackendboundBlockRequestPacket(transactionId, Vector3i.from(x, y, z))); + return future; + } + + @Override + public int[] getBlocksAt(GeyserSession session, BlockPositionIterator iter) { + var erosionHandler = session.getErosionHandler().getAsActive(); + if (erosionHandler == null) { + return super.getBlocksAt(session, iter); + } + CompletableFuture future = new CompletableFuture<>(); + erosionHandler.setPendingBatchLookup(future); + erosionHandler.sendPacket(new BackendboundBatchBlockRequestPacket(iter)); + return future.join(); } @Override @@ -53,10 +91,31 @@ public class GeyserWorldManager extends WorldManager { } @Override - public NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad) { + public void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos) { + var erosionHandler = session.getErosionHandler().getAsActive(); + if (erosionHandler == null) { + // No-op - don't send any additional information other than what the chunk has already sent + return; + } + List vectors = new ObjectArrayList<>(blockEntityInfos.size()); + for (int i = 0; i < blockEntityInfos.size(); i++) { + BlockEntityInfo info = blockEntityInfos.get(i); + vectors.add(Vector3i.from(info.getX(), info.getY(), info.getZ())); + } + erosionHandler.sendPacket(new BackendboundBatchBlockEntityPacket(x, z, vectors)); + } + + @Override + public void sendLecternData(GeyserSession session, int x, int y, int z) { + var erosionHandler = session.getErosionHandler().getAsActive(); + if (erosionHandler != null) { + erosionHandler.sendPacket(new BackendboundBlockEntityPacket(Vector3i.from(x, y, z))); + return; + } + // Without direct server access, we can't get lectern information on-the-fly. // I should have set this up so it's only called when there is a book in the block state. - Camotoy - NbtMapBuilder lecternTag = LecternInventoryTranslator.getBaseLecternTag(x, y, z, 1); + NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(x, y, z, 1); lecternTag.putCompound("book", NbtMap.builder() .putByte("Count", (byte) 1) .putShort("Damage", (short) 0) @@ -67,12 +126,12 @@ public class GeyserWorldManager extends WorldManager { .build()) .build()); lecternTag.putInt("page", -1); // I'm surprisingly glad this exists - it forces Bedrock to stop reading immediately. Usually. - return lecternTag.build(); + BlockEntityUtils.updateBlockEntity(session, lecternTag.build(), Vector3i.from(x, y, z)); } @Override - public boolean shouldExpectLecternHandled() { - return false; + public boolean shouldExpectLecternHandled(GeyserSession session) { + return session.getErosionHandler().isActive(); } @Override @@ -105,4 +164,17 @@ public class GeyserWorldManager extends WorldManager { public boolean hasPermission(GeyserSession session, String permission) { return false; } + + @Nonnull + @Override + public CompletableFuture<@Nullable CompoundTag> getPickItemNbt(GeyserSession session, int x, int y, int z, boolean addNbtData) { + var erosionHandler = session.getErosionHandler().getAsActive(); + if (erosionHandler == null) { + return super.getPickItemNbt(session, x, y, z, addNbtData); + } + CompletableFuture future = new CompletableFuture<>(); + erosionHandler.setPickBlockLookup(future); + erosionHandler.sendPacket(new BackendboundPickBlockPacket(Vector3i.from(x, y, z))); + return future; + } } diff --git a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java index c408d1018..006caff55 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -26,14 +26,16 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.session.GeyserSession; import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; +import java.util.List; import java.util.Locale; import java.util.concurrent.CompletableFuture; @@ -68,6 +70,23 @@ public abstract class WorldManager { */ public abstract int getBlockAt(GeyserSession session, int x, int y, int z); + public final CompletableFuture getBlockAtAsync(GeyserSession session, Vector3i vector) { + return this.getBlockAtAsync(session, vector.getX(), vector.getY(), vector.getZ()); + } + + public CompletableFuture getBlockAtAsync(GeyserSession session, int x, int y, int z) { + return CompletableFuture.completedFuture(this.getBlockAt(session, x, y, z)); + } + + public int[] getBlocksAt(GeyserSession session, BlockPositionIterator iter) { + int[] blocks = new int[iter.getMaxIterations()]; + for (; iter.hasNext(); iter.next()) { + int networkId = this.getBlockAt(session, iter.getX(), iter.getY(), iter.getZ()); + blocks[iter.getIteration()] = networkId; + } + return blocks; + } + /** * Checks whether or not this world manager requires a separate chunk cache/has access to more block data than the chunk cache. *

@@ -89,20 +108,28 @@ public abstract class WorldManager { * We solve this problem by querying all loaded lecterns, where possible, and sending their information in a block entity * tag. * + * Note that the lectern data may be sent asynchronously. + * * @param session the session of the player * @param x the x coordinate of the lectern * @param y the y coordinate of the lectern * @param z the z coordinate of the lectern - * @param isChunkLoad if this is called during a chunk load or not. Changes behavior in certain instances. - * @return the Bedrock lectern block entity tag. This may not be the exact block entity tag - for example, Spigot's - * block handled must be done on the server thread, so we send the tag manually there. */ - public abstract NbtMap getLecternDataAt(GeyserSession session, int x, int y, int z, boolean isChunkLoad); + public abstract void sendLecternData(GeyserSession session, int x, int y, int z); + + /** + * {@link #sendLecternData(GeyserSession, int, int, int)} but batched for chunks. + * + * @param x chunk x + * @param z chunk z + * @param blockEntityInfos a list of coordinates (chunk local) to grab lecterns from. + */ + public abstract void sendLecternData(GeyserSession session, int x, int z, List blockEntityInfos); /** * @return whether we should expect lectern data to update, or if we have to fall back on a workaround. */ - public abstract boolean shouldExpectLecternHandled(); + public abstract boolean shouldExpectLecternHandled(GeyserSession session); /** * Updates a gamerule value on the Java server diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java deleted file mode 100644 index 7b94f751b..000000000 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org - * - * 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. - * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser - */ - -package org.geysermc.geyser.level.block; - -import org.cloudburstmc.protocol.common.util.Preconditions; - -public class BlockPositionIterator { - private final int minX; - private final int minY; - private final int minZ; - - private final int sizeX; - private final int sizeZ; - - private int i = 0; - private final int maxI; - - public BlockPositionIterator(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) { - Preconditions.checkArgument(maxX >= minX, "maxX is not greater than or equal to minX"); - Preconditions.checkArgument(maxY >= minY, "maxY is not greater than or equal to minY"); - Preconditions.checkArgument(maxZ >= minZ, "maxZ is not greater than or equal to minZ"); - - this.minX = minX; - this.minY = minY; - this.minZ = minZ; - - this.sizeX = maxX - minX + 1; - int sizeY = maxY - minY + 1; - this.sizeZ = maxZ - minZ + 1; - this.maxI = sizeX * sizeY * sizeZ; - } - - public boolean hasNext() { - return i < maxI; - } - - public void next() { - // Iterate in zxy order - i++; - } - - public void reset() { - i = 0; - } - - public int getX() { - return ((i / sizeZ) % sizeX) + minX; - } - - public int getY() { - return (i / sizeZ / sizeX) + minY; - } - - public int getZ() { - return (i % sizeZ) + minZ; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java index 58cbce77f..c6fc60303 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockStateValues.java @@ -68,7 +68,6 @@ public final class BlockStateValues { public static final int JAVA_AIR_ID = 0; - public static int JAVA_BELL_ID; public static int JAVA_COBWEB_ID; public static int JAVA_FURNACE_ID; public static int JAVA_FURNACE_LIT_ID; diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java index 6410bb6c9..b983da8b4 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/CollisionManager.java @@ -33,10 +33,10 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import lombok.Getter; import lombok.Setter; +import org.geysermc.erosion.util.BlockPositionIterator; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.level.block.BlockPositionIterator; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.PistonCache; @@ -215,7 +215,7 @@ public class CollisionManager { int minCollisionZ = (int) Math.floor(position.getZ() - ((box.getSizeZ() / 2) + COLLISION_TOLERANCE + pistonExpand)); int maxCollisionZ = (int) Math.floor(position.getZ() + (box.getSizeZ() / 2) + COLLISION_TOLERANCE + pistonExpand); - return new BlockPositionIterator(minCollisionX, minCollisionY, minCollisionZ, maxCollisionX, maxCollisionY, maxCollisionZ); + return BlockPositionIterator.fromMinMax(minCollisionX, minCollisionY, minCollisionZ, maxCollisionX, maxCollisionY, maxCollisionZ); } public BlockPositionIterator playerCollidableBlocksIterator() { @@ -235,8 +235,9 @@ public class CollisionManager { // Used when correction code needs to be run before the main correction BlockPositionIterator iter = session.getCollisionManager().playerCollidableBlocksIterator(); - for (; iter.hasNext(); iter.next()) { - BlockCollision blockCollision = BlockUtils.getCollisionAt(session, iter.getX(), iter.getY(), iter.getZ()); + int[] blocks = session.getGeyser().getWorldManager().getBlocksAt(session, iter); + for (iter.reset(); iter.hasNext(); iter.next()) { + BlockCollision blockCollision = BlockUtils.getCollision(blocks[iter.getIteration()]); if (blockCollision != null) { blockCollision.beforeCorrectPosition(iter.getX(), iter.getY(), iter.getZ(), playerBoundingBox); } @@ -244,7 +245,7 @@ public class CollisionManager { // Main correction code for (iter.reset(); iter.hasNext(); iter.next()) { - BlockCollision blockCollision = BlockUtils.getCollisionAt(session, iter.getX(), iter.getY(), iter.getZ()); + BlockCollision blockCollision = BlockUtils.getCollision(blocks[iter.getIteration()]); if (blockCollision != null) { if (!blockCollision.correctPosition(session, iter.getX(), iter.getY(), iter.getZ(), playerBoundingBox)) { return false; diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java index a05a2f452..fa5201db9 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/Direction.java @@ -25,19 +25,18 @@ package org.geysermc.geyser.level.physics; -import com.github.steveice10.mc.protocol.data.game.level.block.value.PistonValue; import org.cloudburstmc.math.vector.Vector3i; import lombok.Getter; import javax.annotation.Nonnull; public enum Direction { - DOWN(1, Vector3i.from(0, -1, 0), Axis.Y, PistonValue.DOWN), - UP(0, Vector3i.UNIT_Y, Axis.Y, PistonValue.UP), - NORTH(3, Vector3i.from(0, 0, -1), Axis.Z, PistonValue.NORTH), - SOUTH(2, Vector3i.UNIT_Z, Axis.Z, PistonValue.SOUTH), - WEST(5, Vector3i.from(-1, 0, 0), Axis.X, PistonValue.WEST), - EAST(4, Vector3i.UNIT_X, Axis.X, PistonValue.EAST); + DOWN(1, Vector3i.from(0, -1, 0), Axis.Y, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.DOWN), + UP(0, Vector3i.UNIT_Y, Axis.Y, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.UP), + NORTH(3, Vector3i.from(0, 0, -1), Axis.Z, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.NORTH), + SOUTH(2, Vector3i.UNIT_Z, Axis.Z, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.SOUTH), + WEST(5, Vector3i.from(-1, 0, 0), Axis.X, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.WEST), + EAST(4, Vector3i.UNIT_X, Axis.X, com.github.steveice10.mc.protocol.data.game.entity.object.Direction.EAST); public static final Direction[] VALUES = values(); @@ -46,10 +45,9 @@ public enum Direction { private final Vector3i unitVector; @Getter private final Axis axis; - @Getter - private final PistonValue pistonValue; + private final com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue; - Direction(int reversedId, Vector3i unitVector, Axis axis, PistonValue pistonValue) { + Direction(int reversedId, Vector3i unitVector, Axis axis, com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue) { this.reversedId = reversedId; this.unitVector = unitVector; this.axis = axis; @@ -69,7 +67,7 @@ public enum Direction { } @Nonnull - public static Direction fromPistonValue(PistonValue pistonValue) { + public static Direction fromPistonValue(com.github.steveice10.mc.protocol.data.game.entity.object.Direction pistonValue) { for (Direction direction : VALUES) { if (direction.pistonValue == pistonValue) { return direction; diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java b/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java index bf943134b..a6b25d01e 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/PistonBehavior.java @@ -33,7 +33,7 @@ public enum PistonBehavior { DESTROY, PUSH_ONLY; - public static final PistonBehavior[] VALUES = values(); + private static final PistonBehavior[] VALUES = values(); public static PistonBehavior getByName(String name) { String upperCase = name.toUpperCase(Locale.ROOT); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 87890d3e8..870328f27 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -28,12 +28,12 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; -import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544; -import org.cloudburstmc.protocol.bedrock.codec.v545.Bedrock_v545; import org.cloudburstmc.protocol.bedrock.codec.v554.Bedrock_v554; import org.cloudburstmc.protocol.bedrock.codec.v557.Bedrock_v557; import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560; import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568; +import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; @@ -49,7 +49,9 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v560.CODEC; + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = Bedrock_v575.CODEC.toBuilder() + .minecraftVersion("1.19.73") + .build(); /** * A list of all supported Bedrock versions that can join Geyser */ @@ -62,20 +64,20 @@ public final class GameProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v544.CODEC); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v545.CODEC.toBuilder() - .minecraftVersion("1.19.21/1.19.22") - .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v554.CODEC.toBuilder() .minecraftVersion("1.19.30/1.19.31") .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v557.CODEC.toBuilder() .minecraftVersion("1.19.40/1.19.41") .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v560.CODEC.toBuilder() .minecraftVersion("1.19.50/1.19.51") .build()); SUPPORTED_BEDROCK_CODECS.add(Bedrock_v567.CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v568.CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.70/1.19.71/1.19.73") + .build()); } /** @@ -94,10 +96,6 @@ public final class GameProtocol { /* Bedrock convenience methods to gatekeep features and easily remove the check on version removal */ - public static boolean supports1_19_30(GeyserSession session) { - return session.getUpstream().getProtocolVersion() >= Bedrock_v554.CODEC.getProtocolVersion(); - } - public static boolean supports1_19_50(GeyserSession session) { return session.getUpstream().getProtocolVersion() >= Bedrock_v560.CODEC.getProtocolVersion(); } diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 0a81f430d..f373cd25d 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -28,6 +28,8 @@ package org.geysermc.geyser.network; import io.netty.buffer.Unpooled; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; +import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v568.Bedrock_v568; import org.cloudburstmc.protocol.bedrock.data.ExperimentData; import org.cloudburstmc.protocol.bedrock.data.PacketCompressionAlgorithm; import org.cloudburstmc.protocol.bedrock.data.ResourcePackType; @@ -46,6 +48,7 @@ import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket; import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket; import org.cloudburstmc.protocol.common.PacketSignal; +import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.configuration.GeyserConfiguration; @@ -58,11 +61,13 @@ import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.util.LoginEncryptionUtils; import org.geysermc.geyser.util.MathUtils; +import org.geysermc.geyser.util.VersionCheckUtils; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayDeque; import java.util.Deque; +import java.util.OptionalInt; public class UpstreamPacketHandler extends LoggingPacketHandler { @@ -90,7 +95,14 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { String supportedVersions = GameProtocol.getAllSupportedBedrockVersions(); if (protocolVersion > GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { // Too early to determine session locale - session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions)); + String disconnectMessage = GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions); + // If the latest release matches this version, then let the user know. + OptionalInt latestRelease = VersionCheckUtils.getLatestBedrockRelease(); + if (latestRelease.isPresent() && latestRelease.getAsInt() == protocolVersion) { + // Random note: don't make the disconnect message too long or Bedrock will cut it off on smaller screens + disconnectMessage += "\n" + GeyserLocale.getLocaleStringLog("geyser.version.new.on_disconnect", Constants.GEYSER_DOWNLOAD_LOCATION); + } + session.disconnect(disconnectMessage); return false; } else if (protocolVersion < GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); @@ -161,6 +173,11 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return PacketSignal.HANDLED; } + // Hack for... whatever this is + if (loginPacket.getProtocolVersion() == Bedrock_v567.CODEC.getProtocolVersion() && !session.getClientData().getGameVersion().equals("1.19.60")) { + session.getUpstream().getSession().setCodec(Bedrock_v568.CODEC); + } + PlayStatusPacket playStatus = new PlayStatusPacket(); playStatus.setStatus(PlayStatusPacket.Status.LOGIN_SUCCESS); session.sendUpstreamPacket(playStatus); diff --git a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java index 6df1a0c0e..07d56194a 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java +++ b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java @@ -102,13 +102,17 @@ public class ResourcePack { pack.sha256 = FileUtils.calculateSHA256(file); - Stream stream = null; - try { - ZipFile zip = new ZipFile(file); - - stream = zip.stream(); + try (ZipFile zip = new ZipFile(file); + Stream stream = zip.stream()) { stream.forEach((x) -> { - if (x.getName().contains("manifest.json")) { + String name = x.getName(); + if (name.length() >= 80) { + GeyserImpl.getInstance().getLogger().warning("The resource pack " + file.getName() + + " has a file in it that meets or exceeds 80 characters in its path (" + name + + ", " + name.length() + " characters long). This will cause problems on some Bedrock platforms." + + " Please rename it to be shorter, or reduce the amount of folders needed to get to the file."); + } + if (name.contains("manifest.json")) { try { ResourcePackManifest manifest = FileUtils.loadJson(zip.getInputStream(x), ResourcePackManifest.class); // Sometimes a pack_manifest file is present and not in a valid format, @@ -133,10 +137,6 @@ public class ResourcePack { } catch (Exception e) { GeyserImpl.getInstance().getLogger().error(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", file.getName())); e.printStackTrace(); - } finally { - if (stream != null) { - stream.close(); - } } } } diff --git a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java index af030eb00..e3c72c174 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java @@ -79,7 +79,8 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn try (Socket socket = new Socket()) { String address = geyser.getConfig().getRemote().address(); int port = geyser.getConfig().getRemote().port(); - socket.connect(new InetSocketAddress(address, port), 5000); + InetSocketAddress endpoint = new InetSocketAddress(address, port); + socket.connect(endpoint, 5000); ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); try (DataOutputStream handshake = new DataOutputStream(byteArrayStream)) { @@ -103,7 +104,8 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn HAProxyProxiedProtocol.TCP4.byteValue() : HAProxyProxiedProtocol.TCP6.byteValue()); byte[] srcAddrBytes = NetUtil.createByteArrayFromIpAddressString( ((InetSocketAddress) socket.getLocalSocketAddress()).getAddress().getHostAddress()); - byte[] dstAddrBytes = NetUtil.createByteArrayFromIpAddressString(address); + byte[] dstAddrBytes = NetUtil.createByteArrayFromIpAddressString( + endpoint.getAddress().getHostAddress()); dataOutputStream.writeShort(srcAddrBytes.length + dstAddrBytes.length + 4); dataOutputStream.write(srcAddrBytes); dataOutputStream.write(dstAddrBytes); diff --git a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java index c1268f504..fc4e3d022 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java @@ -58,7 +58,7 @@ public abstract class AbstractMappedRegistry> extends } /** - * Returns & maps the value by the given key if present. + * Returns and maps the value by the given key if present. * * @param key the key * @param mapper the mapper diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 144d58232..0bf6ae078 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -140,7 +140,7 @@ public final class Registries { /** * A registry holding all the potion mixes. */ - public static final SimpleRegistry> POTION_MIXES; + public static final VersionedRegistry> POTION_MIXES; /** * A registry holding all the @@ -183,7 +183,7 @@ public final class Registries { RecipeRegistryPopulator.populate(); // Create registries that require other registries to load first - POTION_MIXES = SimpleRegistry.create(PotionMixRegistryLoader::new); + POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); ENCHANTMENTS = SimpleMappedRegistry.create("mappings/enchantments.json", EnchantmentRegistryLoader::new); // Remove unneeded client generation data from NbtMapBuilder diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java index 16fc1f817..88d2ef29d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.registry.loader; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; @@ -32,13 +34,13 @@ import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -//TODO this needs to be versioned, but the runtime item states between 1.17 and 1.17.10 are identical except for new blocks so this works for both /** * Generates a collection of {@link PotionMixData} that enables the * Bedrock client to place brewing items into the brewing stand. @@ -48,63 +50,71 @@ import java.util.Set; * (Ex: Bedrock cannot normally place glass bottles or fully upgraded * potions into the brewing stand, but Java can.) */ -public class PotionMixRegistryLoader implements RegistryLoader> { +public class PotionMixRegistryLoader implements RegistryLoader>> { @Override - public Set load(Object input) { - List ingredients = new ArrayList<>(); - ingredients.add(getNonNull(Items.NETHER_WART)); - ingredients.add(getNonNull(Items.REDSTONE)); - ingredients.add(getNonNull(Items.GLOWSTONE_DUST)); - ingredients.add(getNonNull(Items.FERMENTED_SPIDER_EYE)); - ingredients.add(getNonNull(Items.GUNPOWDER)); - ingredients.add(getNonNull(Items.DRAGON_BREATH)); - ingredients.add(getNonNull(Items.SUGAR)); - ingredients.add(getNonNull(Items.RABBIT_FOOT)); - ingredients.add(getNonNull(Items.GLISTERING_MELON_SLICE)); - ingredients.add(getNonNull(Items.SPIDER_EYE)); - ingredients.add(getNonNull(Items.PUFFERFISH)); - ingredients.add(getNonNull(Items.MAGMA_CREAM)); - ingredients.add(getNonNull(Items.GOLDEN_CARROT)); - ingredients.add(getNonNull(Items.BLAZE_POWDER)); - ingredients.add(getNonNull(Items.GHAST_TEAR)); - ingredients.add(getNonNull(Items.TURTLE_HELMET)); - ingredients.add(getNonNull(Items.PHANTOM_MEMBRANE)); + public Int2ObjectMap> load(Object input) { + var allPotionMixes = new Int2ObjectOpenHashMap>(Registries.ITEMS.get().size()); + for (var entry : Registries.ITEMS.get().int2ObjectEntrySet()) { + ItemMappings mappings = entry.getValue(); + List ingredients = new ArrayList<>(); + ingredients.add(getNonNull(mappings, Items.NETHER_WART)); + ingredients.add(getNonNull(mappings, Items.REDSTONE)); + ingredients.add(getNonNull(mappings, Items.GLOWSTONE_DUST)); + ingredients.add(getNonNull(mappings, Items.FERMENTED_SPIDER_EYE)); + ingredients.add(getNonNull(mappings, Items.GUNPOWDER)); + ingredients.add(getNonNull(mappings, Items.DRAGON_BREATH)); + ingredients.add(getNonNull(mappings, Items.SUGAR)); + ingredients.add(getNonNull(mappings, Items.RABBIT_FOOT)); + ingredients.add(getNonNull(mappings, Items.GLISTERING_MELON_SLICE)); + ingredients.add(getNonNull(mappings, Items.SPIDER_EYE)); + ingredients.add(getNonNull(mappings, Items.PUFFERFISH)); + ingredients.add(getNonNull(mappings, Items.MAGMA_CREAM)); + ingredients.add(getNonNull(mappings, Items.GOLDEN_CARROT)); + ingredients.add(getNonNull(mappings, Items.BLAZE_POWDER)); + ingredients.add(getNonNull(mappings, Items.GHAST_TEAR)); + ingredients.add(getNonNull(mappings, Items.TURTLE_HELMET)); + ingredients.add(getNonNull(mappings, Items.PHANTOM_MEMBRANE)); - List inputs = new ArrayList<>(); - inputs.add(getNonNull(Items.POTION)); - inputs.add(getNonNull(Items.SPLASH_POTION)); - inputs.add(getNonNull(Items.LINGERING_POTION)); + List inputs = List.of( + getNonNull(mappings, Items.POTION), + getNonNull(mappings, Items.SPLASH_POTION), + getNonNull(mappings, Items.LINGERING_POTION) + ); - ItemMapping glassBottle = getNonNull(Items.GLASS_BOTTLE); + ItemMapping glassBottle = getNonNull(mappings, Items.GLASS_BOTTLE); - Set potionMixes = new HashSet<>(); + Set potionMixes = new HashSet<>(); - // Add all types of potions as inputs - ItemMapping fillerIngredient = ingredients.get(0); - for (ItemMapping entryInput : inputs) { - for (Potion potion : Potion.VALUES) { + // Add all types of potions as inputs + ItemMapping fillerIngredient = ingredients.get(0); + for (ItemMapping entryInput : inputs) { + for (Potion potion : Potion.VALUES) { + potionMixes.add(new PotionMixData( + entryInput.getBedrockDefinition().getRuntimeId(), potion.getBedrockId(), + fillerIngredient.getBedrockDefinition().getRuntimeId(), fillerIngredient.getBedrockData(), + glassBottle.getBedrockDefinition().getRuntimeId(), glassBottle.getBedrockData()) + ); + } + } + + // Add all brewing ingredients + // Also adds glass bottle as input + for (ItemMapping ingredient : ingredients) { potionMixes.add(new PotionMixData( - entryInput.getBedrockDefinition().getRuntimeId(), potion.getBedrockId(), - fillerIngredient.getBedrockDefinition().getRuntimeId(), fillerIngredient.getBedrockData(), + glassBottle.getBedrockDefinition().getRuntimeId(), glassBottle.getBedrockData(), + ingredient.getBedrockDefinition().getRuntimeId(), ingredient.getBedrockData(), glassBottle.getBedrockDefinition().getRuntimeId(), glassBottle.getBedrockData()) ); } - } - // Add all brewing ingredients - // Also adds glass bottle as input - for (ItemMapping ingredient : ingredients) { - potionMixes.add(new PotionMixData( - glassBottle.getBedrockDefinition().getRuntimeId(), glassBottle.getBedrockData(), - ingredient.getBedrockDefinition().getRuntimeId(), ingredient.getBedrockData(), - glassBottle.getBedrockDefinition().getRuntimeId(), glassBottle.getBedrockData()) - ); + allPotionMixes.put(entry.getIntKey(), potionMixes); } - return potionMixes; + allPotionMixes.trim(); + return allPotionMixes; } - private static ItemMapping getNonNull(Item javaItem) { + private static ItemMapping getNonNull(ItemMappings mappings, Item javaItem) { ItemMapping itemMapping = Registries.ITEMS.forVersion(GameProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getMapping(javaItem); if (itemMapping == null) throw new NullPointerException("No item entry exists for java identifier: " + javaItem.javaIdentifier()); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index f5f9996d6..b20192e9a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -35,6 +35,7 @@ import org.cloudburstmc.nbt.*; import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544; import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560; import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575; import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.block.BlockStateValues; @@ -73,6 +74,16 @@ public final class BlockRegistryPopulator { .put(ObjectIntPair.of("1_19_20", Bedrock_v544.CODEC.getProtocolVersion()), emptyMapper) .put(ObjectIntPair.of("1_19_50", Bedrock_v560.CODEC.getProtocolVersion()), emptyMapper) .put(ObjectIntPair.of("1_19_60", Bedrock_v567.CODEC.getProtocolVersion()), emptyMapper) + .put(ObjectIntPair.of("1_19_70", Bedrock_v575.CODEC.getProtocolVersion()), (bedrockIdentifier, statesBuilder) -> { + if (bedrockIdentifier.equals("minecraft:wool")) { + String color = (String) statesBuilder.remove("color"); + if ("silver".equals(color)) { + color = "light_gray"; + } + return "minecraft:" + color + "_wool"; + } + return null; + }) .build(); for (Map.Entry, BiFunction> palette : blockMappers.entrySet()) { @@ -216,7 +227,6 @@ public final class BlockRegistryPopulator { Deque cleanIdentifiers = new ArrayDeque<>(); int javaRuntimeId = -1; - int bellBlockId = -1; int cobwebBlockId = -1; int furnaceRuntimeId = -1; int furnaceLitRuntimeId = -1; @@ -293,10 +303,7 @@ public final class BlockRegistryPopulator { // It's possible to only have this store differences in names, but the key set of all Java names is used in sending command suggestions BlockRegistries.JAVA_TO_BEDROCK_IDENTIFIERS.register(cleanJavaIdentifier.intern(), bedrockIdentifier.intern()); - if (javaId.startsWith("minecraft:bell[")) { - bellBlockId = uniqueJavaId; - - } else if (javaId.contains("cobweb")) { + if (javaId.contains("cobweb")) { cobwebBlockId = uniqueJavaId; } else if (javaId.startsWith("minecraft:furnace[facing=north")) { @@ -317,10 +324,6 @@ public final class BlockRegistryPopulator { slimeBlockRuntimeId = javaRuntimeId; } } - if (bellBlockId == -1) { - throw new AssertionError("Unable to find bell in palette"); - } - BlockStateValues.JAVA_BELL_ID = bellBlockId; if (cobwebBlockId == -1) { throw new AssertionError("Unable to find cobwebs in palette"); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 525c310f6..a43b4ec50 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -40,6 +40,7 @@ import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.codec.v544.Bedrock_v544; import org.cloudburstmc.protocol.bedrock.codec.v560.Bedrock_v560; import org.cloudburstmc.protocol.bedrock.codec.v567.Bedrock_v567; +import org.cloudburstmc.protocol.bedrock.codec.v575.Bedrock_v575; import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition; @@ -76,6 +77,7 @@ public class ItemRegistryPopulator { paletteVersions.put("1_19_20", new PaletteVersion(Bedrock_v544.CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_50", new PaletteVersion(Bedrock_v560.CODEC.getProtocolVersion(), Collections.emptyMap())); paletteVersions.put("1_19_60", new PaletteVersion(Bedrock_v567.CODEC.getProtocolVersion(), Collections.emptyMap())); + paletteVersions.put("1_19_70", new PaletteVersion(Bedrock_v575.CODEC.getProtocolVersion(), Collections.emptyMap())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); @@ -173,6 +175,7 @@ public class ItemRegistryPopulator { Set javaOnlyItems = new ObjectOpenHashSet<>(); Collections.addAll(javaOnlyItems, Items.SPECTRAL_ARROW, Items.DEBUG_STICK, Items.KNOWLEDGE_BOOK, Items.TIPPED_ARROW, Items.BUNDLE); + javaOnlyItems.add(Items.DECORATED_POT); if (!customItemsAllowed) { javaOnlyItems.add(Items.FURNACE_MINECART); } @@ -196,6 +199,11 @@ public class ItemRegistryPopulator { mappingItem = entry.getValue(); } + // 1.19.70+ + if (palette.getValue().protocolVersion() >= Bedrock_v575.CODEC.getProtocolVersion() && mappingItem.getBedrockIdentifier().equals("minecraft:wool")) { + mappingItem.setBedrockIdentifier(javaItem.javaIdentifier()); + } + if (customItemsAllowed && javaItem == Items.FURNACE_MINECART) { // Will be added later mappings.add(null); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java index 06903465d..d055f7b28 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java @@ -35,6 +35,7 @@ import org.geysermc.geyser.util.FileUtils; public class PacketRegistryPopulator { + @SuppressWarnings("unchecked") public static void populate() { for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(Translator.class)) { Class packet = clazz.getAnnotation(Translator.class).packet(); @@ -44,18 +45,18 @@ public class PacketRegistryPopulator { try { if (Packet.class.isAssignableFrom(packet)) { Class targetPacket = (Class) packet; - PacketTranslator translator = (PacketTranslator) clazz.newInstance(); + PacketTranslator translator = (PacketTranslator) clazz.getConstructor().newInstance(); Registries.JAVA_PACKET_TRANSLATORS.register(targetPacket, translator); } else if (BedrockPacket.class.isAssignableFrom(packet)) { Class targetPacket = (Class) packet; - PacketTranslator translator = (PacketTranslator) clazz.newInstance(); + PacketTranslator translator = (PacketTranslator) clazz.getConstructor().newInstance(); Registries.BEDROCK_PACKET_TRANSLATORS.register(targetPacket, translator); } else { GeyserImpl.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet."); } - } catch (InstantiationException | IllegalAccessException e) { + } catch (Exception e) { GeyserImpl.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName()); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java index b29fa50c3..f8aeb78ee 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ParticleMapping.java @@ -26,7 +26,6 @@ package org.geysermc.geyser.registry.type; import org.cloudburstmc.protocol.bedrock.data.LevelEventType; -import org.cloudburstmc.protocol.bedrock.data.ParticleType; import javax.annotation.ParametersAreNullableByDefault; diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java index 049086a84..252fed0f4 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.scoreboard; import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; +import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; @@ -44,6 +45,8 @@ import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; +import java.util.stream.Collectors; import static org.geysermc.geyser.scoreboard.UpdateType.*; @@ -365,8 +368,10 @@ public final class Scoreboard { } @Contract("-> new") - public String[] getTeamNames() { - return teams.keySet().toArray(new String[0]); + public LinkedHashMap> getTeamNames() { + return teams.keySet().stream() + .collect(Collectors.toMap(Function.identity(), o -> EnumSet.noneOf(CommandEnumConstraint.class), + (o1, o2) -> o1, LinkedHashMap::new)); } /** diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java index 7738f5f42..e985ca803 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java @@ -33,6 +33,8 @@ import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.HashSet; import java.util.Set; @@ -44,7 +46,7 @@ public final class Team { @Getter(AccessLevel.PACKAGE) private final Set entities; - @Setter private NameTagVisibility nameTagVisibility; + @Nonnull private NameTagVisibility nameTagVisibility = NameTagVisibility.ALWAYS; @Setter private TeamColor color; private final TeamData currentData; @@ -199,6 +201,14 @@ public final class Team { }; } + public Team setNameTagVisibility(@Nullable NameTagVisibility nameTagVisibility) { + if (nameTagVisibility != null) { + // Null check like this (and this.nameTagVisibility defaults to ALWAYS) as of Java 1.19.4 + this.nameTagVisibility = nameTagVisibility; + } + return this; + } + @Override public int hashCode() { return id.hashCode(); diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index e8fc8a51f..0e3cf5f17 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -81,11 +81,11 @@ import lombok.Setter; import lombok.experimental.Accessors; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.common.value.qual.IntRange; -import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.*; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.BedrockServerSession; import org.cloudburstmc.protocol.bedrock.data.*; +import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint; import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.data.command.SoftEnumUpdateType; @@ -114,6 +114,8 @@ import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.erosion.AbstractGeyserboundPacketHandler; +import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; @@ -138,6 +140,7 @@ import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.jetbrains.annotations.NotNull; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -170,6 +173,10 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { @Setter private List certChainData; + @NotNull + @Setter + private AbstractGeyserboundPacketHandler erosionHandler; + @Accessors(fluent = true) @Setter private RemoteServer remoteServer; @@ -257,7 +264,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { /** * Stores a list of all lectern locations and their block entity tags. - * See {@link WorldManager#getLecternDataAt(GeyserSession, int, int, int, boolean)} + * See {@link WorldManager#sendLecternData(GeyserSession, int, int, int)} * for more information. */ private final Set lecternCache; @@ -553,6 +560,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.upstream = new UpstreamSession(bedrockServerSession); this.eventLoop = eventLoop; + this.erosionHandler = new GeyserboundHandshakePacketHandler(this); + this.advancementsCache = new AdvancementsCache(this); this.bookEditCache = new BookEditCache(this); this.chunkCache = new ChunkCache(this); @@ -581,7 +590,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { this.spawned = false; this.loggedIn = false; - if (geyser.getWorldManager().shouldExpectLecternHandled()) { + if (geyser.getWorldManager().shouldExpectLecternHandled(this)) { // Unneeded on these platforms this.lecternCache = null; } else { @@ -631,7 +640,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand. CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); - craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.get()); + craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(this.upstream.getProtocolVersion())); upstream.sendPacket(craftingDataPacket); PlayStatusPacket playStatusPacket = new PlayStatusPacket(); @@ -723,7 +732,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return; } - connectDownstream(); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + } }); } @@ -767,7 +780,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return; } - connectDownstream(); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + } }); } @@ -841,7 +858,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { selectedProfile, service.getAccessToken() ); - connectDownstream(); + try { + connectDownstream(); + } catch (Throwable t) { + t.printStackTrace(); + return false; + } // Save our refresh token for later use geyser.saveRefreshToken(bedrockUsername(), service.getRefreshToken()); @@ -1006,7 +1028,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { // Server is offline, probably disconnectMessage = GeyserLocale.getPlayerLocaleString("geyser.network.remote.server_offline", locale()); } else { - disconnectMessage = MessageTranslator.convertMessageLenient(event.getReason()); + disconnectMessage = MessageTranslator.convertMessage(event.getReason()); } if (downstream instanceof LocalSession) { @@ -1069,6 +1091,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { tickThread.cancel(false); } + erosionHandler.close(); + closed = true; } @@ -1346,6 +1370,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return false; } + public void requestOffhandSwap() { + ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, + Direction.DOWN, 0); + sendDownstreamPacket(swapHandsPacket); + } + /** * Will be overwritten for GeyserConnect. */ @@ -1396,10 +1426,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } public void setServerRenderDistance(int renderDistance) { - // +1 is for Fabric and Spigot - // Without the client misses loading some chunks per https://github.com/GeyserMC/Geyser/issues/3490 - // Fog still appears essentially normally - renderDistance = renderDistance + 1; this.serverRenderDistance = renderDistance; ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); @@ -1411,11 +1437,13 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return this.upstream.getAddress(); } + @Override public boolean sendForm(@NonNull Form form) { formCache.showForm(form); return true; } + @Override public boolean sendForm(@NonNull FormBuilder formBuilder) { formCache.showForm(formBuilder.build()); return true; @@ -1682,6 +1710,8 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { abilities.add(Ability.MINE); // Needed so you can drop items abilities.add(Ability.DOORS_AND_SWITCHES); + // Required for lecterns to work (likely started around 1.19.10; confirmed on 1.19.70) + abilities.add(Ability.OPEN_CONTAINERS); if (gameMode == GameMode.CREATIVE) { // Needed so the client doesn't attempt to take away items abilities.add(Ability.INSTABUILD); @@ -1896,18 +1926,19 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return true; } - public void addCommandEnum(String name, String... enums) { + public void addCommandEnum(String name, String enums) { softEnumPacket(name, SoftEnumUpdateType.ADD, enums); } - public void removeCommandEnum(String name, String... enums) { + public void removeCommandEnum(String name, String enums) { softEnumPacket(name, SoftEnumUpdateType.REMOVE, enums); } - private void softEnumPacket(String name, SoftEnumUpdateType type, String... enums) { + private void softEnumPacket(String name, SoftEnumUpdateType type, String enums) { UpdateSoftEnumPacket packet = new UpdateSoftEnumPacket(); packet.setType(type); - packet.setSoftEnum(new CommandEnumData(name, enums, true)); + // TODO + packet.setSoftEnum(new CommandEnumData(name, new LinkedHashMap<>(Collections.singletonMap(enums, EnumSet.noneOf(CommandEnumConstraint.class))), true)); sendUpstreamPacket(packet); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java index 05c2628df..41f73863e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/LodestoneCache.java @@ -73,8 +73,7 @@ public final class LodestoneCache { } } - for (Int2ObjectMap.Entry entry : this.lodestones.int2ObjectEntrySet()) { - LodestonePos pos = entry.getValue(); + for (LodestonePos pos : this.lodestones.values()) { if (pos.equals(x, y, z, dim)) { // Use this existing position instead this.activeLodestones.put(itemStack, pos); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java index dbb7576d2..a1c928c6b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/EnchantingInventoryTranslator.java @@ -43,6 +43,7 @@ import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; import org.geysermc.geyser.session.GeyserSession; import java.util.Arrays; +import java.util.Locale; public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { public EnchantingInventoryTranslator() { @@ -71,7 +72,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla // The Bedrock index might need changed, so let's look it up and see. int bedrockIndex = value; if (bedrockIndex != -1) { - Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + Enchantment.JavaEnchantment.of(bedrockIndex).name().toLowerCase()); + Enchantment enchantment = Enchantment.getByJavaIdentifier("minecraft:" + Enchantment.JavaEnchantment.of(bedrockIndex).name().toLowerCase(Locale.ROOT)); if (enchantment != null) { // Convert the Java enchantment index to Bedrock's bedrockIndex = enchantment.ordinal(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java index c61ff13de..4a43ea055 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/InventoryTranslator.java @@ -92,7 +92,7 @@ public abstract class InventoryTranslator { put(ContainerType.LOOM, new LoomInventoryTranslator()); put(ContainerType.MERCHANT, new MerchantInventoryTranslator()); put(ContainerType.SHULKER_BOX, new ShulkerInventoryTranslator()); - put(ContainerType.SMITHING, new SmithingInventoryTranslator()); + put(ContainerType.LEGACY_SMITHING, new SmithingInventoryTranslator()); put(ContainerType.STONECUTTER, new StonecutterInventoryTranslator()); /* Lectern */ diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java index 6e9a550dc..ec0d4534d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LecternInventoryTranslator.java @@ -35,6 +35,7 @@ import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.LecternContainer; @@ -110,13 +111,13 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { Vector3i position = session.getLastInteractionBlockPosition(); // If shouldExpectLecternHandled returns true, this is already handled for us // shouldRefresh means that we should boot out the client on our side because their lectern GUI isn't updated yet - boolean shouldRefresh = !session.getGeyser().getWorldManager().shouldExpectLecternHandled() && !session.getLecternCache().contains(position); + boolean shouldRefresh = !session.getGeyser().getWorldManager().shouldExpectLecternHandled(session) && !session.getLecternCache().contains(position); NbtMap blockEntityTag; if (tag != null) { int pagesSize = ((ListTag) tag.get("pages")).size(); ItemData itemData = book.getItemData(session); - NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize); + NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), pagesSize); lecternTag.putCompound("book", NbtMap.builder() .putByte("Count", (byte) itemData.getCount()) .putShort("Damage", (short) 0) @@ -127,7 +128,7 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { blockEntityTag = lecternTag.build(); } else { // There is *a* book here, but... no NBT. - NbtMapBuilder lecternTag = getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 1); + NbtMapBuilder lecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 1); NbtMapBuilder bookTag = NbtMap.builder() .putByte("Count", (byte) 1) .putShort("Damage", (short) 0) @@ -162,20 +163,4 @@ public class LecternInventoryTranslator extends BaseInventoryTranslator { public Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory) { return new LecternContainer(name, windowId, this.size, containerType, playerInventory); } - - public static NbtMapBuilder getBaseLecternTag(int x, int y, int z, int totalPages) { - NbtMapBuilder builder = NbtMap.builder() - .putInt("x", x) - .putInt("y", y) - .putInt("z", z) - .putString("id", "Lectern"); - if (totalPages != 0) { - builder.putByte("hasBook", (byte) 1); - builder.putInt("totalPages", totalPages); - } else { - // Not usually needed, but helps with kicking out Bedrock players from reading the UI - builder.putByte("hasBook", (byte) 0); - } - return builder; - } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java index ab08a5eaf..4abfd18b9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CustomItemTranslator.java @@ -41,10 +41,10 @@ import java.util.OptionalInt; /** * This is only a separate class for testing purposes so we don't have to load in GeyserImpl in ItemTranslator. */ -final class CustomItemTranslator { +public final class CustomItemTranslator { @Nullable - static ItemDefinition getCustomItem(CompoundTag nbt, ItemMapping mapping) { + public static ItemDefinition getCustomItem(CompoundTag nbt, ItemMapping mapping) { if (nbt == null) { return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java index f62dd415f..c43615d47 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java @@ -43,6 +43,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import static org.geysermc.erosion.util.BannerUtils.getJavaPatternTag; + @ItemRemapper public class BannerTranslator extends NbtItemStackTranslator { /** @@ -69,15 +71,6 @@ public class BannerTranslator extends NbtItemStackTranslator { OMINOUS_BANNER_PATTERN.add(getJavaPatternTag("bo", 15)); } - public static CompoundTag getJavaPatternTag(String pattern, int color) { - StringTag patternType = new StringTag("Pattern", pattern); - IntTag colorTag = new IntTag("Color", color); - CompoundTag tag = new CompoundTag(""); - tag.put(patternType); - tag.put(colorTag); - return tag; - } - public BannerTranslator() { appliedItems = Registries.JAVA_ITEMS.get().stream() .filter(entry -> entry.javaIdentifier().endsWith("banner")) @@ -120,7 +113,7 @@ public class BannerTranslator extends NbtItemStackTranslator { * @return The Java edition format pattern nbt */ public static CompoundTag getJavaBannerPattern(NbtMap pattern) { - return BannerTranslator.getJavaPatternTag(pattern.getString("Pattern"), 15 - pattern.getInt("Color")); + return getJavaPatternTag(pattern.getString("Pattern"), 15 - pattern.getInt("Color")); } /** diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java index 204981965..5a61b483d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantmentTranslator.java @@ -25,11 +25,14 @@ package org.geysermc.geyser.translator.inventory.item.nbt; +import com.github.steveice10.mc.protocol.data.game.Identifier; import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.Enchantment; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.inventory.item.ItemRemapper; import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator; @@ -43,28 +46,27 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { @Override public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { List newTags = new ArrayList<>(); - Tag enchantmentTag = itemTag.get("Enchantments"); + Tag enchantmentTag = itemTag.remove("Enchantments"); if (enchantmentTag instanceof ListTag listTag) { for (Tag tag : listTag.getValue()) { if (!(tag instanceof CompoundTag)) continue; - - CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag); - newTags.add(bedrockTag); - } - itemTag.remove("Enchantments"); - } - enchantmentTag = itemTag.get("StoredEnchantments"); - if (enchantmentTag instanceof ListTag listTag) { - for (Tag tag : listTag.getValue()) { - if (!(tag instanceof CompoundTag)) continue; - - CompoundTag bedrockTag = remapEnchantment((CompoundTag) tag); + CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag); + if (bedrockTag != null) { + newTags.add(bedrockTag); + } + } + } + + // TODO consolidate this into EnchantedBookTranslator + enchantmentTag = itemTag.remove("StoredEnchantments"); + if (enchantmentTag instanceof ListTag listTag) { + for (Tag tag : listTag.getValue()) { + if (!(tag instanceof CompoundTag)) continue; + CompoundTag bedrockTag = remapEnchantment(session, (CompoundTag) tag, itemTag); if (bedrockTag != null) { - bedrockTag.put(new ShortTag("GeyserStoredEnchantment", (short) 0)); newTags.add(bedrockTag); } } - itemTag.remove("StoredEnchantments"); } if (!newTags.isEmpty()) { @@ -99,7 +101,6 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { javaValue.put("lvl", new IntTag("lvl", levelTag != null ? levelTag.getValue() : 1)); javaTag.setValue(javaValue); - if (geyserStoredEnchantmentTag != null) { tagValue.remove("GeyserStoredEnchantment"); storedEnchantments.add(javaTag); @@ -120,13 +121,20 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { } - private CompoundTag remapEnchantment(CompoundTag tag) { + private CompoundTag remapEnchantment(GeyserSession session, CompoundTag tag, CompoundTag rootTag) { Tag javaEnchId = tag.get("id"); if (!(javaEnchId instanceof StringTag)) return null; Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); if (enchantment == null) { + if (Identifier.formalize((String) javaEnchId.getValue()).equals("minecraft:sweeping")) { + Tag javaEnchLvl = tag.get("lvl"); + int sweepingLvl = javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.intValue() : 0; + + addSweeping(session, rootTag, sweepingLvl); + return null; + } GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue()); return null; } @@ -140,4 +148,21 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { return bedrockTag; } -} + private void addSweeping(GeyserSession session, CompoundTag itemTag, int level) { + CompoundTag displayTag = itemTag.get("display"); + if (displayTag == null) { + displayTag = new CompoundTag("display"); + itemTag.put(displayTag); + } + ListTag loreTag = displayTag.get("Lore"); + if (loreTag == null) { + loreTag = new ListTag("Lore"); + displayTag.put(loreTag); + } + + String sweepingTranslation = MinecraftLocale.getLocaleString("enchantment.minecraft.sweeping", session.locale()); + String lvlTranslation = MinecraftLocale.getLocaleString("enchantment.level." + level, session.locale()); + + loreTag.add(new StringTag("", ChatColor.RESET + ChatColor.GRAY + sweepingTranslation + " " + lvlTranslation)); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java index 16967f27e..40444ab72 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntity.java @@ -224,7 +224,7 @@ public class PistonBlockEntity { int blockId = session.getGeyser().getWorldManager().getBlockAt(session, blockInFront); if (BlockStateValues.isPistonHead(blockId)) { ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront); - } else if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT && blockId == BlockStateValues.JAVA_AIR_ID) { + } else if ((session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) && blockId == BlockStateValues.JAVA_AIR_ID) { // Spigot removes the piston head from the cache, but we need to send the block update ourselves ChunkUtils.updateBlock(session, BlockStateValues.JAVA_AIR_ID, blockInFront); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java index f9a20a879..19d15c04d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockPickRequestTranslator.java @@ -71,30 +71,28 @@ public class BedrockBlockPickRequestTranslator extends PacketTranslator { + .whenComplete((tag, ex) -> session.ensureInEventLoop(() -> { if (tag == null) { pickItem(session, blockMapping); return; } - session.ensureInEventLoop(() -> { - if (addNbtData) { - ListTag lore = new ListTag("Lore"); - lore.add(new StringTag("", "\"(+NBT)\"")); - CompoundTag display = tag.get("display"); - if (display == null) { - display = new CompoundTag("display"); - tag.put(display); - } - display.put(lore); + if (addNbtData) { + ListTag lore = new ListTag("Lore"); + lore.add(new StringTag("", "\"(+NBT)\"")); + CompoundTag display = tag.get("display"); + if (display == null) { + display = new CompoundTag("display"); + tag.put(display); } - // I don't really like this... I'd rather get an ID from the block mapping I think - ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem()); + display.put(lore); + } + // I don't really like this... I'd rather get an ID from the block mapping I think + ItemMapping mapping = session.getItemMappings().getMapping(blockMapping.getPickItem()); - ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), 1, tag); - InventoryUtils.findOrCreateItem(session, itemStack); - }); - }); + ItemStack itemStack = new ItemStack(mapping.getJavaItem().javaId(), 1, tag); + InventoryUtils.findOrCreateItem(session, itemStack); + })); return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java index eee240907..f64ddeac6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockEntityPickRequestTranslator.java @@ -62,8 +62,10 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator "birch"; case 3 -> "jungle"; case 4 -> "acacia"; - case 5 -> "dark_oak"; - case 6 -> "mangrove"; + //case 5 -> "cherry"; TODO + case 6 -> "dark_oak"; + case 7 -> "mangrove"; + //case 8 -> "bamboo"; default -> "oak"; }; itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java index 76c30a2a1..ba96e69c5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java @@ -74,9 +74,11 @@ import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.BlockUtils; +import org.geysermc.geyser.util.CooldownUtils; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; -import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -355,43 +357,6 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator legacySlots = packet.getLegacySlots(); - if (packet.getActions().size() == 1 && legacySlots.size() > 0) { - InventoryActionData actionData = packet.getActions().get(0); - LegacySetItemSlotData slotData = legacySlots.get(0); - if (slotData.getContainerId() == 6 && actionData.getToItem().getDefinition() != ItemDefinition.AIR) { - // The player is trying to swap out an armor piece that already has an item in it - if (session.getGeyser().getConfig().isAlwaysQuickChangeArmor()) { - // Java doesn't know when a player is in its own inventory and not, so we - // can abuse this feature to send a swap inventory packet - int bedrockHotbarSlot = packet.getHotbarSlot(); - Click click = InventoryUtils.getClickForHotbarSwap(bedrockHotbarSlot); - if (click != null && slotData.getSlots().length != 0) { - Inventory playerInventory = session.getPlayerInventory(); - // Bedrock sends us the index of the slot in the armor container; armor in Java - // Edition is offset by 5 in the player inventory - int armorSlot = slotData.getSlots()[0] + 5; - GeyserItemStack armorSlotItem = playerInventory.getItem(armorSlot); - GeyserItemStack hotbarItem = playerInventory.getItem(playerInventory.getOffsetForHotbar(bedrockHotbarSlot)); - playerInventory.setItem(armorSlot, hotbarItem, session); - playerInventory.setItem(bedrockHotbarSlot, armorSlotItem, session); - - Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(2); - changedSlots.put(armorSlot, hotbarItem.getItemStack()); - changedSlots.put(bedrockHotbarSlot, armorSlotItem.getItemStack()); - - ServerboundContainerClickPacket clickPacket = new ServerboundContainerClickPacket( - playerInventory.getJavaId(), playerInventory.getStateId(), armorSlot, - click.actionType, click.action, null, changedSlots); - session.sendDownstreamPacket(clickPacket); - } - } else { - // Disallowed; let's revert - session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory()); - } - } - } } case 2 -> { int blockState = session.getGameMode() == GameMode.CREATIVE ? diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java index 2d0f30d34..00cd5e5fd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRequestAbilityTranslator.java @@ -30,7 +30,6 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server import org.cloudburstmc.protocol.bedrock.data.Ability; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.RequestAbilityPacket; -import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -43,31 +42,22 @@ public class BedrockRequestAbilityTranslator extends PacketTranslator { public void translate(GeyserSession session, EmotePacket packet) { if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() != EmoteOffhandWorkaroundOption.DISABLED) { // Activate the workaround - we should trigger the offhand now - ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, - Direction.DOWN, 0); - session.sendDownstreamPacket(swapHandsPacket); + session.requestOffhandSwap(); if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) { return; } } + // For the future: could have a method that exposes which players will see the emote + ClientEmoteEvent event = new ClientEmoteEvent(session, packet.getEmoteId()); + session.getGeyser().eventBus().fire(event); + if (event.isCancelled()) { + return; + } + int javaId = session.getPlayerEntity().getEntityId(); for (GeyserSession otherSession : session.getGeyser().getSessionManager().getSessions().values()) { if (otherSession != session) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java index abbeff72c..49ce28167 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockInteractTranslator.java @@ -80,21 +80,23 @@ public class BedrockInteractTranslator extends PacketTranslator session.sendDownstreamPacket(sneakPacket); Entity currentVehicle = session.getPlayerEntity().getVehicle(); - session.setMountVehicleScheduledFuture(session.scheduleInEventLoop(() -> { - if (session.getPlayerEntity().getVehicle() == null) { - return; - } + if (currentVehicle != null) { + session.setMountVehicleScheduledFuture(session.scheduleInEventLoop(() -> { + if (session.getPlayerEntity().getVehicle() == null) { + return; + } - long vehicleBedrockId = currentVehicle.getGeyserId(); - if (session.getPlayerEntity().getVehicle().getGeyserId() == vehicleBedrockId) { - // The Bedrock client, as of 1.19.51, dismounts on its end. The server may not agree with this. - // If the server doesn't agree with our dismount (sends a packet saying we dismounted), - // then remount the player. - SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); - linkPacket.setEntityLink(new EntityLinkData(vehicleBedrockId, session.getPlayerEntity().getGeyserId(), EntityLinkData.Type.PASSENGER, true, false)); - session.sendUpstreamPacket(linkPacket); - } - }, 1, TimeUnit.SECONDS)); + long vehicleBedrockId = currentVehicle.getGeyserId(); + if (session.getPlayerEntity().getVehicle().getGeyserId() == vehicleBedrockId) { + // The Bedrock client, as of 1.19.51, dismounts on its end. The server may not agree with this. + // If the server doesn't agree with our dismount (sends a packet saying we dismounted), + // then remount the player. + SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); + linkPacket.setEntityLink(new EntityLinkData(vehicleBedrockId, session.getPlayerEntity().getGeyserId(), EntityLinkData.Type.PASSENGER, true, false)); + session.sendUpstreamPacket(linkPacket); + } + }, 1, TimeUnit.SECONDS)); + } break; case MOUSEOVER: // Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index b5aaab3a7..d1a2e94b2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -30,12 +30,6 @@ import com.github.steveice10.mc.protocol.data.game.command.CommandParser; import com.github.steveice10.mc.protocol.data.game.command.properties.ResourceProperties; import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; -import org.cloudburstmc.protocol.bedrock.data.command.CommandData; -import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint; -import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData; -import org.cloudburstmc.protocol.bedrock.data.command.CommandParam; -import org.cloudburstmc.protocol.bedrock.data.command.CommandParamData; -import org.cloudburstmc.protocol.bedrock.packet.AvailableCommandsPacket; import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -46,6 +40,8 @@ import lombok.Getter; import lombok.ToString; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.cloudburstmc.protocol.bedrock.data.command.*; +import org.cloudburstmc.protocol.bedrock.packet.AvailableCommandsPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.java.ServerDefineCommandsEvent; import org.geysermc.geyser.command.GeyserCommandManager; @@ -58,8 +54,8 @@ import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.EntityUtils; import java.util.*; -import java.util.stream.Collectors; +@SuppressWarnings("removal") // We know. This is our doing. @Translator(packet = ClientboundCommandsPacket.class) public class JavaCommandsTranslator extends PacketTranslator { @@ -207,9 +203,10 @@ public class JavaCommandsTranslator extends PacketTranslator= 1) { @@ -342,9 +339,7 @@ public class JavaCommandsTranslator extends PacketTranslator o, o -> EnumSet.noneOf(CommandEnumConstraint.class), (o1, o2) -> o1, LinkedHashMap::new)), - true + session.getWorldCache().getScoreboard().getTeamNames(), true )); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java index d50a74394..cf5cfa198 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCustomPayloadTranslator.java @@ -35,10 +35,13 @@ import io.netty.buffer.Unpooled; import org.geysermc.cumulus.Forms; import org.geysermc.cumulus.form.Form; import org.geysermc.cumulus.form.util.FormType; +import org.geysermc.erosion.Constants; +import org.geysermc.erosion.packet.ErosionPacket; +import org.geysermc.erosion.packet.Packets; +import org.geysermc.erosion.packet.geyserbound.GeyserboundPacket; import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; -import org.geysermc.geyser.api.network.AuthType; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -51,82 +54,96 @@ public class JavaCustomPayloadTranslator extends PacketTranslator erosionPacket = Packets.decode(buf); + ((GeyserboundPacket) erosionPacket).handle(session.getErosionHandler()); return; } - String channel = packet.getChannel(); - if (channel.equals(PluginMessageChannels.FORM)) { - byte[] data = packet.getData(); + session.ensureInEventLoop(() -> { + byte[] data = packet.getData(); - // receive: first byte is form type, second and third are the id, remaining is the form data - // respond: first and second byte id, remaining is form response data + // receive: first byte is form type, second and third are the id, remaining is the form data + // respond: first and second byte id, remaining is form response data - FormType type = FormType.fromOrdinal(data[0]); - if (type == null) { - throw new NullPointerException("Got type " + data[0] + " which isn't a valid form type!"); - } - - String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8); - - Form form = Forms.fromJson(dataString, type, (ignored, response) -> { - byte[] finalData; - if (response == null) { - // Response data can be null as of 1.19.20 (same behaviour as empty response data) - // Only need to send the form id - finalData = new byte[]{data[1], data[2]}; - } else { - byte[] raw = response.getBytes(StandardCharsets.UTF_8); - finalData = new byte[raw.length + 2]; - - finalData[0] = data[1]; - finalData[1] = data[2]; - System.arraycopy(raw, 0, finalData, 2, raw.length); + FormType type = FormType.fromOrdinal(data[0]); + if (type == null) { + throw new NullPointerException("Got type " + data[0] + " which isn't a valid form type!"); } - session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData)); + String dataString = new String(data, 3, data.length - 3, Charsets.UTF_8); + + Form form = Forms.fromJson(dataString, type, (ignored, response) -> { + byte[] finalData; + if (response == null) { + // Response data can be null as of 1.19.20 (same behaviour as empty response data) + // Only need to send the form id + finalData = new byte[]{data[1], data[2]}; + } else { + byte[] raw = response.getBytes(StandardCharsets.UTF_8); + finalData = new byte[raw.length + 2]; + + finalData[0] = data[1]; + finalData[1] = data[2]; + System.arraycopy(raw, 0, finalData, 2, raw.length); + } + + session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData)); + }); + session.sendForm(form); }); - session.sendForm(form); } else if (channel.equals(PluginMessageChannels.TRANSFER)) { - byte[] data = packet.getData(); + session.ensureInEventLoop(() -> { + byte[] data = packet.getData(); - // port (4 bytes), address (remaining data) - if (data.length < 5) { - throw new NullPointerException("Transfer data should be at least 5 bytes long"); - } + // port (4 bytes), address (remaining data) + if (data.length < 5) { + throw new NullPointerException("Transfer data should be at least 5 bytes long"); + } - int port = data[0] << 24 | (data[1] & 0xFF) << 16 | (data[2] & 0xFF) << 8 | data[3] & 0xFF; - String address = new String(data, 4, data.length - 4); + int port = data[0] << 24 | (data[1] & 0xFF) << 16 | (data[2] & 0xFF) << 8 | data[3] & 0xFF; + String address = new String(data, 4, data.length - 4); - if (logger.isDebug()) { - logger.info("Transferring client to: " + address + ":" + port); - } + if (logger.isDebug()) { + logger.info("Transferring client to: " + address + ":" + port); + } - TransferPacket transferPacket = new TransferPacket(); - transferPacket.setAddress(address); - transferPacket.setPort(port); - session.sendUpstreamPacket(transferPacket); + TransferPacket transferPacket = new TransferPacket(); + transferPacket.setAddress(address); + transferPacket.setPort(port); + session.sendUpstreamPacket(transferPacket); + }); } else if (channel.equals(PluginMessageChannels.PACKET)) { - logger.debug("A packet has been sent using the Floodgate api"); - byte[] data = packet.getData(); + session.ensureInEventLoop(() -> { + logger.debug("A packet has been sent using the Floodgate api"); + byte[] data = packet.getData(); - // packet id, packet data - if (data.length < 2) { - throw new IllegalStateException("Packet data should be at least 2 bytes long"); - } + // packet id, packet data + if (data.length < 2) { + throw new IllegalStateException("Packet data should be at least 2 bytes long"); + } - int packetId = data[0] & 0xFF; - ByteBuf packetData = Unpooled.wrappedBuffer(data, 1, data.length - 1); + int packetId = data[0] & 0xFF; + ByteBuf packetData = Unpooled.wrappedBuffer(data, 1, data.length - 1); - var toSend = new UnknownPacket(); - toSend.setPacketId(packetId); - toSend.setPayload(packetData); + var toSend = new UnknownPacket(); + toSend.setPacketId(packetId); + toSend.setPayload(packetData); - session.sendUpstreamPacket(toSend); + session.sendUpstreamPacket(toSend); + }); } } + + @Override + public boolean shouldExecuteInEventLoop() { + // For Erosion packets + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java index 2ab82ad5c..41eb5062a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaKeepAliveTranslator.java @@ -47,4 +47,9 @@ public class JavaKeepAliveTranslator extends PacketTranslator dimensions = session.getDimensions(); dimensions.clear(); @@ -107,11 +111,6 @@ public class JavaLoginTranslator extends PacketTranslator CARTOGRAPHY_RECIPES = Arrays.asList( + private static final List CARTOGRAPHY_RECIPES = List.of( MultiRecipeData.of(UUID.fromString("8b36268c-1829-483c-a0f1-993b7156a8f2"), ++LAST_RECIPE_NET_ID), // Map extending MultiRecipeData.of(UUID.fromString("442d85ed-8272-4543-a6f1-418f90ded05d"), ++LAST_RECIPE_NET_ID), // Map cloning MultiRecipeData.of(UUID.fromString("98c84b38-1085-46bd-b1ce-dd38c159e6cc"), ++LAST_RECIPE_NET_ID), // Map upgrading @@ -102,6 +102,10 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { // Required to translate these as of 1.18.10, or else they cannot be crafted - SmithingRecipeData recipeData = (SmithingRecipeData) recipe.getData(); + LegacyUpgradeRecipeData recipeData = (LegacyUpgradeRecipeData) recipe.getData(); ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult()); for (ItemStack base : recipeData.getBase().getOptions()) { ItemDescriptorWithCount bedrockBase = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, base)); @@ -170,7 +177,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { @@ -219,12 +226,14 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator, IntSet> squashedOptions = new HashMap<>(); for (int i = 0; i < ingredients.length; i++) { if (ingredients[i].getOptions().length == 0) { squashedOptions.computeIfAbsent(Collections.singleton(ItemDescriptorWithCount.EMPTY), k -> new IntOpenHashSet()).add(i); continue; } + empty = false; Ingredient ingredient = ingredients[i]; Map> groupedByIds = Arrays.stream(ingredient.getOptions()) .map(item -> ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, item))) @@ -252,6 +261,11 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new IntOpenHashSet()).add(i); } + if (empty) { + // Crashes Bedrock 1.19.70 otherwise + // Fixes https://github.com/GeyserMC/Geyser/issues/3549 + return null; + } int totalCombinations = 1; for (Set optionSet : squashedOptions.keySet()) { totalCombinations *= optionSet.size(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java similarity index 55% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java index 9e51b72ce..19a6e25c0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaDamageEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2022 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2023 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -23,20 +23,30 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.bedrock; +package org.geysermc.geyser.translator.protocol.java.entity; -import org.cloudburstmc.protocol.bedrock.data.AdventureSetting; -import org.cloudburstmc.protocol.bedrock.packet.AdventureSettingsPacket; +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.ClientboundDamageEventPacket; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType; +import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; +import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -@Translator(packet = AdventureSettingsPacket.class) -public class BedrockAdventureSettingsTranslator extends PacketTranslator { +@Translator(packet = ClientboundDamageEventPacket.class) +public class JavaDamageEventTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, AdventureSettingsPacket packet) { - boolean isFlying = packet.getSettings().contains(AdventureSetting.FLYING); - BedrockRequestAbilityTranslator.handle(session, isFlying); + public void translate(GeyserSession session, ClientboundDamageEventPacket packet) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity == null) { + return; + } + + // We can probably actually map damage types. + EntityEventPacket entityEventPacket = new EntityEventPacket(); + entityEventPacket.setRuntimeEntityId(entity.getGeyserId()); + entityEventPacket.setType(EntityEventType.HURT); + session.sendUpstreamPacket(entityEventPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index a25f11cd5..50582974d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -88,15 +88,6 @@ public class JavaEntityEventTranslator extends PacketTranslator 1)); // Force an update to the passenger metadata passenger.updateBedrockMetadata(); + + if (passenger == session.getPlayerEntity()) { + //TODO test + if (session.getMountVehicleScheduledFuture() != null) { + // Cancel this task as it is now unnecessary. + // Note that this isn't present in JavaSetPassengersTranslator as that code is not called for players + // as of Java 1.19.3, but the scheduled future checks for the vehicle being null anyway. + session.getMountVehicleScheduledFuture().cancel(false); + } + } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java index 9fd0b7fbc..a2fc0c07c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerPositionTranslator.java @@ -30,20 +30,16 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; import org.cloudburstmc.math.vector.Vector3f; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.packet.ChunkRadiusUpdatedPacket; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.RespawnPacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; import org.geysermc.geyser.entity.EntityDefinitions; -import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.TeleportCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.ChunkUtils; -import org.geysermc.geyser.util.EntityUtils; @Translator(packet = ClientboundPlayerPositionPacket.class) public class JavaPlayerPositionTranslator extends PacketTranslator { @@ -101,27 +97,6 @@ public class JavaPlayerPositionTranslator extends PacketTranslator 1); - entity.updateBedrockMetadata(); - - if (session.getMountVehicleScheduledFuture() != null) { - // Cancel this task as it is now unnecessary. - // Note that this isn't present in JavaSetPassengersTranslator as that code is not called for players - // as of Java 1.19.3, but the scheduled future checks for the vehicle being null anyway. - session.getMountVehicleScheduledFuture().cancel(false); - } - } - // If coordinates are relative, then add to the existing coordinate double newX = packet.getX() + (packet.getRelative().contains(PositionElement.X) ? entity.getPosition().getX() : 0); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java index c38db1f79..e4b278c48 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockEventTranslator.java @@ -58,15 +58,16 @@ public class JavaBlockEventTranslator extends PacketTranslator { + blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState)); + session.sendUpstreamPacket(blockEventPacket); + }); } else if (packet.getValue() instanceof PistonValue pistonValue) { PistonValueType action = (PistonValueType) packet.getType(); - Direction direction = Direction.fromPistonValue(pistonValue); + Direction direction = Direction.fromPistonValue(pistonValue.getDirection()); PistonCache pistonCache = session.getPistonCache(); - if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT) { + if (session.getGeyser().getPlatformType() == PlatformType.SPIGOT || session.getErosionHandler().isActive()) { // Mostly handled in the GeyserPistonEvents class // Retracting sticky pistons is an exception, since the event is not called on Spigot from 1.13.2 - 1.17.1 // See https://github.com/PaperMC/Paper/blob/6fa1983e9ce177a4a412d5b950fd978620174777/patches/server/0304-Fire-BlockPistonRetractEvent-for-all-empty-pistons.patch @@ -103,7 +104,7 @@ public class JavaBlockEventTranslator extends PacketTranslator 0; // north - case 4 -> 1; // east - case 5 -> 3;// west - default -> bellValue.getValue(); // south (2) is identical + int bedrockRingDirection = switch (bellValue.getDirection()) { + case SOUTH -> 0; + case WEST -> 1; + case NORTH -> 2; + case EAST -> 3; + default -> throw new IllegalStateException("Unexpected BellValue Direction: " + bellValue.getDirection()); }; builder.putInt("Direction", bedrockRingDirection); builder.putByte("Ringing", (byte) 1); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java index 28ec9984e..d17cef461 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaBlockUpdateTranslator.java @@ -43,7 +43,7 @@ public class JavaBlockUpdateTranslator extends PacketTranslator iterator = session.getLecternCache().iterator(); while (iterator.hasNext()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java index 8f5adf4b9..cc787d4e2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaGameEventTranslator.java @@ -48,21 +48,23 @@ import org.geysermc.geyser.translator.protocol.Translator; @Translator(packet = ClientboundGameEventPacket.class) public class JavaGameEventTranslator extends PacketTranslator { + // Strength of rainstorms and thunderstorms is a 0-1 float on Java, while on Bedrock it is a 0-65535 int + private static final int MAX_STORM_STRENGTH = 65535; @Override public void translate(GeyserSession session, ClientboundGameEventPacket packet) { PlayerEntity entity = session.getPlayerEntity(); switch (packet.getNotification()) { + // Yes, START_RAIN and STOP_RAIN are swapped in terms of what they cause the client to do. + // This is how the Mojang mappings name them, so we go with it + // It seems Mojang's intent was that START_RAIN would set the rain strength to 0 so that it can then be incremeneted on a gradient by the server + // The inverse is true for STOP_RAIN + // This is indeed the behavior of the vanilla server + // However, it seems most server software (at least Spigot and Paper) did not go along with this + // As a result many developers use these packets for the opposite of what their names implies + // Behavior last verified with Java 1.19.4 and Bedrock 1.19.71 case START_RAIN: - LevelEventPacket startRainPacket = new LevelEventPacket(); - startRainPacket.setType(LevelEvent.START_RAINING); - startRainPacket.setData(Integer.MAX_VALUE); - startRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(startRainPacket); - session.setRaining(true); - break; - case STOP_RAIN: LevelEventPacket stopRainPacket = new LevelEventPacket(); stopRainPacket.setType(LevelEvent.STOP_RAINING); stopRainPacket.setData(0); @@ -70,34 +72,35 @@ public class JavaGameEventTranslator extends PacketTranslator 0f; - // Java sends the rain level. Bedrock doesn't care, so we don't care if it's already raining. - if (isCurrentlyRaining != session.isRaining()) { - LevelEventPacket changeRainPacket = new LevelEventPacket(); - changeRainPacket.setType(isCurrentlyRaining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); - changeRainPacket.setData(Integer.MAX_VALUE); // Dunno what this does; used to be implemented with ThreadLocalRandom - changeRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeRainPacket); - session.setRaining(isCurrentlyRaining); - } + float rainStrength = ((RainStrengthValue) packet.getValue()).getStrength(); + boolean isCurrentlyRaining = rainStrength > 0f; + LevelEventPacket changeRainPacket = new LevelEventPacket(); + changeRainPacket.setType(isCurrentlyRaining ? LevelEvent.START_RAINING : LevelEvent.STOP_RAINING); + // This is the rain strength on LevelEventType.START_RAINING, but can be any value on LevelEventType.STOP_RAINING + changeRainPacket.setData((int) (rainStrength * MAX_STORM_STRENGTH)); + changeRainPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(changeRainPacket); + session.setRaining(isCurrentlyRaining); break; case THUNDER_STRENGTH: // See above, same process - ThunderStrengthValue thunderValue = (ThunderStrengthValue) packet.getValue(); - boolean isCurrentlyThundering = thunderValue.getStrength() > 0f; - if (isCurrentlyThundering != session.isThunder()) { - LevelEventPacket changeThunderPacket = new LevelEventPacket(); - changeThunderPacket.setType(isCurrentlyThundering ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); - changeThunderPacket.setData(Integer.MAX_VALUE); - changeThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeThunderPacket); - session.setThunder(isCurrentlyThundering); - } + float thunderStrength = ((ThunderStrengthValue) packet.getValue()).getStrength(); + boolean isCurrentlyThundering = thunderStrength > 0f; + LevelEventPacket changeThunderPacket = new LevelEventPacket(); + changeThunderPacket.setType(isCurrentlyThundering ? LevelEvent.START_THUNDERSTORM : LevelEvent.STOP_THUNDERSTORM); + changeThunderPacket.setData((int) (thunderStrength * MAX_STORM_STRENGTH)); + changeThunderPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(changeThunderPacket); + session.setThunder(isCurrentlyThundering); break; case CHANGE_GAMEMODE: GameMode gameMode = (GameMode) packet.getValue(); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java index 712e7fa89..8c768e22e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelChunkWithLightTranslator.java @@ -35,11 +35,6 @@ import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityInfo; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelChunkWithLightPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import org.cloudburstmc.math.vector.Vector3i; -import org.cloudburstmc.nbt.NBTOutputStream; -import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtUtils; -import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufOutputStream; @@ -48,6 +43,13 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.cloudburstmc.math.vector.Vector3i; +import org.cloudburstmc.nbt.NBTOutputStream; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.nbt.NbtUtils; +import org.cloudburstmc.protocol.bedrock.packet.LevelChunkPacket; +import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.level.block.BlockStateValues; @@ -94,6 +96,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator bedrockBlockEntities = new ObjectArrayList<>(blockEntities.length); + final List lecterns = new ObjectArrayList<>(); BitSet waterloggedPaletteIds = new BitSet(); BitSet bedrockOnlyBlockEntityIds = new BitSet(); @@ -239,7 +242,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator entry : session.getItemFrameCache().entrySet()) { Vector3i position = entry.getKey(); if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index 4c49deb0d..6e7f64c9e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -159,7 +159,7 @@ public class JavaLevelEventTranslator extends PacketTranslator { data = 4; pos = pos.add(0, -0.9f, 0); diff --git a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java index 894a19539..acf5773c5 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -30,6 +30,7 @@ import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntLists; import lombok.experimental.UtilityClass; +import org.cloudburstmc.math.GenericMath; import org.cloudburstmc.math.vector.Vector2i; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.protocol.bedrock.data.defintions.BlockDefinition; @@ -92,7 +93,9 @@ public class ChunkUtils { if (chunkPos == null || !chunkPos.equals(newChunkPos)) { NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket(); chunkPublisherUpdatePacket.setPosition(position); - chunkPublisherUpdatePacket.setRadius(session.getServerRenderDistance() << 4); + // Mitigates chunks not loading on 1.17.1 Paper and 1.19.3 Fabric. As of Bedrock 1.19.60. + // https://github.com/GeyserMC/Geyser/issues/3490 + chunkPublisherUpdatePacket.setRadius(GenericMath.ceil((session.getServerRenderDistance() + 1) * MathUtils.SQRT_OF_TWO) << 4); session.sendUpstreamPacket(chunkPublisherUpdatePacket); session.setLastChunkPosition(newChunkPos); diff --git a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index 0141e22ea..457993ac2 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -97,6 +97,7 @@ public class InventoryUtils { if (openInv != null && openInv.getJavaId() == inventory.getJavaId()) { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); + openInv.setDisplayed(true); } else if (openInv != null && openInv.isPending()) { // Presumably, this inventory is no longer relevant, and the client doesn't care about it displayInventory(session, openInv); @@ -105,6 +106,7 @@ public class InventoryUtils { } else { translator.openInventory(session, inventory); translator.updateInventory(session, inventory); + inventory.setDisplayed(true); } } else { session.setOpenInventory(null); @@ -119,7 +121,7 @@ public class InventoryUtils { if (inventory != null) { InventoryTranslator translator = session.getInventoryTranslator(); translator.closeInventory(session, inventory); - if (confirm && !inventory.isPending() && !(translator instanceof LecternInventoryTranslator)) { + if (confirm && inventory.isDisplayed() && !inventory.isPending() && !(translator instanceof LecternInventoryTranslator)) { session.setClosingInventory(true); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java index 0504b6321..dd523df5a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -165,18 +165,14 @@ public class LoginEncryptionUtils { data.setOriginalString(clientData); session.setClientData(data); - if (EncryptionUtils.canUseEncryption()) { - try { - LoginEncryptionUtils.startEncryptionHandshake(session, identityPublicKey); - } catch (Throwable e) { - // An error can be thrown on older Java 8 versions about an invalid key - if (geyser.getConfig().isDebugMode()) { - e.printStackTrace(); - } - - sendEncryptionFailedMessage(geyser); + try { + LoginEncryptionUtils.startEncryptionHandshake(session, identityPublicKey); + } catch (Throwable e) { + // An error can be thrown on older Java 8 versions about an invalid key + if (geyser.getConfig().isDebugMode()) { + e.printStackTrace(); } - } else { + sendEncryptionFailedMessage(geyser); } } catch (Exception ex) { diff --git a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java index 049d78619..dc0edd37a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java @@ -38,10 +38,13 @@ import org.geysermc.geyser.command.GeyserCommandSource; import org.geysermc.geyser.network.GameProtocol; import org.geysermc.geyser.text.GeyserLocale; +import javax.annotation.Nonnull; +import java.util.OptionalInt; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; public final class VersionCheckUtils { + private static @Nonnull OptionalInt LATEST_BEDROCK_RELEASE = OptionalInt.empty(); public static void checkForOutdatedFloodgate(GeyserLogger logger) { try { @@ -61,10 +64,12 @@ public final class VersionCheckUtils { JsonNode bedrock = json.get("bedrock").get("protocol"); int protocolVersion = bedrock.get("id").asInt(); if (GameProtocol.getBedrockCodec(protocolVersion) != null) { + LATEST_BEDROCK_RELEASE = OptionalInt.empty(); // We support the latest version! No need to print a message. return; } + LATEST_BEDROCK_RELEASE = OptionalInt.of(protocolVersion); final String newBedrockVersion = bedrock.get("name").asText(); // Delayed for two reasons: save unnecessary processing, and wait to load locale if this is on join. @@ -89,6 +94,10 @@ public final class VersionCheckUtils { }); } + public static @Nonnull OptionalInt getLatestBedrockRelease() { + return LATEST_BEDROCK_RELEASE; + } + private VersionCheckUtils() { } } diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index c0889f1c5..e4a98b3fc 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -91,7 +91,7 @@ public class WebUtils { InputStream in = con.getInputStream(); Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING); } catch (Exception e) { - throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); + throw new RuntimeException("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java index a50197259..bafb2924c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java +++ b/core/src/main/java/org/geysermc/geyser/util/collection/LecternHasBookMap.java @@ -27,9 +27,9 @@ package org.geysermc.geyser.util.collection; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; +import org.geysermc.erosion.util.LecternUtils; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.util.BlockEntityUtils; /** @@ -47,27 +47,24 @@ public class LecternHasBookMap extends FixedInt2BooleanMap { int offset = blockState - this.start; if (offset < 0 || offset >= this.value.length) { // Block state is out of bounds of this map - lectern has been destroyed, if it existed - if (!worldManager.shouldExpectLecternHandled()) { + if (!worldManager.shouldExpectLecternHandled(session)) { session.getLecternCache().remove(position); } return; } boolean newLecternHasBook; - if (worldManager.shouldExpectLecternHandled()) { - // As of right now, no tag can be added asynchronously - worldManager.getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false); + if (worldManager.shouldExpectLecternHandled(session)) { + worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); } else if ((newLecternHasBook = this.value[offset]) != this.get(worldManager.getBlockAt(session, position))) { - // If the lectern block was updated, or it previously had a book - NbtMap newLecternTag; // newLecternHasBook = the new lectern block state's "has book" toggle. if (newLecternHasBook) { - newLecternTag = worldManager.getLecternDataAt(session, position.getX(), position.getY(), position.getZ(), false); + worldManager.sendLecternData(session, position.getX(), position.getY(), position.getZ()); } else { session.getLecternCache().remove(position); - newLecternTag = LecternInventoryTranslator.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); + NbtMap newLecternTag = LecternUtils.getBaseLecternTag(position.getX(), position.getY(), position.getZ(), 0).build(); + BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); } - BlockEntityUtils.updateBlockEntity(session, newLecternTag, position); } } } diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/Object2IntBiMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/Object2IntBiMap.java index ceb2333bd..01f7012f8 100644 --- a/core/src/main/java/org/geysermc/geyser/util/collection/Object2IntBiMap.java +++ b/core/src/main/java/org/geysermc/geyser/util/collection/Object2IntBiMap.java @@ -40,7 +40,7 @@ import java.util.Objects; /** * A primitive int BiMap implementation built around fastutil to * reduce boxing and the memory footprint. Protocol has a - * {@link com.nukkitx.protocol.util.Int2ObjectBiMap} class, but it + * {@link org.cloudburstmc.protocol.common.util.Int2ObjectBiMap} class, but it * does not extend the Map interface making it difficult to utilize * it in for loops and the registry system. * diff --git a/core/src/main/resources/bedrock/block_palette.1_19_70.nbt b/core/src/main/resources/bedrock/block_palette.1_19_70.nbt new file mode 100644 index 000000000..3e78f3929 Binary files /dev/null and b/core/src/main/resources/bedrock/block_palette.1_19_70.nbt differ diff --git a/core/src/main/resources/bedrock/creative_items.1_19_70.json b/core/src/main/resources/bedrock/creative_items.1_19_70.json new file mode 100644 index 000000000..e47467f23 --- /dev/null +++ b/core/src/main/resources/bedrock/creative_items.1_19_70.json @@ -0,0 +1,5452 @@ +{ + "items" : [ + { + "id" : "minecraft:planks", + "blockRuntimeId" : 9885 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 9886 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 9887 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 9888 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 9889 + }, + { + "id" : "minecraft:planks", + "blockRuntimeId" : 9890 + }, + { + "id" : "minecraft:mangrove_planks", + "blockRuntimeId" : 1639 + }, + { + "id" : "minecraft:crimson_planks", + "blockRuntimeId" : 7466 + }, + { + "id" : "minecraft:warped_planks", + "blockRuntimeId" : 1612 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1883 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1884 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1885 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1886 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1887 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1888 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1895 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1890 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1891 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1889 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1892 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1896 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1893 + }, + { + "id" : "minecraft:cobblestone_wall", + "blockRuntimeId" : 1894 + }, + { + "id" : "minecraft:blackstone_wall", + "blockRuntimeId" : 5774 + }, + { + "id" : "minecraft:polished_blackstone_wall", + "blockRuntimeId" : 10580 + }, + { + "id" : "minecraft:polished_blackstone_brick_wall", + "blockRuntimeId" : 1664 + }, + { + "id" : "minecraft:cobbled_deepslate_wall", + "blockRuntimeId" : 12346 + }, + { + "id" : "minecraft:deepslate_tile_wall", + "blockRuntimeId" : 7703 + }, + { + "id" : "minecraft:polished_deepslate_wall", + "blockRuntimeId" : 12080 + }, + { + "id" : "minecraft:deepslate_brick_wall", + "blockRuntimeId" : 727 + }, + { + "id" : "minecraft:mud_brick_wall", + "blockRuntimeId" : 1422 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 11627 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 11628 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 11629 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 11630 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 11631 + }, + { + "id" : "minecraft:fence", + "blockRuntimeId" : 11632 + }, + { + "id" : "minecraft:mangrove_fence", + "blockRuntimeId" : 10485 + }, + { + "id" : "minecraft:nether_brick_fence", + "blockRuntimeId" : 6138 + }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 12259 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 8889 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 79 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 10436 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 5237 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 8014 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 11849 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 6017 + }, + { + "id" : "minecraft:mangrove_fence_gate", + "blockRuntimeId" : 6473 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 6893 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 8049 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 932 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 5166 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 5936 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 280 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 132 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 10865 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 10829 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 10030 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 7695 + }, + { + "id" : "minecraft:mangrove_stairs", + "blockRuntimeId" : 6443 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 1623 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 9303 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 5042 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 5085 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 7999 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 8197 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 4608 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 5994 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 6239 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 10566 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 7956 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 10890 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 10382 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 109 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 10454 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 10220 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 6999 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 11963 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 12018 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 11526 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 11693 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 211 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 10118 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 5176 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 10881 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 6145 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 6325 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 6452 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 6435 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 6153 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 648 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 691 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 5746 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 9997 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 8876 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 152 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 6885 + }, + { + "id" : "minecraft:polished_deepslate_stairs", + "blockRuntimeId" : 589 + }, + { + "id" : "minecraft:deepslate_brick_stairs", + "blockRuntimeId" : 11685 + }, + { + "id" : "minecraft:mud_brick_stairs", + "blockRuntimeId" : 8173 + }, + { + "id" : "minecraft:wooden_door" + }, + { + "id" : "minecraft:spruce_door" + }, + { + "id" : "minecraft:birch_door" + }, + { + "id" : "minecraft:jungle_door" + }, + { + "id" : "minecraft:acacia_door" + }, + { + "id" : "minecraft:dark_oak_door" + }, + { + "id" : "minecraft:mangrove_door" + }, + { + "id" : "minecraft:iron_door" + }, + { + "id" : "minecraft:crimson_door" + }, + { + "id" : "minecraft:warped_door" + }, + { + "id" : "minecraft:trapdoor", + "blockRuntimeId" : 235 + }, + { + "id" : "minecraft:spruce_trapdoor", + "blockRuntimeId" : 10404 + }, + { + "id" : "minecraft:birch_trapdoor", + "blockRuntimeId" : 10502 + }, + { + "id" : "minecraft:jungle_trapdoor", + "blockRuntimeId" : 8030 + }, + { + "id" : "minecraft:acacia_trapdoor", + "blockRuntimeId" : 8240 + }, + { + "id" : "minecraft:dark_oak_trapdoor", + "blockRuntimeId" : 11765 + }, + { + "id" : "minecraft:mangrove_trapdoor", + "blockRuntimeId" : 6333 + }, + { + "id" : "minecraft:iron_trapdoor", + "blockRuntimeId" : 616 + }, + { + "id" : "minecraft:crimson_trapdoor", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:warped_trapdoor", + "blockRuntimeId" : 6965 + }, + { + "id" : "minecraft:iron_bars", + "blockRuntimeId" : 7033 + }, + { + "id" : "minecraft:glass", + "blockRuntimeId" : 9994 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1826 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1834 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1833 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1841 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1838 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1840 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1827 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1830 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1831 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1839 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1835 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1829 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1837 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1836 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1828 + }, + { + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1832 + }, + { + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 9395 + }, + { + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 7865 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7468 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7476 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7475 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7483 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7480 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7482 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7469 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7472 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7473 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7481 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7477 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7471 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7479 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7478 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7470 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 7474 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 12528 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 5026 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6116 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 8474 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6119 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8445 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7918 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7919 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7920 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7921 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7922 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 7923 + }, + { + "id" : "minecraft:mangrove_slab", + "blockRuntimeId" : 1842 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6121 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 8472 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6117 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 8475 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8446 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8440 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 8476 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8457 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8462 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8463 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8460 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8461 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8459 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8458 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6120 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6123 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8447 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 8456 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 6122 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 8473 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8441 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8442 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8443 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 8444 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 9320 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 10334 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 1602 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 9823 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 6038 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 7867 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 10452 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 9866 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 7930 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 12078 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 255 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", + "blockRuntimeId" : 10397 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 1392 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 11573 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 295 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 6139 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 5174 + }, + { + "id" : "minecraft:mud_brick_slab", + "blockRuntimeId" : 5754 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 6997 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 11512 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 6400 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 10189 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 10399 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 10400 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 10401 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 10402 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 288 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 9917 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 6912 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 11461 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 6434 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 7694 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 6429 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 6004 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 8114 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 8013 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 7866 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 5073 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 258 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 10522 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 6430 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 5111 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 5112 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 5113 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 5114 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 10432 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 10433 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 10434 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 10435 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 8047 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 12242 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 330 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 12527 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 6883 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 891 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 12510 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 5008 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 11997 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 1378 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 1391 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 11805 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 6921 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 9996 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 11444 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 8128 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 11556 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 5269 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 7467 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 219 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 1852 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 279 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 6132 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 12525 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 7917 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 658 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 5154 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 5156 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 5155 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 5157 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 9915 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 9916 + }, + { + "id" : "minecraft:slime", + "blockRuntimeId" : 6079 + }, + { + "id" : "minecraft:honey_block", + "blockRuntimeId" : 1584 + }, + { + "id" : "minecraft:honeycomb_block", + "blockRuntimeId" : 6324 + }, + { + "id" : "minecraft:hay_block", + "blockRuntimeId" : 1379 + }, + { + "id" : "minecraft:bone_block", + "blockRuntimeId" : 6080 + }, + { + "id" : "minecraft:nether_brick", + "blockRuntimeId" : 11535 + }, + { + "id" : "minecraft:red_nether_brick", + "blockRuntimeId" : 151 + }, + { + "id" : "minecraft:netherite_block", + "blockRuntimeId" : 5234 + }, + { + "id" : "minecraft:lodestone", + "blockRuntimeId" : 12523 + }, + { + "id" : "minecraft:white_wool", + "blockRuntimeId" : 8048 + }, + { + "id" : "minecraft:light_gray_wool", + "blockRuntimeId" : 12318 + }, + { + "id" : "minecraft:gray_wool", + "blockRuntimeId" : 228 + }, + { + "id" : "minecraft:black_wool", + "blockRuntimeId" : 659 + }, + { + "id" : "minecraft:brown_wool", + "blockRuntimeId" : 262 + }, + { + "id" : "minecraft:red_wool", + "blockRuntimeId" : 119 + }, + { + "id" : "minecraft:orange_wool", + "blockRuntimeId" : 1360 + }, + { + "id" : "minecraft:yellow_wool", + "blockRuntimeId" : 142 + }, + { + "id" : "minecraft:lime_wool", + "blockRuntimeId" : 9812 + }, + { + "id" : "minecraft:green_wool", + "blockRuntimeId" : 5185 + }, + { + "id" : "minecraft:cyan_wool", + "blockRuntimeId" : 7992 + }, + { + "id" : "minecraft:light_blue_wool", + "blockRuntimeId" : 10944 + }, + { + "id" : "minecraft:blue_wool", + "blockRuntimeId" : 8129 + }, + { + "id" : "minecraft:purple_wool", + "blockRuntimeId" : 12526 + }, + { + "id" : "minecraft:magenta_wool", + "blockRuntimeId" : 1657 + }, + { + "id" : "minecraft:pink_wool", + "blockRuntimeId" : 5235 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1641 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1649 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1648 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1656 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1653 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1655 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1642 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1645 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1646 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1654 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1650 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1644 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1652 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1651 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1643 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 1647 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10102 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10110 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10109 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10117 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10114 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10116 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10103 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10106 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10107 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10115 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10111 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10105 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10113 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10112 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10104 + }, + { + "id" : "minecraft:concrete_powder", + "blockRuntimeId" : 10108 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1343 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1351 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1350 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1358 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1355 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1357 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1344 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1347 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1348 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1356 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1352 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1346 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1354 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1353 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1345 + }, + { + "id" : "minecraft:concrete", + "blockRuntimeId" : 1349 + }, + { + "id" : "minecraft:clay", + "blockRuntimeId" : 10987 + }, + { + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 940 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10006 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10014 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10013 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10021 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10018 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10020 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10007 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10010 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10011 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10019 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10015 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10009 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10017 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10016 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10008 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 10012 + }, + { + "id" : "minecraft:white_glazed_terracotta", + "blockRuntimeId" : 8224 + }, + { + "id" : "minecraft:silver_glazed_terracotta", + "blockRuntimeId" : 4602 + }, + { + "id" : "minecraft:gray_glazed_terracotta", + "blockRuntimeId" : 12517 + }, + { + "id" : "minecraft:black_glazed_terracotta", + "blockRuntimeId" : 8870 + }, + { + "id" : "minecraft:brown_glazed_terracotta", + "blockRuntimeId" : 5002 + }, + { + "id" : "minecraft:red_glazed_terracotta", + "blockRuntimeId" : 6011 + }, + { + "id" : "minecraft:orange_glazed_terracotta", + "blockRuntimeId" : 1844 + }, + { + "id" : "minecraft:yellow_glazed_terracotta", + "blockRuntimeId" : 1605 + }, + { + "id" : "minecraft:lime_glazed_terracotta", + "blockRuntimeId" : 229 + }, + { + "id" : "minecraft:green_glazed_terracotta", + "blockRuntimeId" : 10462 + }, + { + "id" : "minecraft:cyan_glazed_terracotta", + "blockRuntimeId" : 8007 + }, + { + "id" : "minecraft:light_blue_glazed_terracotta", + "blockRuntimeId" : 8121 + }, + { + "id" : "minecraft:blue_glazed_terracotta", + "blockRuntimeId" : 8115 + }, + { + "id" : "minecraft:purple_glazed_terracotta", + "blockRuntimeId" : 10873 + }, + { + "id" : "minecraft:magenta_glazed_terracotta", + "blockRuntimeId" : 1658 + }, + { + "id" : "minecraft:pink_glazed_terracotta", + "blockRuntimeId" : 10391 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 11977 + }, + { + "id" : "minecraft:purpur_block", + "blockRuntimeId" : 11979 + }, + { + "id" : "minecraft:packed_mud", + "blockRuntimeId" : 290 + }, + { + "id" : "minecraft:mud_bricks", + "blockRuntimeId" : 10745 + }, + { + "id" : "minecraft:nether_wart_block", + "blockRuntimeId" : 6141 + }, + { + "id" : "minecraft:warped_wart_block", + "blockRuntimeId" : 9325 + }, + { + "id" : "minecraft:shroomlight", + "blockRuntimeId" : 7677 + }, + { + "id" : "minecraft:crimson_nylium", + "blockRuntimeId" : 6035 + }, + { + "id" : "minecraft:warped_nylium", + "blockRuntimeId" : 10187 + }, + { + "id" : "minecraft:basalt", + "blockRuntimeId" : 6197 + }, + { + "id" : "minecraft:polished_basalt", + "blockRuntimeId" : 24 + }, + { + "id" : "minecraft:smooth_basalt", + "blockRuntimeId" : 1850 + }, + { + "id" : "minecraft:soul_soil", + "blockRuntimeId" : 8482 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 8403 + }, + { + "id" : "minecraft:dirt", + "blockRuntimeId" : 8404 + }, + { + "id" : "minecraft:farmland", + "blockRuntimeId" : 5756 + }, + { + "id" : "minecraft:grass", + "blockRuntimeId" : 10837 + }, + { + "id" : "minecraft:grass_path", + "blockRuntimeId" : 12345 + }, + { + "id" : "minecraft:podzol", + "blockRuntimeId" : 6882 + }, + { + "id" : "minecraft:mycelium", + "blockRuntimeId" : 5141 + }, + { + "id" : "minecraft:mud", + "blockRuntimeId" : 10536 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1336 + }, + { + "id" : "minecraft:iron_ore", + "blockRuntimeId" : 6922 + }, + { + "id" : "minecraft:gold_ore", + "blockRuntimeId" : 1604 + }, + { + "id" : "minecraft:diamond_ore", + "blockRuntimeId" : 6209 + }, + { + "id" : "minecraft:lapis_ore", + "blockRuntimeId" : 11962 + }, + { + "id" : "minecraft:redstone_ore", + "blockRuntimeId" : 6135 + }, + { + "id" : "minecraft:coal_ore", + "blockRuntimeId" : 6133 + }, + { + "id" : "minecraft:copper_ore", + "blockRuntimeId" : 5009 + }, + { + "id" : "minecraft:emerald_ore", + "blockRuntimeId" : 11610 + }, + { + "id" : "minecraft:quartz_ore", + "blockRuntimeId" : 6349 + }, + { + "id" : "minecraft:nether_gold_ore", + "blockRuntimeId" : 27 + }, + { + "id" : "minecraft:ancient_debris", + "blockRuntimeId" : 9937 + }, + { + "id" : "minecraft:deepslate_iron_ore", + "blockRuntimeId" : 11536 + }, + { + "id" : "minecraft:deepslate_gold_ore", + "blockRuntimeId" : 9936 + }, + { + "id" : "minecraft:deepslate_diamond_ore", + "blockRuntimeId" : 12301 + }, + { + "id" : "minecraft:deepslate_lapis_ore", + "blockRuntimeId" : 11525 + }, + { + "id" : "minecraft:deepslate_redstone_ore", + "blockRuntimeId" : 10468 + }, + { + "id" : "minecraft:deepslate_emerald_ore", + "blockRuntimeId" : 10188 + }, + { + "id" : "minecraft:deepslate_coal_ore", + "blockRuntimeId" : 11443 + }, + { + "id" : "minecraft:deepslate_copper_ore", + "blockRuntimeId" : 108 + }, + { + "id" : "minecraft:gravel", + "blockRuntimeId" : 12553 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1337 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1339 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1341 + }, + { + "id" : "minecraft:blackstone", + "blockRuntimeId" : 11848 + }, + { + "id" : "minecraft:deepslate", + "blockRuntimeId" : 259 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1338 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1340 + }, + { + "id" : "minecraft:stone", + "blockRuntimeId" : 1342 + }, + { + "id" : "minecraft:polished_blackstone", + "blockRuntimeId" : 5140 + }, + { + "id" : "minecraft:polished_deepslate", + "blockRuntimeId" : 12017 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 6041 + }, + { + "id" : "minecraft:sand", + "blockRuntimeId" : 6042 + }, + { + "id" : "minecraft:cactus", + "blockRuntimeId" : 10848 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 10524 + }, + { + "id" : "minecraft:stripped_oak_log", + "blockRuntimeId" : 11806 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 10525 + }, + { + "id" : "minecraft:stripped_spruce_log", + "blockRuntimeId" : 10126 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 10526 + }, + { + "id" : "minecraft:stripped_birch_log", + "blockRuntimeId" : 9392 + }, + { + "id" : "minecraft:log", + "blockRuntimeId" : 10527 + }, + { + "id" : "minecraft:stripped_jungle_log", + "blockRuntimeId" : 1325 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 5674 + }, + { + "id" : "minecraft:stripped_acacia_log", + "blockRuntimeId" : 8884 + }, + { + "id" : "minecraft:log2", + "blockRuntimeId" : 5675 + }, + { + "id" : "minecraft:stripped_dark_oak_log", + "blockRuntimeId" : 221 + }, + { + "id" : "minecraft:mangrove_log", + "blockRuntimeId" : 645 + }, + { + "id" : "minecraft:stripped_mangrove_log", + "blockRuntimeId" : 12550 + }, + { + "id" : "minecraft:crimson_stem", + "blockRuntimeId" : 9317 + }, + { + "id" : "minecraft:stripped_crimson_stem", + "blockRuntimeId" : 10810 + }, + { + "id" : "minecraft:warped_stem", + "blockRuntimeId" : 10336 + }, + { + "id" : "minecraft:stripped_warped_stem", + "blockRuntimeId" : 11663 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4161 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4167 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4162 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4168 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4163 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4169 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4164 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4170 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4165 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4171 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4166 + }, + { + "id" : "minecraft:wood", + "blockRuntimeId" : 4172 + }, + { + "id" : "minecraft:mangrove_wood", + "blockRuntimeId" : 6005 + }, + { + "id" : "minecraft:stripped_mangrove_wood", + "blockRuntimeId" : 6075 + }, + { + "id" : "minecraft:crimson_hyphae", + "blockRuntimeId" : 6142 + }, + { + "id" : "minecraft:stripped_crimson_hyphae", + "blockRuntimeId" : 10349 + }, + { + "id" : "minecraft:warped_hyphae", + "blockRuntimeId" : 9322 + }, + { + "id" : "minecraft:stripped_warped_hyphae", + "blockRuntimeId" : 8230 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 9920 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 9921 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 9922 + }, + { + "id" : "minecraft:leaves", + "blockRuntimeId" : 9923 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 6201 + }, + { + "id" : "minecraft:leaves2", + "blockRuntimeId" : 6202 + }, + { + "id" : "minecraft:mangrove_leaves", + "blockRuntimeId" : 10518 + }, + { + "id" : "minecraft:azalea_leaves", + "blockRuntimeId" : 11973 + }, + { + "id" : "minecraft:azalea_leaves_flowered", + "blockRuntimeId" : 10177 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 1396 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 1397 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 1398 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 1399 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 1400 + }, + { + "id" : "minecraft:sapling", + "blockRuntimeId" : 1401 + }, + { + "id" : "minecraft:mangrove_propagule", + "blockRuntimeId" : 10838 + }, + { + "id" : "minecraft:bee_nest", + "blockRuntimeId" : 8406 + }, + { + "id" : "minecraft:wheat_seeds" + }, + { + "id" : "minecraft:pumpkin_seeds" + }, + { + "id" : "minecraft:melon_seeds" + }, + { + "id" : "minecraft:beetroot_seeds" + }, + { + "id" : "minecraft:wheat" + }, + { + "id" : "minecraft:beetroot" + }, + { + "id" : "minecraft:potato" + }, + { + "id" : "minecraft:poisonous_potato" + }, + { + "id" : "minecraft:carrot" + }, + { + "id" : "minecraft:golden_carrot" + }, + { + "id" : "minecraft:apple" + }, + { + "id" : "minecraft:golden_apple" + }, + { + "id" : "minecraft:enchanted_golden_apple" + }, + { + "id" : "minecraft:melon_block", + "blockRuntimeId" : 690 + }, + { + "id" : "minecraft:melon_slice" + }, + { + "id" : "minecraft:glistering_melon_slice" + }, + { + "id" : "minecraft:sweet_berries" + }, + { + "id" : "minecraft:glow_berries" + }, + { + "id" : "minecraft:pumpkin", + "blockRuntimeId" : 6425 + }, + { + "id" : "minecraft:carved_pumpkin", + "blockRuntimeId" : 11641 + }, + { + "id" : "minecraft:lit_pumpkin", + "blockRuntimeId" : 10537 + }, + { + "id" : "minecraft:honeycomb" + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 1621 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 8105 + }, + { + "id" : "minecraft:tallgrass", + "blockRuntimeId" : 1620 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 8104 + }, + { + "id" : "minecraft:nether_sprouts" + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10342 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10340 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10341 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10339 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10343 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10347 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10345 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10346 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10344 + }, + { + "id" : "minecraft:coral", + "blockRuntimeId" : 10348 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 6464 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 6462 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 6463 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 6461 + }, + { + "id" : "minecraft:coral_fan", + "blockRuntimeId" : 6465 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 72 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 70 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 71 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 69 + }, + { + "id" : "minecraft:coral_fan_dead", + "blockRuntimeId" : 73 + }, + { + "id" : "minecraft:crimson_roots", + "blockRuntimeId" : 11836 + }, + { + "id" : "minecraft:warped_roots", + "blockRuntimeId" : 6210 + }, + { + "id" : "minecraft:yellow_flower", + "blockRuntimeId" : 597 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5074 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5075 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5076 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5077 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5078 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5079 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5080 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5081 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5082 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5083 + }, + { + "id" : "minecraft:red_flower", + "blockRuntimeId" : 5084 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 8102 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 8103 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 8106 + }, + { + "id" : "minecraft:double_plant", + "blockRuntimeId" : 8107 + }, + { + "id" : "minecraft:wither_rose", + "blockRuntimeId" : 9995 + }, + { + "id" : "minecraft:white_dye" + }, + { + "id" : "minecraft:light_gray_dye" + }, + { + "id" : "minecraft:gray_dye" + }, + { + "id" : "minecraft:black_dye" + }, + { + "id" : "minecraft:brown_dye" + }, + { + "id" : "minecraft:red_dye" + }, + { + "id" : "minecraft:orange_dye" + }, + { + "id" : "minecraft:yellow_dye" + }, + { + "id" : "minecraft:lime_dye" + }, + { + "id" : "minecraft:green_dye" + }, + { + "id" : "minecraft:cyan_dye" + }, + { + "id" : "minecraft:light_blue_dye" + }, + { + "id" : "minecraft:blue_dye" + }, + { + "id" : "minecraft:purple_dye" + }, + { + "id" : "minecraft:magenta_dye" + }, + { + "id" : "minecraft:pink_dye" + }, + { + "id" : "minecraft:ink_sac" + }, + { + "id" : "minecraft:glow_ink_sac" + }, + { + "id" : "minecraft:cocoa_beans" + }, + { + "id" : "minecraft:lapis_lazuli" + }, + { + "id" : "minecraft:bone_meal" + }, + { + "id" : "minecraft:vine", + "blockRuntimeId" : 1586 + }, + { + "id" : "minecraft:weeping_vines", + "blockRuntimeId" : 8130 + }, + { + "id" : "minecraft:twisting_vines", + "blockRuntimeId" : 8343 + }, + { + "id" : "minecraft:waterlily", + "blockRuntimeId" : 1851 + }, + { + "id" : "minecraft:seagrass", + "blockRuntimeId" : 252 + }, + { + "id" : "minecraft:kelp" + }, + { + "id" : "minecraft:deadbush", + "blockRuntimeId" : 6909 + }, + { + "id" : "minecraft:bamboo", + "blockRuntimeId" : 5142 + }, + { + "id" : "minecraft:snow", + "blockRuntimeId" : 6040 + }, + { + "id" : "minecraft:ice", + "blockRuntimeId" : 10541 + }, + { + "id" : "minecraft:packed_ice", + "blockRuntimeId" : 289 + }, + { + "id" : "minecraft:blue_ice", + "blockRuntimeId" : 10889 + }, + { + "id" : "minecraft:snow_layer", + "blockRuntimeId" : 160 + }, + { + "id" : "minecraft:pointed_dripstone", + "blockRuntimeId" : 11679 + }, + { + "id" : "minecraft:dripstone_block", + "blockRuntimeId" : 1585 + }, + { + "id" : "minecraft:moss_carpet", + "blockRuntimeId" : 293 + }, + { + "id" : "minecraft:moss_block", + "blockRuntimeId" : 10390 + }, + { + "id" : "minecraft:dirt_with_roots", + "blockRuntimeId" : 8046 + }, + { + "id" : "minecraft:hanging_roots", + "blockRuntimeId" : 210 + }, + { + "id" : "minecraft:mangrove_roots", + "blockRuntimeId" : 10005 + }, + { + "id" : "minecraft:muddy_mangrove_roots", + "blockRuntimeId" : 640 + }, + { + "id" : "minecraft:big_dripleaf", + "blockRuntimeId" : 9400 + }, + { + "id" : "minecraft:small_dripleaf_block", + "blockRuntimeId" : 6168 + }, + { + "id" : "minecraft:spore_blossom", + "blockRuntimeId" : 11575 + }, + { + "id" : "minecraft:azalea", + "blockRuntimeId" : 10744 + }, + { + "id" : "minecraft:flowering_azalea", + "blockRuntimeId" : 8127 + }, + { + "id" : "minecraft:glow_lichen", + "blockRuntimeId" : 8336 + }, + { + "id" : "minecraft:amethyst_block", + "blockRuntimeId" : 329 + }, + { + "id" : "minecraft:budding_amethyst", + "blockRuntimeId" : 10864 + }, + { + "id" : "minecraft:amethyst_cluster", + "blockRuntimeId" : 12073 + }, + { + "id" : "minecraft:large_amethyst_bud", + "blockRuntimeId" : 6960 + }, + { + "id" : "minecraft:medium_amethyst_bud", + "blockRuntimeId" : 6224 + }, + { + "id" : "minecraft:small_amethyst_bud", + "blockRuntimeId" : 599 + }, + { + "id" : "minecraft:tuff", + "blockRuntimeId" : 644 + }, + { + "id" : "minecraft:calcite", + "blockRuntimeId" : 220 + }, + { + "id" : "minecraft:chicken" + }, + { + "id" : "minecraft:porkchop" + }, + { + "id" : "minecraft:beef" + }, + { + "id" : "minecraft:mutton" + }, + { + "id" : "minecraft:rabbit" + }, + { + "id" : "minecraft:cod" + }, + { + "id" : "minecraft:salmon" + }, + { + "id" : "minecraft:tropical_fish" + }, + { + "id" : "minecraft:pufferfish" + }, + { + "id" : "minecraft:brown_mushroom", + "blockRuntimeId" : 5001 + }, + { + "id" : "minecraft:red_mushroom", + "blockRuntimeId" : 6433 + }, + { + "id" : "minecraft:crimson_fungus", + "blockRuntimeId" : 12016 + }, + { + "id" : "minecraft:warped_fungus", + "blockRuntimeId" : 294 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 11625 + }, + { + "id" : "minecraft:red_mushroom_block", + "blockRuntimeId" : 5069 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 11626 + }, + { + "id" : "minecraft:brown_mushroom_block", + "blockRuntimeId" : 11611 + }, + { + "id" : "minecraft:egg" + }, + { + "id" : "minecraft:sugar_cane" + }, + { + "id" : "minecraft:sugar" + }, + { + "id" : "minecraft:rotten_flesh" + }, + { + "id" : "minecraft:bone" + }, + { + "id" : "minecraft:web", + "blockRuntimeId" : 10565 + }, + { + "id" : "minecraft:spider_eye" + }, + { + "id" : "minecraft:mob_spawner", + "blockRuntimeId" : 699 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5988 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5989 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5990 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5991 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5992 + }, + { + "id" : "minecraft:monster_egg", + "blockRuntimeId" : 5993 + }, + { + "id" : "minecraft:infested_deepslate", + "blockRuntimeId" : 6873 + }, + { + "id" : "minecraft:dragon_egg", + "blockRuntimeId" : 11534 + }, + { + "id" : "minecraft:turtle_egg", + "blockRuntimeId" : 12260 + }, + { + "id" : "minecraft:frog_spawn", + "blockRuntimeId" : 6247 + }, + { + "id" : "minecraft:pearlescent_froglight", + "blockRuntimeId" : 10273 + }, + { + "id" : "minecraft:verdant_froglight", + "blockRuntimeId" : 10331 + }, + { + "id" : "minecraft:ochre_froglight", + "blockRuntimeId" : 4581 + }, + { + "id" : "minecraft:chicken_spawn_egg" + }, + { + "id" : "minecraft:bee_spawn_egg" + }, + { + "id" : "minecraft:cow_spawn_egg" + }, + { + "id" : "minecraft:pig_spawn_egg" + }, + { + "id" : "minecraft:sheep_spawn_egg" + }, + { + "id" : "minecraft:wolf_spawn_egg" + }, + { + "id" : "minecraft:polar_bear_spawn_egg" + }, + { + "id" : "minecraft:ocelot_spawn_egg" + }, + { + "id" : "minecraft:cat_spawn_egg" + }, + { + "id" : "minecraft:mooshroom_spawn_egg" + }, + { + "id" : "minecraft:bat_spawn_egg" + }, + { + "id" : "minecraft:parrot_spawn_egg" + }, + { + "id" : "minecraft:rabbit_spawn_egg" + }, + { + "id" : "minecraft:llama_spawn_egg" + }, + { + "id" : "minecraft:horse_spawn_egg" + }, + { + "id" : "minecraft:donkey_spawn_egg" + }, + { + "id" : "minecraft:mule_spawn_egg" + }, + { + "id" : "minecraft:skeleton_horse_spawn_egg" + }, + { + "id" : "minecraft:zombie_horse_spawn_egg" + }, + { + "id" : "minecraft:tropical_fish_spawn_egg" + }, + { + "id" : "minecraft:cod_spawn_egg" + }, + { + "id" : "minecraft:pufferfish_spawn_egg" + }, + { + "id" : "minecraft:salmon_spawn_egg" + }, + { + "id" : "minecraft:dolphin_spawn_egg" + }, + { + "id" : "minecraft:turtle_spawn_egg" + }, + { + "id" : "minecraft:panda_spawn_egg" + }, + { + "id" : "minecraft:fox_spawn_egg" + }, + { + "id" : "minecraft:creeper_spawn_egg" + }, + { + "id" : "minecraft:enderman_spawn_egg" + }, + { + "id" : "minecraft:silverfish_spawn_egg" + }, + { + "id" : "minecraft:skeleton_spawn_egg" + }, + { + "id" : "minecraft:wither_skeleton_spawn_egg" + }, + { + "id" : "minecraft:stray_spawn_egg" + }, + { + "id" : "minecraft:slime_spawn_egg" + }, + { + "id" : "minecraft:spider_spawn_egg" + }, + { + "id" : "minecraft:zombie_spawn_egg" + }, + { + "id" : "minecraft:zombie_pigman_spawn_egg" + }, + { + "id" : "minecraft:husk_spawn_egg" + }, + { + "id" : "minecraft:drowned_spawn_egg" + }, + { + "id" : "minecraft:squid_spawn_egg" + }, + { + "id" : "minecraft:glow_squid_spawn_egg" + }, + { + "id" : "minecraft:cave_spider_spawn_egg" + }, + { + "id" : "minecraft:witch_spawn_egg" + }, + { + "id" : "minecraft:guardian_spawn_egg" + }, + { + "id" : "minecraft:elder_guardian_spawn_egg" + }, + { + "id" : "minecraft:endermite_spawn_egg" + }, + { + "id" : "minecraft:magma_cube_spawn_egg" + }, + { + "id" : "minecraft:strider_spawn_egg" + }, + { + "id" : "minecraft:hoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_spawn_egg" + }, + { + "id" : "minecraft:zoglin_spawn_egg" + }, + { + "id" : "minecraft:piglin_brute_spawn_egg" + }, + { + "id" : "minecraft:goat_spawn_egg" + }, + { + "id" : "minecraft:axolotl_spawn_egg" + }, + { + "id" : "minecraft:warden_spawn_egg" + }, + { + "id" : "minecraft:allay_spawn_egg" + }, + { + "id" : "minecraft:frog_spawn_egg" + }, + { + "id" : "minecraft:tadpole_spawn_egg" + }, + { + "id" : "minecraft:trader_llama_spawn_egg" + }, + { + "id" : "minecraft:ghast_spawn_egg" + }, + { + "id" : "minecraft:blaze_spawn_egg" + }, + { + "id" : "minecraft:shulker_spawn_egg" + }, + { + "id" : "minecraft:vindicator_spawn_egg" + }, + { + "id" : "minecraft:evoker_spawn_egg" + }, + { + "id" : "minecraft:vex_spawn_egg" + }, + { + "id" : "minecraft:villager_spawn_egg" + }, + { + "id" : "minecraft:wandering_trader_spawn_egg" + }, + { + "id" : "minecraft:zombie_villager_spawn_egg" + }, + { + "id" : "minecraft:phantom_spawn_egg" + }, + { + "id" : "minecraft:pillager_spawn_egg" + }, + { + "id" : "minecraft:ravager_spawn_egg" + }, + { + "id" : "minecraft:iron_golem_spawn_egg" + }, + { + "id" : "minecraft:snow_golem_spawn_egg" + }, + { + "id" : "minecraft:obsidian", + "blockRuntimeId" : 726 + }, + { + "id" : "minecraft:crying_obsidian", + "blockRuntimeId" : 10574 + }, + { + "id" : "minecraft:bedrock", + "blockRuntimeId" : 10879 + }, + { + "id" : "minecraft:soul_sand", + "blockRuntimeId" : 8483 + }, + { + "id" : "minecraft:netherrack", + "blockRuntimeId" : 10899 + }, + { + "id" : "minecraft:magma", + "blockRuntimeId" : 12272 + }, + { + "id" : "minecraft:nether_wart" + }, + { + "id" : "minecraft:end_stone", + "blockRuntimeId" : 5680 + }, + { + "id" : "minecraft:chorus_flower", + "blockRuntimeId" : 6378 + }, + { + "id" : "minecraft:chorus_plant", + "blockRuntimeId" : 8156 + }, + { + "id" : "minecraft:chorus_fruit" + }, + { + "id" : "minecraft:popped_chorus_fruit" + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 927 + }, + { + "id" : "minecraft:sponge", + "blockRuntimeId" : 928 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7869 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7870 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7871 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7872 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7873 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7874 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7875 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7876 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7877 + }, + { + "id" : "minecraft:coral_block", + "blockRuntimeId" : 7878 + }, + { + "id" : "minecraft:sculk", + "blockRuntimeId" : 10898 + }, + { + "id" : "minecraft:sculk_vein", + "blockRuntimeId" : 11379 + }, + { + "id" : "minecraft:sculk_catalyst", + "blockRuntimeId" : 5071 + }, + { + "id" : "minecraft:sculk_shrieker", + "blockRuntimeId" : 224 + }, + { + "id" : "minecraft:sculk_sensor", + "blockRuntimeId" : 6237 + }, + { + "id" : "minecraft:reinforced_deepslate", + "blockRuntimeId" : 8868 + }, + { + "id" : "minecraft:leather_helmet" + }, + { + "id" : "minecraft:chainmail_helmet" + }, + { + "id" : "minecraft:iron_helmet" + }, + { + "id" : "minecraft:golden_helmet" + }, + { + "id" : "minecraft:diamond_helmet" + }, + { + "id" : "minecraft:netherite_helmet" + }, + { + "id" : "minecraft:leather_chestplate" + }, + { + "id" : "minecraft:chainmail_chestplate" + }, + { + "id" : "minecraft:iron_chestplate" + }, + { + "id" : "minecraft:golden_chestplate" + }, + { + "id" : "minecraft:diamond_chestplate" + }, + { + "id" : "minecraft:netherite_chestplate" + }, + { + "id" : "minecraft:leather_leggings" + }, + { + "id" : "minecraft:chainmail_leggings" + }, + { + "id" : "minecraft:iron_leggings" + }, + { + "id" : "minecraft:golden_leggings" + }, + { + "id" : "minecraft:diamond_leggings" + }, + { + "id" : "minecraft:netherite_leggings" + }, + { + "id" : "minecraft:leather_boots" + }, + { + "id" : "minecraft:chainmail_boots" + }, + { + "id" : "minecraft:iron_boots" + }, + { + "id" : "minecraft:golden_boots" + }, + { + "id" : "minecraft:diamond_boots" + }, + { + "id" : "minecraft:netherite_boots" + }, + { + "id" : "minecraft:wooden_sword" + }, + { + "id" : "minecraft:stone_sword" + }, + { + "id" : "minecraft:iron_sword" + }, + { + "id" : "minecraft:golden_sword" + }, + { + "id" : "minecraft:diamond_sword" + }, + { + "id" : "minecraft:netherite_sword" + }, + { + "id" : "minecraft:wooden_axe" + }, + { + "id" : "minecraft:stone_axe" + }, + { + "id" : "minecraft:iron_axe" + }, + { + "id" : "minecraft:golden_axe" + }, + { + "id" : "minecraft:diamond_axe" + }, + { + "id" : "minecraft:netherite_axe" + }, + { + "id" : "minecraft:wooden_pickaxe" + }, + { + "id" : "minecraft:stone_pickaxe" + }, + { + "id" : "minecraft:iron_pickaxe" + }, + { + "id" : "minecraft:golden_pickaxe" + }, + { + "id" : "minecraft:diamond_pickaxe" + }, + { + "id" : "minecraft:netherite_pickaxe" + }, + { + "id" : "minecraft:wooden_shovel" + }, + { + "id" : "minecraft:stone_shovel" + }, + { + "id" : "minecraft:iron_shovel" + }, + { + "id" : "minecraft:golden_shovel" + }, + { + "id" : "minecraft:diamond_shovel" + }, + { + "id" : "minecraft:netherite_shovel" + }, + { + "id" : "minecraft:wooden_hoe" + }, + { + "id" : "minecraft:stone_hoe" + }, + { + "id" : "minecraft:iron_hoe" + }, + { + "id" : "minecraft:golden_hoe" + }, + { + "id" : "minecraft:diamond_hoe" + }, + { + "id" : "minecraft:netherite_hoe" + }, + { + "id" : "minecraft:bow" + }, + { + "id" : "minecraft:crossbow" + }, + { + "id" : "minecraft:arrow" + }, + { + "id" : "minecraft:arrow", + "damage" : 6 + }, + { + "id" : "minecraft:arrow", + "damage" : 7 + }, + { + "id" : "minecraft:arrow", + "damage" : 8 + }, + { + "id" : "minecraft:arrow", + "damage" : 9 + }, + { + "id" : "minecraft:arrow", + "damage" : 10 + }, + { + "id" : "minecraft:arrow", + "damage" : 11 + }, + { + "id" : "minecraft:arrow", + "damage" : 12 + }, + { + "id" : "minecraft:arrow", + "damage" : 13 + }, + { + "id" : "minecraft:arrow", + "damage" : 14 + }, + { + "id" : "minecraft:arrow", + "damage" : 15 + }, + { + "id" : "minecraft:arrow", + "damage" : 16 + }, + { + "id" : "minecraft:arrow", + "damage" : 17 + }, + { + "id" : "minecraft:arrow", + "damage" : 18 + }, + { + "id" : "minecraft:arrow", + "damage" : 19 + }, + { + "id" : "minecraft:arrow", + "damage" : 20 + }, + { + "id" : "minecraft:arrow", + "damage" : 21 + }, + { + "id" : "minecraft:arrow", + "damage" : 22 + }, + { + "id" : "minecraft:arrow", + "damage" : 23 + }, + { + "id" : "minecraft:arrow", + "damage" : 24 + }, + { + "id" : "minecraft:arrow", + "damage" : 25 + }, + { + "id" : "minecraft:arrow", + "damage" : 26 + }, + { + "id" : "minecraft:arrow", + "damage" : 27 + }, + { + "id" : "minecraft:arrow", + "damage" : 28 + }, + { + "id" : "minecraft:arrow", + "damage" : 29 + }, + { + "id" : "minecraft:arrow", + "damage" : 30 + }, + { + "id" : "minecraft:arrow", + "damage" : 31 + }, + { + "id" : "minecraft:arrow", + "damage" : 32 + }, + { + "id" : "minecraft:arrow", + "damage" : 33 + }, + { + "id" : "minecraft:arrow", + "damage" : 34 + }, + { + "id" : "minecraft:arrow", + "damage" : 35 + }, + { + "id" : "minecraft:arrow", + "damage" : 36 + }, + { + "id" : "minecraft:arrow", + "damage" : 37 + }, + { + "id" : "minecraft:arrow", + "damage" : 38 + }, + { + "id" : "minecraft:arrow", + "damage" : 39 + }, + { + "id" : "minecraft:arrow", + "damage" : 40 + }, + { + "id" : "minecraft:arrow", + "damage" : 41 + }, + { + "id" : "minecraft:arrow", + "damage" : 42 + }, + { + "id" : "minecraft:arrow", + "damage" : 43 + }, + { + "id" : "minecraft:shield" + }, + { + "id" : "minecraft:cooked_chicken" + }, + { + "id" : "minecraft:cooked_porkchop" + }, + { + "id" : "minecraft:cooked_beef" + }, + { + "id" : "minecraft:cooked_mutton" + }, + { + "id" : "minecraft:cooked_rabbit" + }, + { + "id" : "minecraft:cooked_cod" + }, + { + "id" : "minecraft:cooked_salmon" + }, + { + "id" : "minecraft:bread" + }, + { + "id" : "minecraft:mushroom_stew" + }, + { + "id" : "minecraft:beetroot_soup" + }, + { + "id" : "minecraft:rabbit_stew" + }, + { + "id" : "minecraft:baked_potato" + }, + { + "id" : "minecraft:cookie" + }, + { + "id" : "minecraft:pumpkin_pie" + }, + { + "id" : "minecraft:cake" + }, + { + "id" : "minecraft:dried_kelp" + }, + { + "id" : "minecraft:fishing_rod" + }, + { + "id" : "minecraft:carrot_on_a_stick" + }, + { + "id" : "minecraft:warped_fungus_on_a_stick" + }, + { + "id" : "minecraft:snowball" + }, + { + "id" : "minecraft:shears" + }, + { + "id" : "minecraft:flint_and_steel" + }, + { + "id" : "minecraft:lead" + }, + { + "id" : "minecraft:clock" + }, + { + "id" : "minecraft:compass" + }, + { + "id" : "minecraft:recovery_compass" + }, + { + "id" : "minecraft:goat_horn" + }, + { + "id" : "minecraft:goat_horn", + "damage" : 1 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 2 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 3 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 4 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 5 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 6 + }, + { + "id" : "minecraft:goat_horn", + "damage" : 7 + }, + { + "id" : "minecraft:empty_map" + }, + { + "id" : "minecraft:empty_map", + "damage" : 2 + }, + { + "id" : "minecraft:saddle" + }, + { + "id" : "minecraft:leather_horse_armor" + }, + { + "id" : "minecraft:iron_horse_armor" + }, + { + "id" : "minecraft:golden_horse_armor" + }, + { + "id" : "minecraft:diamond_horse_armor" + }, + { + "id" : "minecraft:trident" + }, + { + "id" : "minecraft:turtle_helmet" + }, + { + "id" : "minecraft:elytra" + }, + { + "id" : "minecraft:totem_of_undying" + }, + { + "id" : "minecraft:glass_bottle" + }, + { + "id" : "minecraft:experience_bottle" + }, + { + "id" : "minecraft:potion" + }, + { + "id" : "minecraft:potion", + "damage" : 1 + }, + { + "id" : "minecraft:potion", + "damage" : 2 + }, + { + "id" : "minecraft:potion", + "damage" : 3 + }, + { + "id" : "minecraft:potion", + "damage" : 4 + }, + { + "id" : "minecraft:potion", + "damage" : 5 + }, + { + "id" : "minecraft:potion", + "damage" : 6 + }, + { + "id" : "minecraft:potion", + "damage" : 7 + }, + { + "id" : "minecraft:potion", + "damage" : 8 + }, + { + "id" : "minecraft:potion", + "damage" : 9 + }, + { + "id" : "minecraft:potion", + "damage" : 10 + }, + { + "id" : "minecraft:potion", + "damage" : 11 + }, + { + "id" : "minecraft:potion", + "damage" : 12 + }, + { + "id" : "minecraft:potion", + "damage" : 13 + }, + { + "id" : "minecraft:potion", + "damage" : 14 + }, + { + "id" : "minecraft:potion", + "damage" : 15 + }, + { + "id" : "minecraft:potion", + "damage" : 16 + }, + { + "id" : "minecraft:potion", + "damage" : 17 + }, + { + "id" : "minecraft:potion", + "damage" : 18 + }, + { + "id" : "minecraft:potion", + "damage" : 19 + }, + { + "id" : "minecraft:potion", + "damage" : 20 + }, + { + "id" : "minecraft:potion", + "damage" : 21 + }, + { + "id" : "minecraft:potion", + "damage" : 22 + }, + { + "id" : "minecraft:potion", + "damage" : 23 + }, + { + "id" : "minecraft:potion", + "damage" : 24 + }, + { + "id" : "minecraft:potion", + "damage" : 25 + }, + { + "id" : "minecraft:potion", + "damage" : 26 + }, + { + "id" : "minecraft:potion", + "damage" : 27 + }, + { + "id" : "minecraft:potion", + "damage" : 28 + }, + { + "id" : "minecraft:potion", + "damage" : 29 + }, + { + "id" : "minecraft:potion", + "damage" : 30 + }, + { + "id" : "minecraft:potion", + "damage" : 31 + }, + { + "id" : "minecraft:potion", + "damage" : 32 + }, + { + "id" : "minecraft:potion", + "damage" : 33 + }, + { + "id" : "minecraft:potion", + "damage" : 34 + }, + { + "id" : "minecraft:potion", + "damage" : 35 + }, + { + "id" : "minecraft:potion", + "damage" : 36 + }, + { + "id" : "minecraft:potion", + "damage" : 37 + }, + { + "id" : "minecraft:potion", + "damage" : 38 + }, + { + "id" : "minecraft:potion", + "damage" : 39 + }, + { + "id" : "minecraft:potion", + "damage" : 40 + }, + { + "id" : "minecraft:potion", + "damage" : 41 + }, + { + "id" : "minecraft:potion", + "damage" : 42 + }, + { + "id" : "minecraft:splash_potion" + }, + { + "id" : "minecraft:splash_potion", + "damage" : 1 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 2 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 3 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 4 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 5 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 6 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 7 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 8 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 9 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 10 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 11 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 12 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 13 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 14 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 15 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 16 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 17 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 18 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 19 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 20 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 21 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 22 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 23 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 24 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 25 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 26 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 27 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 28 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 29 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 30 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 31 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 32 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 33 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 34 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 35 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 36 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 37 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 38 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 39 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 40 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 41 + }, + { + "id" : "minecraft:splash_potion", + "damage" : 42 + }, + { + "id" : "minecraft:lingering_potion" + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 1 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 2 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 3 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 4 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 5 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 6 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 7 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 8 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 9 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 10 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 11 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 12 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 13 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 14 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 15 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 16 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 17 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 18 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 19 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 20 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 21 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 22 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 23 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 24 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 25 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 26 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 27 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 28 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 29 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 30 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 31 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 32 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 33 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 34 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 35 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 36 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 37 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 38 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 39 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 40 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 41 + }, + { + "id" : "minecraft:lingering_potion", + "damage" : 42 + }, + { + "id" : "minecraft:spyglass" + }, + { + "id" : "minecraft:stick" + }, + { + "id" : "minecraft:bed" + }, + { + "id" : "minecraft:bed", + "damage" : 8 + }, + { + "id" : "minecraft:bed", + "damage" : 7 + }, + { + "id" : "minecraft:bed", + "damage" : 15 + }, + { + "id" : "minecraft:bed", + "damage" : 12 + }, + { + "id" : "minecraft:bed", + "damage" : 14 + }, + { + "id" : "minecraft:bed", + "damage" : 1 + }, + { + "id" : "minecraft:bed", + "damage" : 4 + }, + { + "id" : "minecraft:bed", + "damage" : 5 + }, + { + "id" : "minecraft:bed", + "damage" : 13 + }, + { + "id" : "minecraft:bed", + "damage" : 9 + }, + { + "id" : "minecraft:bed", + "damage" : 3 + }, + { + "id" : "minecraft:bed", + "damage" : 11 + }, + { + "id" : "minecraft:bed", + "damage" : 10 + }, + { + "id" : "minecraft:bed", + "damage" : 2 + }, + { + "id" : "minecraft:bed", + "damage" : 6 + }, + { + "id" : "minecraft:torch", + "blockRuntimeId" : 1416 + }, + { + "id" : "minecraft:soul_torch", + "blockRuntimeId" : 6876 + }, + { + "id" : "minecraft:sea_pickle", + "blockRuntimeId" : 8891 + }, + { + "id" : "minecraft:lantern", + "blockRuntimeId" : 10936 + }, + { + "id" : "minecraft:soul_lantern", + "blockRuntimeId" : 8401 + }, + { + "id" : "minecraft:candle", + "blockRuntimeId" : 11666 + }, + { + "id" : "minecraft:white_candle", + "blockRuntimeId" : 7948 + }, + { + "id" : "minecraft:orange_candle", + "blockRuntimeId" : 660 + }, + { + "id" : "minecraft:magenta_candle", + "blockRuntimeId" : 716 + }, + { + "id" : "minecraft:light_blue_candle", + "blockRuntimeId" : 6417 + }, + { + "id" : "minecraft:yellow_candle", + "blockRuntimeId" : 10022 + }, + { + "id" : "minecraft:lime_candle", + "blockRuntimeId" : 10206 + }, + { + "id" : "minecraft:pink_candle", + "blockRuntimeId" : 11633 + }, + { + "id" : "minecraft:gray_candle", + "blockRuntimeId" : 1631 + }, + { + "id" : "minecraft:light_gray_candle", + "blockRuntimeId" : 10062 + }, + { + "id" : "minecraft:cyan_candle", + "blockRuntimeId" : 11989 + }, + { + "id" : "minecraft:purple_candle", + "blockRuntimeId" : 10900 + }, + { + "id" : "minecraft:blue_candle" + }, + { + "id" : "minecraft:brown_candle", + "blockRuntimeId" : 9295 + }, + { + "id" : "minecraft:green_candle", + "blockRuntimeId" : 1370 + }, + { + "id" : "minecraft:red_candle", + "blockRuntimeId" : 6913 + }, + { + "id" : "minecraft:black_candle", + "blockRuntimeId" : 176 + }, + { + "id" : "minecraft:crafting_table", + "blockRuntimeId" : 8890 + }, + { + "id" : "minecraft:cartography_table", + "blockRuntimeId" : 12554 + }, + { + "id" : "minecraft:fletching_table", + "blockRuntimeId" : 8869 + }, + { + "id" : "minecraft:smithing_table", + "blockRuntimeId" : 5184 + }, + { + "id" : "minecraft:beehive", + "blockRuntimeId" : 9938 + }, + { + "id" : "minecraft:campfire" + }, + { + "id" : "minecraft:soul_campfire" + }, + { + "id" : "minecraft:furnace", + "blockRuntimeId" : 12065 + }, + { + "id" : "minecraft:blast_furnace", + "blockRuntimeId" : 11830 + }, + { + "id" : "minecraft:smoker", + "blockRuntimeId" : 1330 + }, + { + "id" : "minecraft:respawn_anchor", + "blockRuntimeId" : 1365 + }, + { + "id" : "minecraft:brewing_stand" + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 10486 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 10490 + }, + { + "id" : "minecraft:anvil", + "blockRuntimeId" : 10494 + }, + { + "id" : "minecraft:grindstone", + "blockRuntimeId" : 12302 + }, + { + "id" : "minecraft:enchanting_table", + "blockRuntimeId" : 10579 + }, + { + "id" : "minecraft:bookshelf", + "blockRuntimeId" : 10523 + }, + { + "id" : "minecraft:lectern", + "blockRuntimeId" : 10802 + }, + { + "id" : "minecraft:cauldron" + }, + { + "id" : "minecraft:composter", + "blockRuntimeId" : 8065 + }, + { + "id" : "minecraft:chest", + "blockRuntimeId" : 10978 + }, + { + "id" : "minecraft:trapped_chest", + "blockRuntimeId" : 8234 + }, + { + "id" : "minecraft:ender_chest", + "blockRuntimeId" : 6217 + }, + { + "id" : "minecraft:barrel", + "blockRuntimeId" : 6366 + }, + { + "id" : "minecraft:undyed_shulker_box", + "blockRuntimeId" : 5139 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7964 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7972 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7971 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7979 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7976 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7978 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7965 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7968 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7969 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7977 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7973 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7967 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7975 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7974 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7966 + }, + { + "id" : "minecraft:shulker_box", + "blockRuntimeId" : 7970 + }, + { + "id" : "minecraft:armor_stand" + }, + { + "id" : "minecraft:noteblock", + "blockRuntimeId" : 643 + }, + { + "id" : "minecraft:jukebox", + "blockRuntimeId" : 7490 + }, + { + "id" : "minecraft:music_disc_13" + }, + { + "id" : "minecraft:music_disc_cat" + }, + { + "id" : "minecraft:music_disc_blocks" + }, + { + "id" : "minecraft:music_disc_chirp" + }, + { + "id" : "minecraft:music_disc_far" + }, + { + "id" : "minecraft:music_disc_mall" + }, + { + "id" : "minecraft:music_disc_mellohi" + }, + { + "id" : "minecraft:music_disc_stal" + }, + { + "id" : "minecraft:music_disc_strad" + }, + { + "id" : "minecraft:music_disc_ward" + }, + { + "id" : "minecraft:music_disc_11" + }, + { + "id" : "minecraft:music_disc_wait" + }, + { + "id" : "minecraft:music_disc_otherside" + }, + { + "id" : "minecraft:music_disc_5" + }, + { + "id" : "minecraft:music_disc_pigstep" + }, + { + "id" : "minecraft:disc_fragment_5" + }, + { + "id" : "minecraft:glowstone_dust" + }, + { + "id" : "minecraft:glowstone", + "blockRuntimeId" : 5729 + }, + { + "id" : "minecraft:redstone_lamp", + "blockRuntimeId" : 257 + }, + { + "id" : "minecraft:sea_lantern", + "blockRuntimeId" : 11809 + }, + { + "id" : "minecraft:oak_sign" + }, + { + "id" : "minecraft:spruce_sign" + }, + { + "id" : "minecraft:birch_sign" + }, + { + "id" : "minecraft:jungle_sign" + }, + { + "id" : "minecraft:acacia_sign" + }, + { + "id" : "minecraft:dark_oak_sign" + }, + { + "id" : "minecraft:mangrove_sign" + }, + { + "id" : "minecraft:crimson_sign" + }, + { + "id" : "minecraft:warped_sign" + }, + { + "id" : "minecraft:painting" + }, + { + "id" : "minecraft:frame" + }, + { + "id" : "minecraft:glow_frame" + }, + { + "id" : "minecraft:honey_bottle" + }, + { + "id" : "minecraft:flower_pot" + }, + { + "id" : "minecraft:bowl" + }, + { + "id" : "minecraft:bucket" + }, + { + "id" : "minecraft:milk_bucket" + }, + { + "id" : "minecraft:water_bucket" + }, + { + "id" : "minecraft:lava_bucket" + }, + { + "id" : "minecraft:cod_bucket" + }, + { + "id" : "minecraft:salmon_bucket" + }, + { + "id" : "minecraft:tropical_fish_bucket" + }, + { + "id" : "minecraft:pufferfish_bucket" + }, + { + "id" : "minecraft:powder_snow_bucket" + }, + { + "id" : "minecraft:axolotl_bucket" + }, + { + "id" : "minecraft:tadpole_bucket" + }, + { + "id" : "minecraft:skull", + "damage" : 3 + }, + { + "id" : "minecraft:skull", + "damage" : 2 + }, + { + "id" : "minecraft:skull", + "damage" : 4 + }, + { + "id" : "minecraft:skull", + "damage" : 5 + }, + { + "id" : "minecraft:skull" + }, + { + "id" : "minecraft:skull", + "damage" : 1 + }, + { + "id" : "minecraft:beacon", + "blockRuntimeId" : 150 + }, + { + "id" : "minecraft:bell", + "blockRuntimeId" : 10770 + }, + { + "id" : "minecraft:conduit", + "blockRuntimeId" : 6078 + }, + { + "id" : "minecraft:stonecutter_block", + "blockRuntimeId" : 11837 + }, + { + "id" : "minecraft:end_portal_frame", + "blockRuntimeId" : 9891 + }, + { + "id" : "minecraft:coal" + }, + { + "id" : "minecraft:charcoal" + }, + { + "id" : "minecraft:diamond" + }, + { + "id" : "minecraft:iron_nugget" + }, + { + "id" : "minecraft:raw_iron" + }, + { + "id" : "minecraft:raw_gold" + }, + { + "id" : "minecraft:raw_copper" + }, + { + "id" : "minecraft:copper_ingot" + }, + { + "id" : "minecraft:iron_ingot" + }, + { + "id" : "minecraft:netherite_scrap" + }, + { + "id" : "minecraft:netherite_ingot" + }, + { + "id" : "minecraft:gold_nugget" + }, + { + "id" : "minecraft:gold_ingot" + }, + { + "id" : "minecraft:emerald" + }, + { + "id" : "minecraft:quartz" + }, + { + "id" : "minecraft:clay_ball" + }, + { + "id" : "minecraft:brick" + }, + { + "id" : "minecraft:netherbrick" + }, + { + "id" : "minecraft:prismarine_shard" + }, + { + "id" : "minecraft:amethyst_shard" + }, + { + "id" : "minecraft:prismarine_crystals" + }, + { + "id" : "minecraft:nautilus_shell" + }, + { + "id" : "minecraft:heart_of_the_sea" + }, + { + "id" : "minecraft:scute" + }, + { + "id" : "minecraft:phantom_membrane" + }, + { + "id" : "minecraft:string" + }, + { + "id" : "minecraft:feather" + }, + { + "id" : "minecraft:flint" + }, + { + "id" : "minecraft:gunpowder" + }, + { + "id" : "minecraft:leather" + }, + { + "id" : "minecraft:rabbit_hide" + }, + { + "id" : "minecraft:rabbit_foot" + }, + { + "id" : "minecraft:fire_charge" + }, + { + "id" : "minecraft:blaze_rod" + }, + { + "id" : "minecraft:blaze_powder" + }, + { + "id" : "minecraft:magma_cream" + }, + { + "id" : "minecraft:fermented_spider_eye" + }, + { + "id" : "minecraft:echo_shard" + }, + { + "id" : "minecraft:dragon_breath" + }, + { + "id" : "minecraft:shulker_shell" + }, + { + "id" : "minecraft:ghast_tear" + }, + { + "id" : "minecraft:slime_ball" + }, + { + "id" : "minecraft:ender_pearl" + }, + { + "id" : "minecraft:ender_eye" + }, + { + "id" : "minecraft:nether_star" + }, + { + "id" : "minecraft:end_rod", + "blockRuntimeId" : 9311 + }, + { + "id" : "minecraft:lightning_rod", + "blockRuntimeId" : 1877 + }, + { + "id" : "minecraft:end_crystal" + }, + { + "id" : "minecraft:paper" + }, + { + "id" : "minecraft:book" + }, + { + "id" : "minecraft:writable_book" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAEAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAIAAAA=" + }, + { + "id" : "minecraft:enchanted_book", + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQlAAIDAGx2bAMAAAA=" + }, + { + "id" : "minecraft:oak_boat" + }, + { + "id" : "minecraft:spruce_boat" + }, + { + "id" : "minecraft:birch_boat" + }, + { + "id" : "minecraft:jungle_boat" + }, + { + "id" : "minecraft:acacia_boat" + }, + { + "id" : "minecraft:dark_oak_boat" + }, + { + "id" : "minecraft:mangrove_boat" + }, + { + "id" : "minecraft:oak_chest_boat" + }, + { + "id" : "minecraft:spruce_chest_boat" + }, + { + "id" : "minecraft:birch_chest_boat" + }, + { + "id" : "minecraft:jungle_chest_boat" + }, + { + "id" : "minecraft:acacia_chest_boat" + }, + { + "id" : "minecraft:dark_oak_chest_boat" + }, + { + "id" : "minecraft:mangrove_chest_boat" + }, + { + "id" : "minecraft:rail", + "blockRuntimeId" : 5764 + }, + { + "id" : "minecraft:golden_rail", + "blockRuntimeId" : 7980 + }, + { + "id" : "minecraft:detector_rail", + "blockRuntimeId" : 5976 + }, + { + "id" : "minecraft:activator_rail", + "blockRuntimeId" : 604 + }, + { + "id" : "minecraft:minecart" + }, + { + "id" : "minecraft:chest_minecart" + }, + { + "id" : "minecraft:hopper_minecart" + }, + { + "id" : "minecraft:tnt_minecart" + }, + { + "id" : "minecraft:redstone" + }, + { + "id" : "minecraft:redstone_block", + "blockRuntimeId" : 5236 + }, + { + "id" : "minecraft:redstone_torch", + "blockRuntimeId" : 4596 + }, + { + "id" : "minecraft:lever", + "blockRuntimeId" : 10364 + }, + { + "id" : "minecraft:wooden_button", + "blockRuntimeId" : 10229 + }, + { + "id" : "minecraft:spruce_button", + "blockRuntimeId" : 6169 + }, + { + "id" : "minecraft:birch_button", + "blockRuntimeId" : 12029 + }, + { + "id" : "minecraft:jungle_button", + "blockRuntimeId" : 120 + }, + { + "id" : "minecraft:acacia_button", + "blockRuntimeId" : 11494 + }, + { + "id" : "minecraft:dark_oak_button", + "blockRuntimeId" : 96 + }, + { + "id" : "minecraft:mangrove_button", + "blockRuntimeId" : 10924 + }, + { + "id" : "minecraft:stone_button", + "blockRuntimeId" : 894 + }, + { + "id" : "minecraft:crimson_button", + "blockRuntimeId" : 6280 + }, + { + "id" : "minecraft:warped_button", + "blockRuntimeId" : 11513 + }, + { + "id" : "minecraft:polished_blackstone_button", + "blockRuntimeId" : 12053 + }, + { + "id" : "minecraft:tripwire_hook", + "blockRuntimeId" : 9334 + }, + { + "id" : "minecraft:wooden_pressure_plate", + "blockRuntimeId" : 12327 + }, + { + "id" : "minecraft:spruce_pressure_plate", + "blockRuntimeId" : 5218 + }, + { + "id" : "minecraft:birch_pressure_plate", + "blockRuntimeId" : 5010 + }, + { + "id" : "minecraft:jungle_pressure_plate", + "blockRuntimeId" : 5093 + }, + { + "id" : "minecraft:acacia_pressure_plate", + "blockRuntimeId" : 7879 + }, + { + "id" : "minecraft:dark_oak_pressure_plate", + "blockRuntimeId" : 9376 + }, + { + "id" : "minecraft:mangrove_pressure_plate", + "blockRuntimeId" : 5713 + }, + { + "id" : "minecraft:crimson_pressure_plate", + "blockRuntimeId" : 12534 + }, + { + "id" : "minecraft:warped_pressure_plate", + "blockRuntimeId" : 263 + }, + { + "id" : "minecraft:stone_pressure_plate", + "blockRuntimeId" : 5730 + }, + { + "id" : "minecraft:light_weighted_pressure_plate", + "blockRuntimeId" : 5123 + }, + { + "id" : "minecraft:heavy_weighted_pressure_plate", + "blockRuntimeId" : 1861 + }, + { + "id" : "minecraft:polished_blackstone_pressure_plate", + "blockRuntimeId" : 10070 + }, + { + "id" : "minecraft:observer", + "blockRuntimeId" : 4584 + }, + { + "id" : "minecraft:daylight_detector", + "blockRuntimeId" : 6043 + }, + { + "id" : "minecraft:repeater" + }, + { + "id" : "minecraft:comparator" + }, + { + "id" : "minecraft:hopper" + }, + { + "id" : "minecraft:dropper", + "blockRuntimeId" : 11648 + }, + { + "id" : "minecraft:dispenser", + "blockRuntimeId" : 12276 + }, + { + "id" : "minecraft:piston", + "blockRuntimeId" : 1614 + }, + { + "id" : "minecraft:sticky_piston", + "blockRuntimeId" : 6212 + }, + { + "id" : "minecraft:tnt", + "blockRuntimeId" : 10559 + }, + { + "id" : "minecraft:name_tag" + }, + { + "id" : "minecraft:loom", + "blockRuntimeId" : 5670 + }, + { + "id" : "minecraft:banner" + }, + { + "id" : "minecraft:banner", + "damage" : 8 + }, + { + "id" : "minecraft:banner", + "damage" : 7 + }, + { + "id" : "minecraft:banner", + "damage" : 15 + }, + { + "id" : "minecraft:banner", + "damage" : 12 + }, + { + "id" : "minecraft:banner", + "damage" : 14 + }, + { + "id" : "minecraft:banner", + "damage" : 1 + }, + { + "id" : "minecraft:banner", + "damage" : 4 + }, + { + "id" : "minecraft:banner", + "damage" : 5 + }, + { + "id" : "minecraft:banner", + "damage" : 13 + }, + { + "id" : "minecraft:banner", + "damage" : 9 + }, + { + "id" : "minecraft:banner", + "damage" : 3 + }, + { + "id" : "minecraft:banner", + "damage" : 11 + }, + { + "id" : "minecraft:banner", + "damage" : 10 + }, + { + "id" : "minecraft:banner", + "damage" : 2 + }, + { + "id" : "minecraft:banner", + "damage" : 6 + }, + { + "id" : "minecraft:banner", + "damage" : 15, + "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA" + }, + { + "id" : "minecraft:creeper_banner_pattern" + }, + { + "id" : "minecraft:skull_banner_pattern" + }, + { + "id" : "minecraft:flower_banner_pattern" + }, + { + "id" : "minecraft:mojang_banner_pattern" + }, + { + "id" : "minecraft:field_masoned_banner_pattern" + }, + { + "id" : "minecraft:bordure_indented_banner_pattern" + }, + { + "id" : "minecraft:piglin_banner_pattern" + }, + { + "id" : "minecraft:globe_banner_pattern" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_rocket", + "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + }, + { + "id" : "minecraft:firework_star", + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 8, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 7, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 15, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 12, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 14, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 1, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 4, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 5, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 13, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 9, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 3, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 11, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 10, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 2, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + }, + { + "id" : "minecraft:firework_star", + "damage" : 6, + "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" + }, + { + "id" : "minecraft:chain" + }, + { + "id" : "minecraft:target", + "blockRuntimeId" : 10228 + }, + { + "id" : "minecraft:lodestone_compass" + }, + { + "id" : "minecraft:wither_spawn_egg" + }, + { + "id" : "minecraft:ender_dragon_spawn_egg" + } + ] +} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_19_70.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_70.json new file mode 100644 index 000000000..500fcc4f6 --- /dev/null +++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_70.json @@ -0,0 +1,4786 @@ +[ + { + "name" : "minecraft:acacia_boat", + "id" : 380 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:acacia_chest_boat", + "id" : 648 + }, + { + "name" : "minecraft:acacia_door", + "id" : 562 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:acacia_hanging_sign", + "id" : -504 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 585 + }, + { + "name" : "minecraft:acacia_stairs", + "id" : 163 + }, + { + "name" : "minecraft:acacia_standing_sign", + "id" : -190 + }, + { + "name" : "minecraft:acacia_trapdoor", + "id" : -145 + }, + { + "name" : "minecraft:acacia_wall_sign", + "id" : -191 + }, + { + "name" : "minecraft:activator_rail", + "id" : 126 + }, + { + "name" : "minecraft:agent_spawn_egg", + "id" : 488 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:allay_spawn_egg", + "id" : 637 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:amethyst_block", + "id" : -327 + }, + { + "name" : "minecraft:amethyst_cluster", + "id" : -329 + }, + { + "name" : "minecraft:amethyst_shard", + "id" : 630 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:apple", + "id" : 257 + }, + { + "name" : "minecraft:archer_pottery_shard", + "id" : 659 + }, + { + "name" : "minecraft:armor_stand", + "id" : 558 + }, + { + "name" : "minecraft:arms_up_pottery_shard", + "id" : 660 + }, + { + "name" : "minecraft:arrow", + "id" : 302 + }, + { + "name" : "minecraft:axolotl_bucket", + "id" : 370 + }, + { + "name" : "minecraft:axolotl_spawn_egg", + "id" : 502 + }, + { + "name" : "minecraft:azalea", + "id" : -337 + }, + { + "name" : "minecraft:azalea_leaves", + "id" : -324 + }, + { + "name" : "minecraft:azalea_leaves_flowered", + "id" : -325 + }, + { + "name" : "minecraft:baked_potato", + "id" : 281 + }, + { + "name" : "minecraft:balloon", + "id" : 604 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:bamboo_block", + "id" : -527 + }, + { + "name" : "minecraft:bamboo_button", + "id" : -511 + }, + { + "name" : "minecraft:bamboo_chest_raft", + "id" : 657 + }, + { + "name" : "minecraft:bamboo_door", + "id" : -517 + }, + { + "name" : "minecraft:bamboo_double_slab", + "id" : -521 + }, + { + "name" : "minecraft:bamboo_fence", + "id" : -515 + }, + { + "name" : "minecraft:bamboo_fence_gate", + "id" : -516 + }, + { + "name" : "minecraft:bamboo_hanging_sign", + "id" : -522 + }, + { + "name" : "minecraft:bamboo_mosaic", + "id" : -509 + }, + { + "name" : "minecraft:bamboo_mosaic_double_slab", + "id" : -525 + }, + { + "name" : "minecraft:bamboo_mosaic_slab", + "id" : -524 + }, + { + "name" : "minecraft:bamboo_mosaic_stairs", + "id" : -523 + }, + { + "name" : "minecraft:bamboo_planks", + "id" : -510 + }, + { + "name" : "minecraft:bamboo_pressure_plate", + "id" : -514 + }, + { + "name" : "minecraft:bamboo_raft", + "id" : 656 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:bamboo_sign", + "id" : 655 + }, + { + "name" : "minecraft:bamboo_slab", + "id" : -513 + }, + { + "name" : "minecraft:bamboo_stairs", + "id" : -512 + }, + { + "name" : "minecraft:bamboo_standing_sign", + "id" : -518 + }, + { + "name" : "minecraft:bamboo_trapdoor", + "id" : -520 + }, + { + "name" : "minecraft:bamboo_wall_sign", + "id" : -519 + }, + { + "name" : "minecraft:banner", + "id" : 573 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 667 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:bat_spawn_egg", + "id" : 454 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:bed", + "id" : 419 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:bee_spawn_egg", + "id" : 495 + }, + { + "name" : "minecraft:beef", + "id" : 273 + }, + { + "name" : "minecraft:beehive", + "id" : -219 + }, + { + "name" : "minecraft:beetroot", + "id" : 285 + }, + { + "name" : "minecraft:beetroot_seeds", + "id" : 295 + }, + { + "name" : "minecraft:beetroot_soup", + "id" : 286 + }, + { + "name" : "minecraft:bell", + "id" : -206 + }, + { + "name" : "minecraft:big_dripleaf", + "id" : -323 + }, + { + "name" : "minecraft:birch_boat", + "id" : 377 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_chest_boat", + "id" : 645 + }, + { + "name" : "minecraft:birch_door", + "id" : 560 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:birch_hanging_sign", + "id" : -502 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:birch_sign", + "id" : 583 + }, + { + "name" : "minecraft:birch_stairs", + "id" : 135 + }, + { + "name" : "minecraft:birch_standing_sign", + "id" : -186 + }, + { + "name" : "minecraft:birch_trapdoor", + "id" : -146 + }, + { + "name" : "minecraft:birch_wall_sign", + "id" : -187 + }, + { + "name" : "minecraft:black_candle", + "id" : -428 + }, + { + "name" : "minecraft:black_candle_cake", + "id" : -445 + }, + { + "name" : "minecraft:black_dye", + "id" : 396 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "name" : "minecraft:black_wool", + "id" : -554 + }, + { + "name" : "minecraft:blackstone", + "id" : -273 + }, + { + "name" : "minecraft:blackstone_double_slab", + "id" : -283 + }, + { + "name" : "minecraft:blackstone_slab", + "id" : -282 + }, + { + "name" : "minecraft:blackstone_stairs", + "id" : -276 + }, + { + "name" : "minecraft:blackstone_wall", + "id" : -277 + }, + { + "name" : "minecraft:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 430 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 424 + }, + { + "name" : "minecraft:blaze_spawn_egg", + "id" : 457 + }, + { + "name" : "minecraft:bleach", + "id" : 602 + }, + { + "name" : "minecraft:blue_candle", + "id" : -424 + }, + { + "name" : "minecraft:blue_candle_cake", + "id" : -441 + }, + { + "name" : "minecraft:blue_dye", + "id" : 400 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:blue_wool", + "id" : -563 + }, + { + "name" : "minecraft:boat", + "id" : 665 + }, + { + "name" : "minecraft:bone", + "id" : 416 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:bone_meal", + "id" : 412 + }, + { + "name" : "minecraft:book", + "id" : 388 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:bordure_indented_banner_pattern", + "id" : 592 + }, + { + "name" : "minecraft:bow", + "id" : 301 + }, + { + "name" : "minecraft:bowl", + "id" : 322 + }, + { + "name" : "minecraft:bread", + "id" : 261 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 432 + }, + { + "name" : "minecraft:brick", + "id" : 384 + }, + { + "name" : "minecraft:brick_block", + "id" : 45 + }, + { + "name" : "minecraft:brick_stairs", + "id" : 108 + }, + { + "name" : "minecraft:brown_candle", + "id" : -425 + }, + { + "name" : "minecraft:brown_candle_cake", + "id" : -442 + }, + { + "name" : "minecraft:brown_dye", + "id" : 399 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:brown_wool", + "id" : -555 + }, + { + "name" : "minecraft:brush", + "id" : 663 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:bucket", + "id" : 361 + }, + { + "name" : "minecraft:budding_amethyst", + "id" : -328 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:cake", + "id" : 418 + }, + { + "name" : "minecraft:calcite", + "id" : -326 + }, + { + "name" : "minecraft:camel_spawn_egg", + "id" : 658 + }, + { + "name" : "minecraft:camera", + "id" : 599 + }, + { + "name" : "minecraft:campfire", + "id" : 595 + }, + { + "name" : "minecraft:candle", + "id" : -412 + }, + { + "name" : "minecraft:candle_cake", + "id" : -429 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:carrot", + "id" : 279 + }, + { + "name" : "minecraft:carrot_on_a_stick", + "id" : 523 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:cat_spawn_egg", + "id" : 489 + }, + { + "name" : "minecraft:cauldron", + "id" : 433 + }, + { + "name" : "minecraft:cave_spider_spawn_egg", + "id" : 458 + }, + { + "name" : "minecraft:cave_vines", + "id" : -322 + }, + { + "name" : "minecraft:cave_vines_body_with_berries", + "id" : -375 + }, + { + "name" : "minecraft:cave_vines_head_with_berries", + "id" : -376 + }, + { + "name" : "minecraft:chain", + "id" : 625 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 343 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 341 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 340 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 342 + }, + { + "name" : "minecraft:charcoal", + "id" : 304 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:chest_boat", + "id" : 651 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 390 + }, + { + "name" : "minecraft:chicken", + "id" : 275 + }, + { + "name" : "minecraft:chicken_spawn_egg", + "id" : 436 + }, + { + "name" : "minecraft:chiseled_bookshelf", + "id" : -526 + }, + { + "name" : "minecraft:chiseled_deepslate", + "id" : -395 + }, + { + "name" : "minecraft:chiseled_nether_bricks", + "id" : -302 + }, + { + "name" : "minecraft:chiseled_polished_blackstone", + "id" : -279 + }, + { + "name" : "minecraft:chorus_flower", + "id" : 200 + }, + { + "name" : "minecraft:chorus_fruit", + "id" : 564 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:clay_ball", + "id" : 385 + }, + { + "name" : "minecraft:client_request_placeholder_block", + "id" : -465 + }, + { + "name" : "minecraft:clock", + "id" : 394 + }, + { + "name" : "minecraft:coal", + "id" : 303 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "name" : "minecraft:cobbled_deepslate", + "id" : -379 + }, + { + "name" : "minecraft:cobbled_deepslate_double_slab", + "id" : -396 + }, + { + "name" : "minecraft:cobbled_deepslate_slab", + "id" : -380 + }, + { + "name" : "minecraft:cobbled_deepslate_stairs", + "id" : -381 + }, + { + "name" : "minecraft:cobbled_deepslate_wall", + "id" : -382 + }, + { + "name" : "minecraft:cobblestone", + "id" : 4 + }, + { + "name" : "minecraft:cobblestone_wall", + "id" : 139 + }, + { + "name" : "minecraft:cocoa", + "id" : 127 + }, + { + "name" : "minecraft:cocoa_beans", + "id" : 413 + }, + { + "name" : "minecraft:cod", + "id" : 264 + }, + { + "name" : "minecraft:cod_bucket", + "id" : 365 + }, + { + "name" : "minecraft:cod_spawn_egg", + "id" : 481 + }, + { + "name" : "minecraft:colored_torch_bp", + "id" : 204 + }, + { + "name" : "minecraft:colored_torch_rg", + "id" : 202 + }, + { + "name" : "minecraft:command_block", + "id" : 137 + }, + { + "name" : "minecraft:command_block_minecart", + "id" : 569 + }, + { + "name" : "minecraft:comparator", + "id" : 528 + }, + { + "name" : "minecraft:compass", + "id" : 392 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:compound", + "id" : 600 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "name" : "minecraft:conduit", + "id" : -157 + }, + { + "name" : "minecraft:cooked_beef", + "id" : 274 + }, + { + "name" : "minecraft:cooked_chicken", + "id" : 276 + }, + { + "name" : "minecraft:cooked_cod", + "id" : 268 + }, + { + "name" : "minecraft:cooked_mutton", + "id" : 557 + }, + { + "name" : "minecraft:cooked_porkchop", + "id" : 263 + }, + { + "name" : "minecraft:cooked_rabbit", + "id" : 289 + }, + { + "name" : "minecraft:cooked_salmon", + "id" : 269 + }, + { + "name" : "minecraft:cookie", + "id" : 271 + }, + { + "name" : "minecraft:copper_block", + "id" : -340 + }, + { + "name" : "minecraft:copper_ingot", + "id" : 510 + }, + { + "name" : "minecraft:copper_ore", + "id" : -311 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "name" : "minecraft:coral_block", + "id" : -132 + }, + { + "name" : "minecraft:coral_fan", + "id" : -133 + }, + { + "name" : "minecraft:coral_fan_dead", + "id" : -134 + }, + { + "name" : "minecraft:coral_fan_hang", + "id" : -135 + }, + { + "name" : "minecraft:coral_fan_hang2", + "id" : -136 + }, + { + "name" : "minecraft:coral_fan_hang3", + "id" : -137 + }, + { + "name" : "minecraft:cow_spawn_egg", + "id" : 437 + }, + { + "name" : "minecraft:cracked_deepslate_bricks", + "id" : -410 + }, + { + "name" : "minecraft:cracked_deepslate_tiles", + "id" : -409 + }, + { + "name" : "minecraft:cracked_nether_bricks", + "id" : -303 + }, + { + "name" : "minecraft:cracked_polished_blackstone_bricks", + "id" : -280 + }, + { + "name" : "minecraft:crafting_table", + "id" : 58 + }, + { + "name" : "minecraft:creeper_banner_pattern", + "id" : 588 + }, + { + "name" : "minecraft:creeper_spawn_egg", + "id" : 442 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:crimson_door", + "id" : 622 + }, + { + "name" : "minecraft:crimson_double_slab", + "id" : -266 + }, + { + "name" : "minecraft:crimson_fence", + "id" : -256 + }, + { + "name" : "minecraft:crimson_fence_gate", + "id" : -258 + }, + { + "name" : "minecraft:crimson_fungus", + "id" : -228 + }, + { + "name" : "minecraft:crimson_hanging_sign", + "id" : -506 + }, + { + "name" : "minecraft:crimson_hyphae", + "id" : -299 + }, + { + "name" : "minecraft:crimson_nylium", + "id" : -232 + }, + { + "name" : "minecraft:crimson_planks", + "id" : -242 + }, + { + "name" : "minecraft:crimson_pressure_plate", + "id" : -262 + }, + { + "name" : "minecraft:crimson_roots", + "id" : -223 + }, + { + "name" : "minecraft:crimson_sign", + "id" : 620 + }, + { + "name" : "minecraft:crimson_slab", + "id" : -264 + }, + { + "name" : "minecraft:crimson_stairs", + "id" : -254 + }, + { + "name" : "minecraft:crimson_standing_sign", + "id" : -250 + }, + { + "name" : "minecraft:crimson_stem", + "id" : -225 + }, + { + "name" : "minecraft:crimson_trapdoor", + "id" : -246 + }, + { + "name" : "minecraft:crimson_wall_sign", + "id" : -252 + }, + { + "name" : "minecraft:crossbow", + "id" : 581 + }, + { + "name" : "minecraft:crying_obsidian", + "id" : -289 + }, + { + "name" : "minecraft:cut_copper", + "id" : -347 + }, + { + "name" : "minecraft:cut_copper_slab", + "id" : -361 + }, + { + "name" : "minecraft:cut_copper_stairs", + "id" : -354 + }, + { + "name" : "minecraft:cyan_candle", + "id" : -422 + }, + { + "name" : "minecraft:cyan_candle_cake", + "id" : -439 + }, + { + "name" : "minecraft:cyan_dye", + "id" : 402 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:cyan_wool", + "id" : -561 + }, + { + "name" : "minecraft:dark_oak_boat", + "id" : 381 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:dark_oak_chest_boat", + "id" : 649 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 563 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:dark_oak_hanging_sign", + "id" : -505 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:dark_oak_sign", + "id" : 586 + }, + { + "name" : "minecraft:dark_oak_stairs", + "id" : 164 + }, + { + "name" : "minecraft:dark_oak_trapdoor", + "id" : -147 + }, + { + "name" : "minecraft:dark_prismarine_stairs", + "id" : -3 + }, + { + "name" : "minecraft:darkoak_standing_sign", + "id" : -192 + }, + { + "name" : "minecraft:darkoak_wall_sign", + "id" : -193 + }, + { + "name" : "minecraft:daylight_detector", + "id" : 151 + }, + { + "name" : "minecraft:daylight_detector_inverted", + "id" : 178 + }, + { + "name" : "minecraft:deadbush", + "id" : 32 + }, + { + "name" : "minecraft:decorated_pot", + "id" : -551 + }, + { + "name" : "minecraft:deepslate", + "id" : -378 + }, + { + "name" : "minecraft:deepslate_brick_double_slab", + "id" : -399 + }, + { + "name" : "minecraft:deepslate_brick_slab", + "id" : -392 + }, + { + "name" : "minecraft:deepslate_brick_stairs", + "id" : -393 + }, + { + "name" : "minecraft:deepslate_brick_wall", + "id" : -394 + }, + { + "name" : "minecraft:deepslate_bricks", + "id" : -391 + }, + { + "name" : "minecraft:deepslate_coal_ore", + "id" : -406 + }, + { + "name" : "minecraft:deepslate_copper_ore", + "id" : -408 + }, + { + "name" : "minecraft:deepslate_diamond_ore", + "id" : -405 + }, + { + "name" : "minecraft:deepslate_emerald_ore", + "id" : -407 + }, + { + "name" : "minecraft:deepslate_gold_ore", + "id" : -402 + }, + { + "name" : "minecraft:deepslate_iron_ore", + "id" : -401 + }, + { + "name" : "minecraft:deepslate_lapis_ore", + "id" : -400 + }, + { + "name" : "minecraft:deepslate_redstone_ore", + "id" : -403 + }, + { + "name" : "minecraft:deepslate_tile_double_slab", + "id" : -398 + }, + { + "name" : "minecraft:deepslate_tile_slab", + "id" : -388 + }, + { + "name" : "minecraft:deepslate_tile_stairs", + "id" : -389 + }, + { + "name" : "minecraft:deepslate_tile_wall", + "id" : -390 + }, + { + "name" : "minecraft:deepslate_tiles", + "id" : -387 + }, + { + "name" : "minecraft:deny", + "id" : 211 + }, + { + "name" : "minecraft:detector_rail", + "id" : 28 + }, + { + "name" : "minecraft:diamond", + "id" : 305 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 320 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 351 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 349 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 348 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 333 + }, + { + "name" : "minecraft:diamond_horse_armor", + "id" : 539 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 350 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 319 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 318 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 317 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:dirt_with_roots", + "id" : -318 + }, + { + "name" : "minecraft:disc_fragment_5", + "id" : 643 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:dolphin_spawn_egg", + "id" : 485 + }, + { + "name" : "minecraft:donkey_spawn_egg", + "id" : 466 + }, + { + "name" : "minecraft:double_cut_copper_slab", + "id" : -368 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:double_stone_block_slab", + "id" : 43 + }, + { + "name" : "minecraft:double_stone_block_slab2", + "id" : 181 + }, + { + "name" : "minecraft:double_stone_block_slab3", + "id" : -167 + }, + { + "name" : "minecraft:double_stone_block_slab4", + "id" : -168 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 566 + }, + { + "name" : "minecraft:dragon_egg", + "id" : 122 + }, + { + "name" : "minecraft:dried_kelp", + "id" : 270 + }, + { + "name" : "minecraft:dried_kelp_block", + "id" : -139 + }, + { + "name" : "minecraft:dripstone_block", + "id" : -317 + }, + { + "name" : "minecraft:dropper", + "id" : 125 + }, + { + "name" : "minecraft:drowned_spawn_egg", + "id" : 484 + }, + { + "name" : "minecraft:dye", + "id" : 666 + }, + { + "name" : "minecraft:echo_shard", + "id" : 653 + }, + { + "name" : "minecraft:egg", + "id" : 391 + }, + { + "name" : "minecraft:elder_guardian_spawn_egg", + "id" : 472 + }, + { + "name" : "minecraft:element_0", + "id" : 36 + }, + { + "name" : "minecraft:element_1", + "id" : -12 + }, + { + "name" : "minecraft:element_10", + "id" : -21 + }, + { + "name" : "minecraft:element_100", + "id" : -111 + }, + { + "name" : "minecraft:element_101", + "id" : -112 + }, + { + "name" : "minecraft:element_102", + "id" : -113 + }, + { + "name" : "minecraft:element_103", + "id" : -114 + }, + { + "name" : "minecraft:element_104", + "id" : -115 + }, + { + "name" : "minecraft:element_105", + "id" : -116 + }, + { + "name" : "minecraft:element_106", + "id" : -117 + }, + { + "name" : "minecraft:element_107", + "id" : -118 + }, + { + "name" : "minecraft:element_108", + "id" : -119 + }, + { + "name" : "minecraft:element_109", + "id" : -120 + }, + { + "name" : "minecraft:element_11", + "id" : -22 + }, + { + "name" : "minecraft:element_110", + "id" : -121 + }, + { + "name" : "minecraft:element_111", + "id" : -122 + }, + { + "name" : "minecraft:element_112", + "id" : -123 + }, + { + "name" : "minecraft:element_113", + "id" : -124 + }, + { + "name" : "minecraft:element_114", + "id" : -125 + }, + { + "name" : "minecraft:element_115", + "id" : -126 + }, + { + "name" : "minecraft:element_116", + "id" : -127 + }, + { + "name" : "minecraft:element_117", + "id" : -128 + }, + { + "name" : "minecraft:element_118", + "id" : -129 + }, + { + "name" : "minecraft:element_12", + "id" : -23 + }, + { + "name" : "minecraft:element_13", + "id" : -24 + }, + { + "name" : "minecraft:element_14", + "id" : -25 + }, + { + "name" : "minecraft:element_15", + "id" : -26 + }, + { + "name" : "minecraft:element_16", + "id" : -27 + }, + { + "name" : "minecraft:element_17", + "id" : -28 + }, + { + "name" : "minecraft:element_18", + "id" : -29 + }, + { + "name" : "minecraft:element_19", + "id" : -30 + }, + { + "name" : "minecraft:element_2", + "id" : -13 + }, + { + "name" : "minecraft:element_20", + "id" : -31 + }, + { + "name" : "minecraft:element_21", + "id" : -32 + }, + { + "name" : "minecraft:element_22", + "id" : -33 + }, + { + "name" : "minecraft:element_23", + "id" : -34 + }, + { + "name" : "minecraft:element_24", + "id" : -35 + }, + { + "name" : "minecraft:element_25", + "id" : -36 + }, + { + "name" : "minecraft:element_26", + "id" : -37 + }, + { + "name" : "minecraft:element_27", + "id" : -38 + }, + { + "name" : "minecraft:element_28", + "id" : -39 + }, + { + "name" : "minecraft:element_29", + "id" : -40 + }, + { + "name" : "minecraft:element_3", + "id" : -14 + }, + { + "name" : "minecraft:element_30", + "id" : -41 + }, + { + "name" : "minecraft:element_31", + "id" : -42 + }, + { + "name" : "minecraft:element_32", + "id" : -43 + }, + { + "name" : "minecraft:element_33", + "id" : -44 + }, + { + "name" : "minecraft:element_34", + "id" : -45 + }, + { + "name" : "minecraft:element_35", + "id" : -46 + }, + { + "name" : "minecraft:element_36", + "id" : -47 + }, + { + "name" : "minecraft:element_37", + "id" : -48 + }, + { + "name" : "minecraft:element_38", + "id" : -49 + }, + { + "name" : "minecraft:element_39", + "id" : -50 + }, + { + "name" : "minecraft:element_4", + "id" : -15 + }, + { + "name" : "minecraft:element_40", + "id" : -51 + }, + { + "name" : "minecraft:element_41", + "id" : -52 + }, + { + "name" : "minecraft:element_42", + "id" : -53 + }, + { + "name" : "minecraft:element_43", + "id" : -54 + }, + { + "name" : "minecraft:element_44", + "id" : -55 + }, + { + "name" : "minecraft:element_45", + "id" : -56 + }, + { + "name" : "minecraft:element_46", + "id" : -57 + }, + { + "name" : "minecraft:element_47", + "id" : -58 + }, + { + "name" : "minecraft:element_48", + "id" : -59 + }, + { + "name" : "minecraft:element_49", + "id" : -60 + }, + { + "name" : "minecraft:element_5", + "id" : -16 + }, + { + "name" : "minecraft:element_50", + "id" : -61 + }, + { + "name" : "minecraft:element_51", + "id" : -62 + }, + { + "name" : "minecraft:element_52", + "id" : -63 + }, + { + "name" : "minecraft:element_53", + "id" : -64 + }, + { + "name" : "minecraft:element_54", + "id" : -65 + }, + { + "name" : "minecraft:element_55", + "id" : -66 + }, + { + "name" : "minecraft:element_56", + "id" : -67 + }, + { + "name" : "minecraft:element_57", + "id" : -68 + }, + { + "name" : "minecraft:element_58", + "id" : -69 + }, + { + "name" : "minecraft:element_59", + "id" : -70 + }, + { + "name" : "minecraft:element_6", + "id" : -17 + }, + { + "name" : "minecraft:element_60", + "id" : -71 + }, + { + "name" : "minecraft:element_61", + "id" : -72 + }, + { + "name" : "minecraft:element_62", + "id" : -73 + }, + { + "name" : "minecraft:element_63", + "id" : -74 + }, + { + "name" : "minecraft:element_64", + "id" : -75 + }, + { + "name" : "minecraft:element_65", + "id" : -76 + }, + { + "name" : "minecraft:element_66", + "id" : -77 + }, + { + "name" : "minecraft:element_67", + "id" : -78 + }, + { + "name" : "minecraft:element_68", + "id" : -79 + }, + { + "name" : "minecraft:element_69", + "id" : -80 + }, + { + "name" : "minecraft:element_7", + "id" : -18 + }, + { + "name" : "minecraft:element_70", + "id" : -81 + }, + { + "name" : "minecraft:element_71", + "id" : -82 + }, + { + "name" : "minecraft:element_72", + "id" : -83 + }, + { + "name" : "minecraft:element_73", + "id" : -84 + }, + { + "name" : "minecraft:element_74", + "id" : -85 + }, + { + "name" : "minecraft:element_75", + "id" : -86 + }, + { + "name" : "minecraft:element_76", + "id" : -87 + }, + { + "name" : "minecraft:element_77", + "id" : -88 + }, + { + "name" : "minecraft:element_78", + "id" : -89 + }, + { + "name" : "minecraft:element_79", + "id" : -90 + }, + { + "name" : "minecraft:element_8", + "id" : -19 + }, + { + "name" : "minecraft:element_80", + "id" : -91 + }, + { + "name" : "minecraft:element_81", + "id" : -92 + }, + { + "name" : "minecraft:element_82", + "id" : -93 + }, + { + "name" : "minecraft:element_83", + "id" : -94 + }, + { + "name" : "minecraft:element_84", + "id" : -95 + }, + { + "name" : "minecraft:element_85", + "id" : -96 + }, + { + "name" : "minecraft:element_86", + "id" : -97 + }, + { + "name" : "minecraft:element_87", + "id" : -98 + }, + { + "name" : "minecraft:element_88", + "id" : -99 + }, + { + "name" : "minecraft:element_89", + "id" : -100 + }, + { + "name" : "minecraft:element_9", + "id" : -20 + }, + { + "name" : "minecraft:element_90", + "id" : -101 + }, + { + "name" : "minecraft:element_91", + "id" : -102 + }, + { + "name" : "minecraft:element_92", + "id" : -103 + }, + { + "name" : "minecraft:element_93", + "id" : -104 + }, + { + "name" : "minecraft:element_94", + "id" : -105 + }, + { + "name" : "minecraft:element_95", + "id" : -106 + }, + { + "name" : "minecraft:element_96", + "id" : -107 + }, + { + "name" : "minecraft:element_97", + "id" : -108 + }, + { + "name" : "minecraft:element_98", + "id" : -109 + }, + { + "name" : "minecraft:element_99", + "id" : -110 + }, + { + "name" : "minecraft:elytra", + "id" : 570 + }, + { + "name" : "minecraft:emerald", + "id" : 518 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:empty_map", + "id" : 521 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 527 + }, + { + "name" : "minecraft:enchanted_golden_apple", + "id" : 259 + }, + { + "name" : "minecraft:enchanting_table", + "id" : 116 + }, + { + "name" : "minecraft:end_brick_stairs", + "id" : -178 + }, + { + "name" : "minecraft:end_bricks", + "id" : 206 + }, + { + "name" : "minecraft:end_crystal", + "id" : 669 + }, + { + "name" : "minecraft:end_gateway", + "id" : 209 + }, + { + "name" : "minecraft:end_portal", + "id" : 119 + }, + { + "name" : "minecraft:end_portal_frame", + "id" : 120 + }, + { + "name" : "minecraft:end_rod", + "id" : 208 + }, + { + "name" : "minecraft:end_stone", + "id" : 121 + }, + { + "name" : "minecraft:ender_chest", + "id" : 130 + }, + { + "name" : "minecraft:ender_dragon_spawn_egg", + "id" : 507 + }, + { + "name" : "minecraft:ender_eye", + "id" : 434 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 423 + }, + { + "name" : "minecraft:enderman_spawn_egg", + "id" : 443 + }, + { + "name" : "minecraft:endermite_spawn_egg", + "id" : 461 + }, + { + "name" : "minecraft:evoker_spawn_egg", + "id" : 476 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 514 + }, + { + "name" : "minecraft:exposed_copper", + "id" : -341 + }, + { + "name" : "minecraft:exposed_cut_copper", + "id" : -348 + }, + { + "name" : "minecraft:exposed_cut_copper_slab", + "id" : -362 + }, + { + "name" : "minecraft:exposed_cut_copper_stairs", + "id" : -355 + }, + { + "name" : "minecraft:exposed_double_cut_copper_slab", + "id" : -369 + }, + { + "name" : "minecraft:farmland", + "id" : 60 + }, + { + "name" : "minecraft:feather", + "id" : 328 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 429 + }, + { + "name" : "minecraft:field_masoned_banner_pattern", + "id" : 591 + }, + { + "name" : "minecraft:filled_map", + "id" : 421 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:fire_charge", + "id" : 515 + }, + { + "name" : "minecraft:firework_rocket", + "id" : 525 + }, + { + "name" : "minecraft:firework_star", + "id" : 526 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 393 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:flint", + "id" : 357 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 300 + }, + { + "name" : "minecraft:flower_banner_pattern", + "id" : 587 + }, + { + "name" : "minecraft:flower_pot", + "id" : 520 + }, + { + "name" : "minecraft:flowering_azalea", + "id" : -338 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:fox_spawn_egg", + "id" : 491 + }, + { + "name" : "minecraft:frame", + "id" : 519 + }, + { + "name" : "minecraft:frog_spawn", + "id" : -468 + }, + { + "name" : "minecraft:frog_spawn_egg", + "id" : 634 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:ghast_spawn_egg", + "id" : 455 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 425 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 428 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:glistering_melon_slice", + "id" : 435 + }, + { + "name" : "minecraft:globe_banner_pattern", + "id" : 594 + }, + { + "name" : "minecraft:glow_berries", + "id" : 670 + }, + { + "name" : "minecraft:glow_frame", + "id" : 629 + }, + { + "name" : "minecraft:glow_ink_sac", + "id" : 509 + }, + { + "name" : "minecraft:glow_lichen", + "id" : -411 + }, + { + "name" : "minecraft:glow_squid_spawn_egg", + "id" : 504 + }, + { + "name" : "minecraft:glow_stick", + "id" : 607 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 395 + }, + { + "name" : "minecraft:goat_horn", + "id" : 633 + }, + { + "name" : "minecraft:goat_spawn_egg", + "id" : 503 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 307 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 426 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:golden_apple", + "id" : 258 + }, + { + "name" : "minecraft:golden_axe", + "id" : 326 + }, + { + "name" : "minecraft:golden_boots", + "id" : 355 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 283 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 353 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 352 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 334 + }, + { + "name" : "minecraft:golden_horse_armor", + "id" : 538 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 354 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 325 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 324 + }, + { + "name" : "minecraft:golden_sword", + "id" : 323 + }, + { + "name" : "minecraft:granite_stairs", + "id" : -169 + }, + { + "name" : "minecraft:grass", + "id" : 2 + }, + { + "name" : "minecraft:grass_path", + "id" : 198 + }, + { + "name" : "minecraft:gravel", + "id" : 13 + }, + { + "name" : "minecraft:gray_candle", + "id" : -420 + }, + { + "name" : "minecraft:gray_candle_cake", + "id" : -437 + }, + { + "name" : "minecraft:gray_dye", + "id" : 404 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:gray_wool", + "id" : -553 + }, + { + "name" : "minecraft:green_candle", + "id" : -426 + }, + { + "name" : "minecraft:green_candle_cake", + "id" : -443 + }, + { + "name" : "minecraft:green_dye", + "id" : 398 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:green_wool", + "id" : -560 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:guardian_spawn_egg", + "id" : 462 + }, + { + "name" : "minecraft:gunpowder", + "id" : 329 + }, + { + "name" : "minecraft:hanging_roots", + "id" : -319 + }, + { + "name" : "minecraft:hard_glass", + "id" : 253 + }, + { + "name" : "minecraft:hard_glass_pane", + "id" : 190 + }, + { + "name" : "minecraft:hard_stained_glass", + "id" : 254 + }, + { + "name" : "minecraft:hard_stained_glass_pane", + "id" : 191 + }, + { + "name" : "minecraft:hardened_clay", + "id" : 172 + }, + { + "name" : "minecraft:hay_block", + "id" : 170 + }, + { + "name" : "minecraft:heart_of_the_sea", + "id" : 577 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:hoglin_spawn_egg", + "id" : 497 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 598 + }, + { + "name" : "minecraft:honeycomb", + "id" : 597 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:hopper", + "id" : 533 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 532 + }, + { + "name" : "minecraft:horse_spawn_egg", + "id" : 459 + }, + { + "name" : "minecraft:husk_spawn_egg", + "id" : 464 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 601 + }, + { + "name" : "minecraft:infested_deepslate", + "id" : -454 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:ink_sac", + "id" : 414 + }, + { + "name" : "minecraft:invisible_bedrock", + "id" : 95 + }, + { + "name" : "minecraft:iron_axe", + "id" : 299 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:iron_boots", + "id" : 347 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 345 + }, + { + "name" : "minecraft:iron_door", + "id" : 373 + }, + { + "name" : "minecraft:iron_golem_spawn_egg", + "id" : 505 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 344 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 332 + }, + { + "name" : "minecraft:iron_horse_armor", + "id" : 537 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 306 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 346 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 575 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 298 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 297 + }, + { + "name" : "minecraft:iron_sword", + "id" : 308 + }, + { + "name" : "minecraft:iron_trapdoor", + "id" : 167 + }, + { + "name" : "minecraft:item.acacia_door", + "id" : 196 + }, + { + "name" : "minecraft:item.bed", + "id" : 26 + }, + { + "name" : "minecraft:item.beetroot", + "id" : 244 + }, + { + "name" : "minecraft:item.birch_door", + "id" : 194 + }, + { + "name" : "minecraft:item.brewing_stand", + "id" : 117 + }, + { + "name" : "minecraft:item.cake", + "id" : 92 + }, + { + "name" : "minecraft:item.camera", + "id" : 242 + }, + { + "name" : "minecraft:item.campfire", + "id" : -209 + }, + { + "name" : "minecraft:item.cauldron", + "id" : 118 + }, + { + "name" : "minecraft:item.chain", + "id" : -286 + }, + { + "name" : "minecraft:item.crimson_door", + "id" : -244 + }, + { + "name" : "minecraft:item.dark_oak_door", + "id" : 197 + }, + { + "name" : "minecraft:item.flower_pot", + "id" : 140 + }, + { + "name" : "minecraft:item.frame", + "id" : 199 + }, + { + "name" : "minecraft:item.glow_frame", + "id" : -339 + }, + { + "name" : "minecraft:item.hopper", + "id" : 154 + }, + { + "name" : "minecraft:item.iron_door", + "id" : 71 + }, + { + "name" : "minecraft:item.jungle_door", + "id" : 195 + }, + { + "name" : "minecraft:item.kelp", + "id" : -138 + }, + { + "name" : "minecraft:item.mangrove_door", + "id" : -493 + }, + { + "name" : "minecraft:item.nether_sprouts", + "id" : -238 + }, + { + "name" : "minecraft:item.nether_wart", + "id" : 115 + }, + { + "name" : "minecraft:item.reeds", + "id" : 83 + }, + { + "name" : "minecraft:item.skull", + "id" : 144 + }, + { + "name" : "minecraft:item.soul_campfire", + "id" : -290 + }, + { + "name" : "minecraft:item.spruce_door", + "id" : 193 + }, + { + "name" : "minecraft:item.warped_door", + "id" : -245 + }, + { + "name" : "minecraft:item.wheat", + "id" : 59 + }, + { + "name" : "minecraft:item.wooden_door", + "id" : 64 + }, + { + "name" : "minecraft:jigsaw", + "id" : -211 + }, + { + "name" : "minecraft:jukebox", + "id" : 84 + }, + { + "name" : "minecraft:jungle_boat", + "id" : 378 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:jungle_chest_boat", + "id" : 646 + }, + { + "name" : "minecraft:jungle_door", + "id" : 561 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:jungle_hanging_sign", + "id" : -503 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 584 + }, + { + "name" : "minecraft:jungle_stairs", + "id" : 136 + }, + { + "name" : "minecraft:jungle_standing_sign", + "id" : -188 + }, + { + "name" : "minecraft:jungle_trapdoor", + "id" : -148 + }, + { + "name" : "minecraft:jungle_wall_sign", + "id" : -189 + }, + { + "name" : "minecraft:kelp", + "id" : 383 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:lapis_lazuli", + "id" : 415 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:large_amethyst_bud", + "id" : -330 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:lava_bucket", + "id" : 364 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:lead", + "id" : 553 + }, + { + "name" : "minecraft:leather", + "id" : 382 + }, + { + "name" : "minecraft:leather_boots", + "id" : 339 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 337 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 336 + }, + { + "name" : "minecraft:leather_horse_armor", + "id" : 536 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 338 + }, + { + "name" : "minecraft:leaves", + "id" : 18 + }, + { + "name" : "minecraft:leaves2", + "id" : 161 + }, + { + "name" : "minecraft:lectern", + "id" : -194 + }, + { + "name" : "minecraft:lever", + "id" : 69 + }, + { + "name" : "minecraft:light_block", + "id" : -215 + }, + { + "name" : "minecraft:light_blue_candle", + "id" : -416 + }, + { + "name" : "minecraft:light_blue_candle_cake", + "id" : -433 + }, + { + "name" : "minecraft:light_blue_dye", + "id" : 408 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:light_blue_wool", + "id" : -562 + }, + { + "name" : "minecraft:light_gray_candle", + "id" : -421 + }, + { + "name" : "minecraft:light_gray_candle_cake", + "id" : -438 + }, + { + "name" : "minecraft:light_gray_dye", + "id" : 403 + }, + { + "name" : "minecraft:light_gray_wool", + "id" : -552 + }, + { + "name" : "minecraft:light_weighted_pressure_plate", + "id" : 147 + }, + { + "name" : "minecraft:lightning_rod", + "id" : -312 + }, + { + "name" : "minecraft:lime_candle", + "id" : -418 + }, + { + "name" : "minecraft:lime_candle_cake", + "id" : -435 + }, + { + "name" : "minecraft:lime_dye", + "id" : 406 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:lime_wool", + "id" : -559 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 568 + }, + { + "name" : "minecraft:lit_blast_furnace", + "id" : -214 + }, + { + "name" : "minecraft:lit_deepslate_redstone_ore", + "id" : -404 + }, + { + "name" : "minecraft:lit_furnace", + "id" : 62 + }, + { + "name" : "minecraft:lit_pumpkin", + "id" : 91 + }, + { + "name" : "minecraft:lit_redstone_lamp", + "id" : 124 + }, + { + "name" : "minecraft:lit_redstone_ore", + "id" : 74 + }, + { + "name" : "minecraft:lit_smoker", + "id" : -199 + }, + { + "name" : "minecraft:llama_spawn_egg", + "id" : 474 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:lodestone_compass", + "id" : 608 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:magenta_candle", + "id" : -415 + }, + { + "name" : "minecraft:magenta_candle_cake", + "id" : -432 + }, + { + "name" : "minecraft:magenta_dye", + "id" : 409 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:magenta_wool", + "id" : -565 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:magma_cream", + "id" : 431 + }, + { + "name" : "minecraft:magma_cube_spawn_egg", + "id" : 456 + }, + { + "name" : "minecraft:mangrove_boat", + "id" : 641 + }, + { + "name" : "minecraft:mangrove_button", + "id" : -487 + }, + { + "name" : "minecraft:mangrove_chest_boat", + "id" : 650 + }, + { + "name" : "minecraft:mangrove_door", + "id" : 639 + }, + { + "name" : "minecraft:mangrove_double_slab", + "id" : -499 + }, + { + "name" : "minecraft:mangrove_fence", + "id" : -491 + }, + { + "name" : "minecraft:mangrove_fence_gate", + "id" : -492 + }, + { + "name" : "minecraft:mangrove_hanging_sign", + "id" : -508 + }, + { + "name" : "minecraft:mangrove_leaves", + "id" : -472 + }, + { + "name" : "minecraft:mangrove_log", + "id" : -484 + }, + { + "name" : "minecraft:mangrove_planks", + "id" : -486 + }, + { + "name" : "minecraft:mangrove_pressure_plate", + "id" : -490 + }, + { + "name" : "minecraft:mangrove_propagule", + "id" : -474 + }, + { + "name" : "minecraft:mangrove_roots", + "id" : -482 + }, + { + "name" : "minecraft:mangrove_sign", + "id" : 640 + }, + { + "name" : "minecraft:mangrove_slab", + "id" : -489 + }, + { + "name" : "minecraft:mangrove_stairs", + "id" : -488 + }, + { + "name" : "minecraft:mangrove_standing_sign", + "id" : -494 + }, + { + "name" : "minecraft:mangrove_trapdoor", + "id" : -496 + }, + { + "name" : "minecraft:mangrove_wall_sign", + "id" : -495 + }, + { + "name" : "minecraft:mangrove_wood", + "id" : -497 + }, + { + "name" : "minecraft:medicine", + "id" : 605 + }, + { + "name" : "minecraft:medium_amethyst_bud", + "id" : -331 + }, + { + "name" : "minecraft:melon_block", + "id" : 103 + }, + { + "name" : "minecraft:melon_seeds", + "id" : 293 + }, + { + "name" : "minecraft:melon_slice", + "id" : 272 + }, + { + "name" : "minecraft:melon_stem", + "id" : 105 + }, + { + "name" : "minecraft:milk_bucket", + "id" : 362 + }, + { + "name" : "minecraft:minecart", + "id" : 371 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:mojang_banner_pattern", + "id" : 590 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:mooshroom_spawn_egg", + "id" : 441 + }, + { + "name" : "minecraft:moss_block", + "id" : -320 + }, + { + "name" : "minecraft:moss_carpet", + "id" : -335 + }, + { + "name" : "minecraft:mossy_cobblestone", + "id" : 48 + }, + { + "name" : "minecraft:mossy_cobblestone_stairs", + "id" : -179 + }, + { + "name" : "minecraft:mossy_stone_brick_stairs", + "id" : -175 + }, + { + "name" : "minecraft:moving_block", + "id" : 250 + }, + { + "name" : "minecraft:mud", + "id" : -473 + }, + { + "name" : "minecraft:mud_brick_double_slab", + "id" : -479 + }, + { + "name" : "minecraft:mud_brick_slab", + "id" : -478 + }, + { + "name" : "minecraft:mud_brick_stairs", + "id" : -480 + }, + { + "name" : "minecraft:mud_brick_wall", + "id" : -481 + }, + { + "name" : "minecraft:mud_bricks", + "id" : -475 + }, + { + "name" : "minecraft:muddy_mangrove_roots", + "id" : -483 + }, + { + "name" : "minecraft:mule_spawn_egg", + "id" : 467 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 260 + }, + { + "name" : "minecraft:music_disc_11", + "id" : 550 + }, + { + "name" : "minecraft:music_disc_13", + "id" : 540 + }, + { + "name" : "minecraft:music_disc_5", + "id" : 642 + }, + { + "name" : "minecraft:music_disc_blocks", + "id" : 542 + }, + { + "name" : "minecraft:music_disc_cat", + "id" : 541 + }, + { + "name" : "minecraft:music_disc_chirp", + "id" : 543 + }, + { + "name" : "minecraft:music_disc_far", + "id" : 544 + }, + { + "name" : "minecraft:music_disc_mall", + "id" : 545 + }, + { + "name" : "minecraft:music_disc_mellohi", + "id" : 546 + }, + { + "name" : "minecraft:music_disc_otherside", + "id" : 632 + }, + { + "name" : "minecraft:music_disc_pigstep", + "id" : 626 + }, + { + "name" : "minecraft:music_disc_stal", + "id" : 547 + }, + { + "name" : "minecraft:music_disc_strad", + "id" : 548 + }, + { + "name" : "minecraft:music_disc_wait", + "id" : 551 + }, + { + "name" : "minecraft:music_disc_ward", + "id" : 549 + }, + { + "name" : "minecraft:mutton", + "id" : 556 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:name_tag", + "id" : 554 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 576 + }, + { + "name" : "minecraft:nether_brick", + "id" : 112 + }, + { + "name" : "minecraft:nether_brick_fence", + "id" : 113 + }, + { + "name" : "minecraft:nether_brick_stairs", + "id" : 114 + }, + { + "name" : "minecraft:nether_gold_ore", + "id" : -288 + }, + { + "name" : "minecraft:nether_sprouts", + "id" : 627 + }, + { + "name" : "minecraft:nether_star", + "id" : 524 + }, + { + "name" : "minecraft:nether_wart", + "id" : 294 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:netherbrick", + "id" : 529 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 613 + }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 618 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 616 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 615 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 614 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 609 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 617 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 612 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 619 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 611 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 610 + }, + { + "name" : "minecraft:netherrack", + "id" : 87 + }, + { + "name" : "minecraft:netherreactor", + "id" : 247 + }, + { + "name" : "minecraft:normal_stone_stairs", + "id" : -180 + }, + { + "name" : "minecraft:noteblock", + "id" : 25 + }, + { + "name" : "minecraft:npc_spawn_egg", + "id" : 471 + }, + { + "name" : "minecraft:oak_boat", + "id" : 376 + }, + { + "name" : "minecraft:oak_chest_boat", + "id" : 644 + }, + { + "name" : "minecraft:oak_hanging_sign", + "id" : -500 + }, + { + "name" : "minecraft:oak_sign", + "id" : 359 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:ocelot_spawn_egg", + "id" : 452 + }, + { + "name" : "minecraft:ochre_froglight", + "id" : -471 + }, + { + "name" : "minecraft:orange_candle", + "id" : -414 + }, + { + "name" : "minecraft:orange_candle_cake", + "id" : -431 + }, + { + "name" : "minecraft:orange_dye", + "id" : 410 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "name" : "minecraft:orange_wool", + "id" : -557 + }, + { + "name" : "minecraft:oxidized_copper", + "id" : -343 + }, + { + "name" : "minecraft:oxidized_cut_copper", + "id" : -350 + }, + { + "name" : "minecraft:oxidized_cut_copper_slab", + "id" : -364 + }, + { + "name" : "minecraft:oxidized_cut_copper_stairs", + "id" : -357 + }, + { + "name" : "minecraft:oxidized_double_cut_copper_slab", + "id" : -371 + }, + { + "name" : "minecraft:packed_ice", + "id" : 174 + }, + { + "name" : "minecraft:packed_mud", + "id" : -477 + }, + { + "name" : "minecraft:painting", + "id" : 358 + }, + { + "name" : "minecraft:panda_spawn_egg", + "id" : 490 + }, + { + "name" : "minecraft:paper", + "id" : 387 + }, + { + "name" : "minecraft:parrot_spawn_egg", + "id" : 479 + }, + { + "name" : "minecraft:pearlescent_froglight", + "id" : -469 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 580 + }, + { + "name" : "minecraft:phantom_spawn_egg", + "id" : 487 + }, + { + "name" : "minecraft:pig_spawn_egg", + "id" : 438 + }, + { + "name" : "minecraft:piglin_banner_pattern", + "id" : 593 + }, + { + "name" : "minecraft:piglin_brute_spawn_egg", + "id" : 500 + }, + { + "name" : "minecraft:piglin_spawn_egg", + "id" : 498 + }, + { + "name" : "minecraft:pillager_spawn_egg", + "id" : 492 + }, + { + "name" : "minecraft:pink_candle", + "id" : -419 + }, + { + "name" : "minecraft:pink_candle_cake", + "id" : -436 + }, + { + "name" : "minecraft:pink_dye", + "id" : 405 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:pink_wool", + "id" : -566 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:piston_arm_collision", + "id" : 34 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:pointed_dripstone", + "id" : -308 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 282 + }, + { + "name" : "minecraft:polar_bear_spawn_egg", + "id" : 473 + }, + { + "name" : "minecraft:polished_andesite_stairs", + "id" : -174 + }, + { + "name" : "minecraft:polished_basalt", + "id" : -235 + }, + { + "name" : "minecraft:polished_blackstone", + "id" : -291 + }, + { + "name" : "minecraft:polished_blackstone_brick_double_slab", + "id" : -285 + }, + { + "name" : "minecraft:polished_blackstone_brick_slab", + "id" : -284 + }, + { + "name" : "minecraft:polished_blackstone_brick_stairs", + "id" : -275 + }, + { + "name" : "minecraft:polished_blackstone_brick_wall", + "id" : -278 + }, + { + "name" : "minecraft:polished_blackstone_bricks", + "id" : -274 + }, + { + "name" : "minecraft:polished_blackstone_button", + "id" : -296 + }, + { + "name" : "minecraft:polished_blackstone_double_slab", + "id" : -294 + }, + { + "name" : "minecraft:polished_blackstone_pressure_plate", + "id" : -295 + }, + { + "name" : "minecraft:polished_blackstone_slab", + "id" : -293 + }, + { + "name" : "minecraft:polished_blackstone_stairs", + "id" : -292 + }, + { + "name" : "minecraft:polished_blackstone_wall", + "id" : -297 + }, + { + "name" : "minecraft:polished_deepslate", + "id" : -383 + }, + { + "name" : "minecraft:polished_deepslate_double_slab", + "id" : -397 + }, + { + "name" : "minecraft:polished_deepslate_slab", + "id" : -384 + }, + { + "name" : "minecraft:polished_deepslate_stairs", + "id" : -385 + }, + { + "name" : "minecraft:polished_deepslate_wall", + "id" : -386 + }, + { + "name" : "minecraft:polished_diorite_stairs", + "id" : -173 + }, + { + "name" : "minecraft:polished_granite_stairs", + "id" : -172 + }, + { + "name" : "minecraft:popped_chorus_fruit", + "id" : 565 + }, + { + "name" : "minecraft:porkchop", + "id" : 262 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:potato", + "id" : 280 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:potion", + "id" : 427 + }, + { + "name" : "minecraft:powder_snow", + "id" : -306 + }, + { + "name" : "minecraft:powder_snow_bucket", + "id" : 369 + }, + { + "name" : "minecraft:powered_comparator", + "id" : 150 + }, + { + "name" : "minecraft:powered_repeater", + "id" : 94 + }, + { + "name" : "minecraft:prismarine", + "id" : 168 + }, + { + "name" : "minecraft:prismarine_bricks_stairs", + "id" : -4 + }, + { + "name" : "minecraft:prismarine_crystals", + "id" : 555 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 571 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:prize_pottery_shard", + "id" : 661 + }, + { + "name" : "minecraft:pufferfish", + "id" : 267 + }, + { + "name" : "minecraft:pufferfish_bucket", + "id" : 368 + }, + { + "name" : "minecraft:pufferfish_spawn_egg", + "id" : 482 + }, + { + "name" : "minecraft:pumpkin", + "id" : 86 + }, + { + "name" : "minecraft:pumpkin_pie", + "id" : 284 + }, + { + "name" : "minecraft:pumpkin_seeds", + "id" : 292 + }, + { + "name" : "minecraft:pumpkin_stem", + "id" : 104 + }, + { + "name" : "minecraft:purple_candle", + "id" : -423 + }, + { + "name" : "minecraft:purple_candle_cake", + "id" : -440 + }, + { + "name" : "minecraft:purple_dye", + "id" : 401 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:purple_wool", + "id" : -564 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:quartz", + "id" : 530 + }, + { + "name" : "minecraft:quartz_block", + "id" : 155 + }, + { + "name" : "minecraft:quartz_bricks", + "id" : -304 + }, + { + "name" : "minecraft:quartz_ore", + "id" : 153 + }, + { + "name" : "minecraft:quartz_stairs", + "id" : 156 + }, + { + "name" : "minecraft:rabbit", + "id" : 288 + }, + { + "name" : "minecraft:rabbit_foot", + "id" : 534 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 535 + }, + { + "name" : "minecraft:rabbit_spawn_egg", + "id" : 460 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 290 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 603 + }, + { + "name" : "minecraft:ravager_spawn_egg", + "id" : 494 + }, + { + "name" : "minecraft:raw_copper", + "id" : 513 + }, + { + "name" : "minecraft:raw_copper_block", + "id" : -452 + }, + { + "name" : "minecraft:raw_gold", + "id" : 512 + }, + { + "name" : "minecraft:raw_gold_block", + "id" : -453 + }, + { + "name" : "minecraft:raw_iron", + "id" : 511 + }, + { + "name" : "minecraft:raw_iron_block", + "id" : -451 + }, + { + "name" : "minecraft:recovery_compass", + "id" : 652 + }, + { + "name" : "minecraft:red_candle", + "id" : -427 + }, + { + "name" : "minecraft:red_candle_cake", + "id" : -444 + }, + { + "name" : "minecraft:red_dye", + "id" : 397 + }, + { + "name" : "minecraft:red_flower", + "id" : 38 + }, + { + "name" : "minecraft:red_glazed_terracotta", + "id" : 234 + }, + { + "name" : "minecraft:red_mushroom", + "id" : 40 + }, + { + "name" : "minecraft:red_mushroom_block", + "id" : 100 + }, + { + "name" : "minecraft:red_nether_brick", + "id" : 215 + }, + { + "name" : "minecraft:red_nether_brick_stairs", + "id" : -184 + }, + { + "name" : "minecraft:red_sandstone", + "id" : 179 + }, + { + "name" : "minecraft:red_sandstone_stairs", + "id" : 180 + }, + { + "name" : "minecraft:red_wool", + "id" : -556 + }, + { + "name" : "minecraft:redstone", + "id" : 374 + }, + { + "name" : "minecraft:redstone_block", + "id" : 152 + }, + { + "name" : "minecraft:redstone_lamp", + "id" : 123 + }, + { + "name" : "minecraft:redstone_ore", + "id" : 73 + }, + { + "name" : "minecraft:redstone_torch", + "id" : 76 + }, + { + "name" : "minecraft:redstone_wire", + "id" : 55 + }, + { + "name" : "minecraft:reinforced_deepslate", + "id" : -466 + }, + { + "name" : "minecraft:repeater", + "id" : 420 + }, + { + "name" : "minecraft:repeating_command_block", + "id" : 188 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:respawn_anchor", + "id" : -272 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 277 + }, + { + "name" : "minecraft:saddle", + "id" : 372 + }, + { + "name" : "minecraft:salmon", + "id" : 265 + }, + { + "name" : "minecraft:salmon_bucket", + "id" : 366 + }, + { + "name" : "minecraft:salmon_spawn_egg", + "id" : 483 + }, + { + "name" : "minecraft:sand", + "id" : 12 + }, + { + "name" : "minecraft:sandstone", + "id" : 24 + }, + { + "name" : "minecraft:sandstone_stairs", + "id" : 128 + }, + { + "name" : "minecraft:sapling", + "id" : 6 + }, + { + "name" : "minecraft:scaffolding", + "id" : -165 + }, + { + "name" : "minecraft:sculk", + "id" : -458 + }, + { + "name" : "minecraft:sculk_catalyst", + "id" : -460 + }, + { + "name" : "minecraft:sculk_sensor", + "id" : -307 + }, + { + "name" : "minecraft:sculk_shrieker", + "id" : -461 + }, + { + "name" : "minecraft:sculk_vein", + "id" : -459 + }, + { + "name" : "minecraft:scute", + "id" : 578 + }, + { + "name" : "minecraft:sea_lantern", + "id" : 169 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:shears", + "id" : 422 + }, + { + "name" : "minecraft:sheep_spawn_egg", + "id" : 439 + }, + { + "name" : "minecraft:shield", + "id" : 356 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 572 + }, + { + "name" : "minecraft:shulker_spawn_egg", + "id" : 470 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:silverfish_spawn_egg", + "id" : 444 + }, + { + "name" : "minecraft:skeleton_horse_spawn_egg", + "id" : 468 + }, + { + "name" : "minecraft:skeleton_spawn_egg", + "id" : 445 + }, + { + "name" : "minecraft:skull", + "id" : 522 + }, + { + "name" : "minecraft:skull_banner_pattern", + "id" : 589 + }, + { + "name" : "minecraft:skull_pottery_shard", + "id" : 662 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:slime_ball", + "id" : 389 + }, + { + "name" : "minecraft:slime_spawn_egg", + "id" : 446 + }, + { + "name" : "minecraft:small_amethyst_bud", + "id" : -332 + }, + { + "name" : "minecraft:small_dripleaf_block", + "id" : -336 + }, + { + "name" : "minecraft:smithing_table", + "id" : -202 + }, + { + "name" : "minecraft:smoker", + "id" : -198 + }, + { + "name" : "minecraft:smooth_basalt", + "id" : -377 + }, + { + "name" : "minecraft:smooth_quartz_stairs", + "id" : -185 + }, + { + "name" : "minecraft:smooth_red_sandstone_stairs", + "id" : -176 + }, + { + "name" : "minecraft:smooth_sandstone_stairs", + "id" : -177 + }, + { + "name" : "minecraft:smooth_stone", + "id" : -183 + }, + { + "name" : "minecraft:sniffer_spawn_egg", + "id" : 501 + }, + { + "name" : "minecraft:snow", + "id" : 80 + }, + { + "name" : "minecraft:snow_golem_spawn_egg", + "id" : 506 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:snowball", + "id" : 375 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 628 + }, + { + "name" : "minecraft:soul_fire", + "id" : -237 + }, + { + "name" : "minecraft:soul_lantern", + "id" : -269 + }, + { + "name" : "minecraft:soul_sand", + "id" : 88 + }, + { + "name" : "minecraft:soul_soil", + "id" : -236 + }, + { + "name" : "minecraft:soul_torch", + "id" : -268 + }, + { + "name" : "minecraft:sparkler", + "id" : 606 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 668 + }, + { + "name" : "minecraft:spider_eye", + "id" : 278 + }, + { + "name" : "minecraft:spider_spawn_egg", + "id" : 447 + }, + { + "name" : "minecraft:splash_potion", + "id" : 567 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:spore_blossom", + "id" : -321 + }, + { + "name" : "minecraft:spruce_boat", + "id" : 379 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:spruce_chest_boat", + "id" : 647 + }, + { + "name" : "minecraft:spruce_door", + "id" : 559 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:spruce_hanging_sign", + "id" : -501 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 582 + }, + { + "name" : "minecraft:spruce_stairs", + "id" : 134 + }, + { + "name" : "minecraft:spruce_standing_sign", + "id" : -181 + }, + { + "name" : "minecraft:spruce_trapdoor", + "id" : -149 + }, + { + "name" : "minecraft:spruce_wall_sign", + "id" : -182 + }, + { + "name" : "minecraft:spyglass", + "id" : 631 + }, + { + "name" : "minecraft:squid_spawn_egg", + "id" : 451 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:standing_sign", + "id" : 63 + }, + { + "name" : "minecraft:stick", + "id" : 321 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:sticky_piston_arm_collision", + "id" : -217 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:stone_axe", + "id" : 316 + }, + { + "name" : "minecraft:stone_block_slab", + "id" : 44 + }, + { + "name" : "minecraft:stone_block_slab2", + "id" : 182 + }, + { + "name" : "minecraft:stone_block_slab3", + "id" : -162 + }, + { + "name" : "minecraft:stone_block_slab4", + "id" : -166 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 331 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 315 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 314 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:stone_sword", + "id" : 313 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:stray_spawn_egg", + "id" : 463 + }, + { + "name" : "minecraft:strider_spawn_egg", + "id" : 496 + }, + { + "name" : "minecraft:string", + "id" : 327 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:stripped_bamboo_block", + "id" : -528 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "name" : "minecraft:stripped_crimson_hyphae", + "id" : -300 + }, + { + "name" : "minecraft:stripped_crimson_stem", + "id" : -240 + }, + { + "name" : "minecraft:stripped_dark_oak_log", + "id" : -9 + }, + { + "name" : "minecraft:stripped_jungle_log", + "id" : -7 + }, + { + "name" : "minecraft:stripped_mangrove_log", + "id" : -485 + }, + { + "name" : "minecraft:stripped_mangrove_wood", + "id" : -498 + }, + { + "name" : "minecraft:stripped_oak_log", + "id" : -10 + }, + { + "name" : "minecraft:stripped_spruce_log", + "id" : -5 + }, + { + "name" : "minecraft:stripped_warped_hyphae", + "id" : -301 + }, + { + "name" : "minecraft:stripped_warped_stem", + "id" : -241 + }, + { + "name" : "minecraft:structure_block", + "id" : 252 + }, + { + "name" : "minecraft:structure_void", + "id" : 217 + }, + { + "name" : "minecraft:sugar", + "id" : 417 + }, + { + "name" : "minecraft:sugar_cane", + "id" : 386 + }, + { + "name" : "minecraft:suspicious_sand", + "id" : -529 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 596 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 287 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "name" : "minecraft:tadpole_bucket", + "id" : 636 + }, + { + "name" : "minecraft:tadpole_spawn_egg", + "id" : 635 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:target", + "id" : -239 + }, + { + "name" : "minecraft:tinted_glass", + "id" : -334 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 531 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:torchflower", + "id" : -568 + }, + { + "name" : "minecraft:torchflower_crop", + "id" : -567 + }, + { + "name" : "minecraft:torchflower_seeds", + "id" : 296 + }, + { + "name" : "minecraft:totem_of_undying", + "id" : 574 + }, + { + "name" : "minecraft:trader_llama_spawn_egg", + "id" : 654 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:trident", + "id" : 552 + }, + { + "name" : "minecraft:trip_wire", + "id" : 132 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:tropical_fish", + "id" : 266 + }, + { + "name" : "minecraft:tropical_fish_bucket", + "id" : 367 + }, + { + "name" : "minecraft:tropical_fish_spawn_egg", + "id" : 480 + }, + { + "name" : "minecraft:tuff", + "id" : -333 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 579 + }, + { + "name" : "minecraft:turtle_spawn_egg", + "id" : 486 + }, + { + "name" : "minecraft:twisting_vines", + "id" : -287 + }, + { + "name" : "minecraft:underwater_torch", + "id" : 239 + }, + { + "name" : "minecraft:undyed_shulker_box", + "id" : 205 + }, + { + "name" : "minecraft:unknown", + "id" : -305 + }, + { + "name" : "minecraft:unlit_redstone_torch", + "id" : 75 + }, + { + "name" : "minecraft:unpowered_comparator", + "id" : 149 + }, + { + "name" : "minecraft:unpowered_repeater", + "id" : 93 + }, + { + "name" : "minecraft:verdant_froglight", + "id" : -470 + }, + { + "name" : "minecraft:vex_spawn_egg", + "id" : 477 + }, + { + "name" : "minecraft:villager_spawn_egg", + "id" : 450 + }, + { + "name" : "minecraft:vindicator_spawn_egg", + "id" : 475 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:wandering_trader_spawn_egg", + "id" : 493 + }, + { + "name" : "minecraft:warden_spawn_egg", + "id" : 638 + }, + { + "name" : "minecraft:warped_button", + "id" : -261 + }, + { + "name" : "minecraft:warped_door", + "id" : 623 + }, + { + "name" : "minecraft:warped_double_slab", + "id" : -267 + }, + { + "name" : "minecraft:warped_fence", + "id" : -257 + }, + { + "name" : "minecraft:warped_fence_gate", + "id" : -259 + }, + { + "name" : "minecraft:warped_fungus", + "id" : -229 + }, + { + "name" : "minecraft:warped_fungus_on_a_stick", + "id" : 624 + }, + { + "name" : "minecraft:warped_hanging_sign", + "id" : -507 + }, + { + "name" : "minecraft:warped_hyphae", + "id" : -298 + }, + { + "name" : "minecraft:warped_nylium", + "id" : -233 + }, + { + "name" : "minecraft:warped_planks", + "id" : -243 + }, + { + "name" : "minecraft:warped_pressure_plate", + "id" : -263 + }, + { + "name" : "minecraft:warped_roots", + "id" : -224 + }, + { + "name" : "minecraft:warped_sign", + "id" : 621 + }, + { + "name" : "minecraft:warped_slab", + "id" : -265 + }, + { + "name" : "minecraft:warped_stairs", + "id" : -255 + }, + { + "name" : "minecraft:warped_standing_sign", + "id" : -251 + }, + { + "name" : "minecraft:warped_stem", + "id" : -226 + }, + { + "name" : "minecraft:warped_trapdoor", + "id" : -247 + }, + { + "name" : "minecraft:warped_wall_sign", + "id" : -253 + }, + { + "name" : "minecraft:warped_wart_block", + "id" : -227 + }, + { + "name" : "minecraft:water", + "id" : 9 + }, + { + "name" : "minecraft:water_bucket", + "id" : 363 + }, + { + "name" : "minecraft:waterlily", + "id" : 111 + }, + { + "name" : "minecraft:waxed_copper", + "id" : -344 + }, + { + "name" : "minecraft:waxed_cut_copper", + "id" : -351 + }, + { + "name" : "minecraft:waxed_cut_copper_slab", + "id" : -365 + }, + { + "name" : "minecraft:waxed_cut_copper_stairs", + "id" : -358 + }, + { + "name" : "minecraft:waxed_double_cut_copper_slab", + "id" : -372 + }, + { + "name" : "minecraft:waxed_exposed_copper", + "id" : -345 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper", + "id" : -352 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_slab", + "id" : -366 + }, + { + "name" : "minecraft:waxed_exposed_cut_copper_stairs", + "id" : -359 + }, + { + "name" : "minecraft:waxed_exposed_double_cut_copper_slab", + "id" : -373 + }, + { + "name" : "minecraft:waxed_oxidized_copper", + "id" : -446 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper", + "id" : -447 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_slab", + "id" : -449 + }, + { + "name" : "minecraft:waxed_oxidized_cut_copper_stairs", + "id" : -448 + }, + { + "name" : "minecraft:waxed_oxidized_double_cut_copper_slab", + "id" : -450 + }, + { + "name" : "minecraft:waxed_weathered_copper", + "id" : -346 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper", + "id" : -353 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_slab", + "id" : -367 + }, + { + "name" : "minecraft:waxed_weathered_cut_copper_stairs", + "id" : -360 + }, + { + "name" : "minecraft:waxed_weathered_double_cut_copper_slab", + "id" : -374 + }, + { + "name" : "minecraft:weathered_copper", + "id" : -342 + }, + { + "name" : "minecraft:weathered_cut_copper", + "id" : -349 + }, + { + "name" : "minecraft:weathered_cut_copper_slab", + "id" : -363 + }, + { + "name" : "minecraft:weathered_cut_copper_stairs", + "id" : -356 + }, + { + "name" : "minecraft:weathered_double_cut_copper_slab", + "id" : -370 + }, + { + "name" : "minecraft:web", + "id" : 30 + }, + { + "name" : "minecraft:weeping_vines", + "id" : -231 + }, + { + "name" : "minecraft:wheat", + "id" : 335 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 291 + }, + { + "name" : "minecraft:white_candle", + "id" : -413 + }, + { + "name" : "minecraft:white_candle_cake", + "id" : -430 + }, + { + "name" : "minecraft:white_dye", + "id" : 411 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:white_wool", + "id" : 35 + }, + { + "name" : "minecraft:witch_spawn_egg", + "id" : 453 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:wither_skeleton_spawn_egg", + "id" : 465 + }, + { + "name" : "minecraft:wither_spawn_egg", + "id" : 508 + }, + { + "name" : "minecraft:wolf_spawn_egg", + "id" : 440 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 312 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:wooden_door", + "id" : 360 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 330 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 311 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 310 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 309 + }, + { + "name" : "minecraft:wool", + "id" : 664 + }, + { + "name" : "minecraft:writable_book", + "id" : 516 + }, + { + "name" : "minecraft:written_book", + "id" : 517 + }, + { + "name" : "minecraft:yellow_candle", + "id" : -417 + }, + { + "name" : "minecraft:yellow_candle_cake", + "id" : -434 + }, + { + "name" : "minecraft:yellow_dye", + "id" : 407 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:yellow_wool", + "id" : -558 + }, + { + "name" : "minecraft:zoglin_spawn_egg", + "id" : 499 + }, + { + "name" : "minecraft:zombie_horse_spawn_egg", + "id" : 469 + }, + { + "name" : "minecraft:zombie_pigman_spawn_egg", + "id" : 449 + }, + { + "name" : "minecraft:zombie_spawn_egg", + "id" : 448 + }, + { + "name" : "minecraft:zombie_villager_spawn_egg", + "id" : 478 + } +] \ No newline at end of file diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index eb5b7e73c..421ad4c1c 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -130,10 +130,6 @@ show-coordinates: true # Whether Bedrock players are blocked from performing their scaffolding-style bridging. disable-bedrock-scaffolding: false -# Whether Bedrock players can right-click outside of their inventory to replace armor in their inventory, even if the -# armor slot is already occupied (which Java Edition doesn't allow) -always-quick-change-armor: false - # If set, when a Bedrock player performs any emote, it will swap the offhand and mainhand items, just like the Java Edition keybind # There are three options this can be set to: # disabled - the default/fallback, which doesn't apply this workaround diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 84333403e..f5cb8134c 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 84333403e7884306efa44c369e9cea216711c32a +Subproject commit f5cb8134c4a9a164c75775ee3cc67a9a661dae4e diff --git a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java index e83c6f73d..a804916fa 100644 --- a/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java +++ b/core/src/test/java/org/geysermc/geyser/network/translators/chat/MessageTranslatorTest.java @@ -27,18 +27,20 @@ package org.geysermc.geyser.network.translators.chat; import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import java.util.HashMap; import java.util.Map; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class MessageTranslatorTest { private Map messages = new HashMap<>(); - @Before + @BeforeAll public void setUp() throws Exception { messages.put("{\"text\":\"\",\"extra\":[{\"text\":\"DoctorMad9952 joined the game\",\"color\":\"yellow\"}]}", "§r§eDoctorMad9952 joined the game"); @@ -70,27 +72,27 @@ public class MessageTranslatorTest { public void convertMessage() { for (Map.Entry entry : messages.entrySet()) { String bedrockMessage = MessageTranslator.convertMessage(entry.getKey(), "en_US"); - Assert.assertEquals("Translation of messages is incorrect", entry.getValue(), bedrockMessage); + Assertions.assertEquals(entry.getValue(), bedrockMessage, "Translation of messages is incorrect"); } } @Test public void convertMessageLenient() { - Assert.assertEquals("All newline message is not handled properly", "\n\n\n\n", MessageTranslator.convertMessageLenient("\n\n\n\n")); - Assert.assertEquals("Empty message is not handled properly", "", MessageTranslator.convertMessageLenient("")); - Assert.assertEquals("Reset before message is not handled properly", "§r§eGame Selector", MessageTranslator.convertMessageLenient("§r§eGame Selector")); - Assert.assertEquals("Unimplemented formatting chars not stripped", "Bold Underline", MessageTranslator.convertMessageLenient("§m§nBold Underline")); + Assertions.assertEquals("\n\n\n\n", MessageTranslator.convertMessageLenient("\n\n\n\n"), "All newline message is not handled properly"); + Assertions.assertEquals("", MessageTranslator.convertMessageLenient(""), "Empty message is not handled properly"); + Assertions.assertEquals("§r§eGame Selector", MessageTranslator.convertMessageLenient("§r§eGame Selector"), "Reset before message is not handled properly"); + Assertions.assertEquals("Bold Underline", MessageTranslator.convertMessageLenient("§m§nBold Underline"), "Unimplemented formatting chars not stripped"); } @Test public void convertToPlainText() { - Assert.assertEquals("JSON message is not handled properly", "Many colors here", MessageTranslator.convertToPlainText("{\"extra\":[{\"color\":\"red\",\"text\":\"M\"},{\"color\":\"gold\",\"text\":\"a\"},{\"color\":\"yellow\",\"text\":\"n\"},{\"color\":\"green\",\"text\":\"y \"},{\"color\":\"aqua\",\"text\":\"c\"},{\"color\":\"dark_purple\",\"text\":\"o\"},{\"color\":\"red\",\"text\":\"l\"},{\"color\":\"gold\",\"text\":\"o\"},{\"color\":\"yellow\",\"text\":\"r\"},{\"color\":\"green\",\"text\":\"s \"},{\"color\":\"aqua\",\"text\":\"h\"},{\"color\":\"dark_purple\",\"text\":\"e\"},{\"color\":\"red\",\"text\":\"r\"},{\"color\":\"gold\",\"text\":\"e\"}],\"text\":\"\"}", "en_US")); - Assert.assertEquals("Legacy formatted message is not handled properly (Colors)", "Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e")); - Assert.assertEquals("Legacy formatted message is not handled properly (Colors)", "Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e", "en_US")); - Assert.assertEquals("Legacy formatted message is not handled properly (Style)", "Obf Bold Strikethrough Underline Italic Reset", MessageTranslator.convertToPlainText("§kObf §lBold §mStrikethrough §nUnderline §oItalic §rReset", "en_US")); - Assert.assertEquals("Valid lenient JSON is not handled properly", "Strange", MessageTranslator.convertToPlainText("§rStrange", "en_US")); - Assert.assertEquals("Empty message is not handled properly", "", MessageTranslator.convertToPlainText("", "en_US")); - Assert.assertEquals("Whitespace is not preserved", " ", MessageTranslator.convertToPlainText(" ", "en_US")); + Assertions.assertEquals("Many colors here", MessageTranslator.convertToPlainText("{\"extra\":[{\"color\":\"red\",\"text\":\"M\"},{\"color\":\"gold\",\"text\":\"a\"},{\"color\":\"yellow\",\"text\":\"n\"},{\"color\":\"green\",\"text\":\"y \"},{\"color\":\"aqua\",\"text\":\"c\"},{\"color\":\"dark_purple\",\"text\":\"o\"},{\"color\":\"red\",\"text\":\"l\"},{\"color\":\"gold\",\"text\":\"o\"},{\"color\":\"yellow\",\"text\":\"r\"},{\"color\":\"green\",\"text\":\"s \"},{\"color\":\"aqua\",\"text\":\"h\"},{\"color\":\"dark_purple\",\"text\":\"e\"},{\"color\":\"red\",\"text\":\"r\"},{\"color\":\"gold\",\"text\":\"e\"}],\"text\":\"\"}", "en_US"), "JSON message is not handled properly"); + Assertions.assertEquals("Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e"), "Legacy formatted message is not handled properly (Colors)"); + Assertions.assertEquals("Many colors here", MessageTranslator.convertToPlainText("§cM§6a§en§ay §bc§5o§cl§6o§er§as §bh§5e§cr§6e", "en_US"), "Legacy formatted message is not handled properly (Colors)"); + Assertions.assertEquals("Obf Bold Strikethrough Underline Italic Reset", MessageTranslator.convertToPlainText("§kObf §lBold §mStrikethrough §nUnderline §oItalic §rReset", "en_US"), "Legacy formatted message is not handled properly (Style)"); + Assertions.assertEquals("Strange", MessageTranslator.convertToPlainText("§rStrange", "en_US"), "Valid lenient JSON is not handled properly"); + Assertions.assertEquals("", MessageTranslator.convertToPlainText("", "en_US"), "Empty message is not handled properly"); + Assertions.assertEquals(" ", MessageTranslator.convertToPlainText(" ", "en_US"), "Whitespace is not preserved"); } @Test diff --git a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java index 5b1781e7b..e4aafe5c2 100644 --- a/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java +++ b/core/src/test/java/org/geysermc/geyser/translator/inventory/item/CustomItemsTest.java @@ -31,27 +31,30 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; import org.cloudburstmc.protocol.bedrock.data.defintions.ItemDefinition; +import org.cloudburstmc.protocol.bedrock.data.defintions.SimpleItemDefinition; import org.geysermc.geyser.api.item.custom.CustomItemOptions; import org.geysermc.geyser.api.util.TriState; import org.geysermc.geyser.item.GeyserCustomItemOptions; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.registry.type.ItemMapping; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.OptionalInt; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class CustomItemsTest { private ItemMapping testMappingWithDamage; private Map tagToCustomItemWithDamage; private ItemMapping testMappingWithNoDamage; private Map tagToCustomItemWithNoDamage; - @Before + @BeforeAll public void setup() { CustomItemOptions a = new GeyserCustomItemOptions(TriState.TRUE, OptionalInt.of(2), OptionalInt.empty()); CustomItemOptions b = new GeyserCustomItemOptions(TriState.FALSE, OptionalInt.of(5), OptionalInt.empty()); @@ -63,13 +66,13 @@ public class CustomItemsTest { Map optionsToId = new Object2ObjectArrayMap<>(); // Order here is important, hence why we're using an array map - optionsToId.put(g, new ItemDefinition("geyser:test_item_7", 7, true)); - optionsToId.put(f, new ItemDefinition("geyser:test_item_6", 6, true)); - optionsToId.put(e, new ItemDefinition("geyser:test_item_5", 5, true)); - optionsToId.put(d, new ItemDefinition("geyser:test_item_4", 4, true)); - optionsToId.put(c, new ItemDefinition("geyser:test_item_3", 3, true)); - optionsToId.put(b, new ItemDefinition("geyser:test_item_2", 2, true)); - optionsToId.put(a, new ItemDefinition("geyser:test_item_1", 1, true)); + optionsToId.put(g, new SimpleItemDefinition("geyser:test_item_7", 7, true)); + optionsToId.put(f, new SimpleItemDefinition("geyser:test_item_6", 6, true)); + optionsToId.put(e, new SimpleItemDefinition("geyser:test_item_5", 5, true)); + optionsToId.put(d, new SimpleItemDefinition("geyser:test_item_4", 4, true)); + optionsToId.put(c, new SimpleItemDefinition("geyser:test_item_3", 3, true)); + optionsToId.put(b, new SimpleItemDefinition("geyser:test_item_2", 2, true)); + optionsToId.put(a, new SimpleItemDefinition("geyser:test_item_1", 1, true)); tagToCustomItemWithDamage = new HashMap<>(); @@ -149,12 +152,12 @@ public class CustomItemsTest { public void testCustomItems() { for (Map.Entry entry : this.tagToCustomItemWithDamage.entrySet()) { ItemDefinition id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithDamage); - Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getValue(), id); + Assertions.assertEquals(entry.getValue(), id, entry.getKey() + " did not produce the correct custom item"); } for (Map.Entry entry : this.tagToCustomItemWithNoDamage.entrySet()) { ItemDefinition id = CustomItemTranslator.getCustomItem(entry.getKey(), this.testMappingWithNoDamage); - Assert.assertEquals(entry.getKey() + " did not produce the correct custom item", entry.getValue(), id); + Assertions.assertEquals(entry.getValue(), id, entry.getKey() + " did not produce the correct custom item"); } } } diff --git a/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java b/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java index a2a9f98f6..639c79331 100644 --- a/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java +++ b/core/src/test/java/org/geysermc/geyser/util/collection/GeyserCollectionsTest.java @@ -25,9 +25,11 @@ package org.geysermc.geyser.util.collection; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class GeyserCollectionsTest { private final byte[] bytes = new byte[] {(byte) 5, (byte) 4, (byte) 3, (byte) 2, (byte) 2, (byte) 1}; private final boolean[] booleans = new boolean[] {true, false, false, true}; @@ -51,35 +53,35 @@ public class GeyserCollectionsTest { int lastKey = index; // Easy, understandable out-of-bounds checks - Assert.assertFalse("Map contains key bigger by one!", map.containsKey(lastKey)); - Assert.assertTrue("Map doesn't contain final key!", map.containsKey(lastKey - 1)); + Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!"); + Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!"); // Ensure the first and last values do not throw an exception on get, and test getOrDefault map.get(start - 1); map.get(lastKey); - Assert.assertEquals(map.getOrDefault(start - 1, Byte.MAX_VALUE), Byte.MAX_VALUE); - Assert.assertEquals(map.getOrDefault(lastKey, Byte.MAX_VALUE), Byte.MAX_VALUE); - Assert.assertEquals(map.getOrDefault(lastKey, Byte.MIN_VALUE), Byte.MIN_VALUE); + Assertions.assertEquals(map.getOrDefault(start - 1, Byte.MAX_VALUE), Byte.MAX_VALUE); + Assertions.assertEquals(map.getOrDefault(lastKey, Byte.MAX_VALUE), Byte.MAX_VALUE); + Assertions.assertEquals(map.getOrDefault(lastKey, Byte.MIN_VALUE), Byte.MIN_VALUE); - Assert.assertEquals(map.size(), bytes.length); + Assertions.assertEquals(map.size(), bytes.length); for (int i = start; i < bytes.length; i++) { - Assert.assertTrue(map.containsKey(i)); - Assert.assertEquals(map.get(i), bytes[i - start]); + Assertions.assertTrue(map.containsKey(i)); + Assertions.assertEquals(map.get(i), bytes[i - start]); } for (int i = start - 1; i >= (start - 6); i--) { // Lower than expected check - Assert.assertFalse(i + " is in a map that starts with " + start, map.containsKey(i)); + Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start); } for (int i = bytes.length + start; i < bytes.length + 5 + start; i++) { // Higher than expected check - Assert.assertFalse(i + " is in a map that ends with " + (start + bytes.length), map.containsKey(i)); + Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + bytes.length)); } for (byte b : bytes) { - Assert.assertTrue(map.containsValue(b)); + Assertions.assertTrue(map.containsValue(b)); } } @@ -99,33 +101,33 @@ public class GeyserCollectionsTest { int lastKey = index; // Easy, understandable out-of-bounds checks - Assert.assertFalse("Map contains key bigger by one!", map.containsKey(lastKey)); - Assert.assertTrue("Map doesn't contain final key!", map.containsKey(lastKey - 1)); + Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!"); + Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!"); // Ensure the first and last values do not throw an exception on get map.get(start - 1); map.get(lastKey); - Assert.assertTrue(map.getOrDefault(lastKey, true)); + Assertions.assertTrue(map.getOrDefault(lastKey, true)); - Assert.assertEquals(map.size(), booleans.length); + Assertions.assertEquals(map.size(), booleans.length); for (int i = start; i < booleans.length; i++) { - Assert.assertTrue(map.containsKey(i)); - Assert.assertEquals(map.get(i), booleans[i - start]); + Assertions.assertTrue(map.containsKey(i)); + Assertions.assertEquals(map.get(i), booleans[i - start]); } for (int i = start - 1; i >= (start - 6); i--) { // Lower than expected check - Assert.assertFalse(i + " is in a map that starts with " + start, map.containsKey(i)); + Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start); } for (int i = booleans.length + start; i < booleans.length + start + 5; i++) { // Higher than expected check - Assert.assertFalse(i + " is in a map that ends with " + (start + booleans.length), map.containsKey(i)); + Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + booleans.length)); } for (boolean b : booleans) { - Assert.assertTrue(map.containsValue(b)); + Assertions.assertTrue(map.containsValue(b)); } } @@ -145,35 +147,35 @@ public class GeyserCollectionsTest { int lastKey = index; // Easy, understandable out-of-bounds checks - Assert.assertFalse("Map contains key bigger by one!", map.containsKey(lastKey)); - Assert.assertTrue("Map doesn't contain final key!", map.containsKey(lastKey - 1)); + Assertions.assertFalse(map.containsKey(lastKey), "Map contains key bigger by one!"); + Assertions.assertTrue(map.containsKey(lastKey - 1), "Map doesn't contain final key!"); // Ensure the first and last values do not throw an exception on get, and test getOrDefault map.get(start - 1); map.get(lastKey); - Assert.assertEquals(map.getOrDefault(start - 1, Integer.MAX_VALUE), Integer.MAX_VALUE); - Assert.assertEquals(map.getOrDefault(lastKey, Integer.MAX_VALUE), Integer.MAX_VALUE); - Assert.assertEquals(map.getOrDefault(lastKey, Integer.MIN_VALUE), Integer.MIN_VALUE); + Assertions.assertEquals(map.getOrDefault(start - 1, Integer.MAX_VALUE), Integer.MAX_VALUE); + Assertions.assertEquals(map.getOrDefault(lastKey, Integer.MAX_VALUE), Integer.MAX_VALUE); + Assertions.assertEquals(map.getOrDefault(lastKey, Integer.MIN_VALUE), Integer.MIN_VALUE); - Assert.assertEquals(map.size(), ints.length); + Assertions.assertEquals(map.size(), ints.length); for (int i = start; i < ints.length; i++) { - Assert.assertTrue(map.containsKey(i)); - Assert.assertEquals(map.get(i), ints[i - start]); + Assertions.assertTrue(map.containsKey(i)); + Assertions.assertEquals(map.get(i), ints[i - start]); } for (int i = start - 1; i >= (start - 6); i--) { // Lower than expected check - Assert.assertFalse(i + " is in a map that starts with " + start, map.containsKey(i)); + Assertions.assertFalse(map.containsKey(i), i + " is in a map that starts with " + start); } for (int i = ints.length + start; i < ints.length + 5 + start; i++) { // Higher than expected check - Assert.assertFalse(i + " is in a map that ends with " + (start + ints.length), map.containsKey(i)); + Assertions.assertFalse(map.containsKey(i), i + " is in a map that ends with " + (start + ints.length)); } for (int i : ints) { - Assert.assertTrue(map.containsValue(i)); + Assertions.assertTrue(map.containsValue(i)); } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a4c5dd33e..6151b6dbd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,7 @@ [versions] base-api = "1.0.0-SNAPSHOT" cumulus = "1.1.1" +erosion = "1.0-SNAPSHOT" events = "1.0-SNAPSHOT" jackson = "2.14.0" fastutil = "8.5.2" @@ -11,18 +12,17 @@ websocket = "1.5.1" protocol = "3.0.0.Beta1-SNAPSHOT" raknet = "0.0.1.Final-SNAPSHOT" mcauthlib = "d9d773e" -mcprotocollib = "1.19.3-SNAPSHOT" -packetlib = "3.0.1" +mcprotocollib = "1.19.4-SNAPSHOT" adventure = "4.12.0-20220629.025215-9" adventure-platform = "4.1.2" -junit = "4.13.1" +junit = "5.9.2" checkerframework = "3.19.0" log4j = "2.17.1" jline = "3.21.0" terminalconsoleappender = "1.2.0" -paper = "1.19-R0.1-SNAPSHOT" +folia = "1.19.4-R0.1-SNAPSHOT" viaversion = "4.0.0" -adapters = "1.6-SNAPSHOT" +adapters = "1.8-SNAPSHOT" commodore = "2.2" bungeecord = "a7c6ede" velocity = "3.0.0" @@ -36,6 +36,9 @@ base-api = { group = "org.geysermc.api", name = "base-api", version.ref = "base- cumulus = { group = "org.geysermc.cumulus", name = "cumulus", version.ref = "cumulus" } events = { group = "org.geysermc.event", name = "events", version.ref = "events" } +erosion-bukkit-common = { group = "org.geysermc.erosion", name = "bukkit-common", version.ref = "erosion" } +erosion-common = { group = "org.geysermc.erosion", name = "common", version.ref = "erosion" } + jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" } jackson-core = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" } jackson-dataformat-yaml = { group = "com.fasterxml.jackson.dataformat", name = "jackson-dataformat-yaml", version.ref = "jackson" } @@ -67,8 +70,8 @@ jline-terminal = { group = "org.jline", name = "jline-terminal", version.ref = " jline-terminal-jna = { group = "org.jline", name = "jline-terminal-jna", version.ref = "jline" } jline-reader = { group = "org.jline", name = "jline-reader", version.ref = "jline" } -paper-api = { group = "io.papermc.paper", name = "paper-api", version.ref = "paper" } -paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "paper" } +folia-api = { group = "dev.folia", name = "folia-api", version.ref = "folia" } +paper-mojangapi = { group = "io.papermc.paper", name = "paper-mojangapi", version.ref = "folia" } # check these on https://modmuss50.me/fabric.html fabric-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" } @@ -81,10 +84,9 @@ checker-qual = { group = "org.checkerframework", name = "checker-qual", version. commodore = { group = "me.lucko", name = "commodore", version.ref = "commodore" } guava = { group = "com.google.guava", name = "guava", version.ref = "guava" } gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson" } -junit = { group = "junit", name = "junit", version.ref = "junit" } +junit = { group = "org.junit.jupiter", name = "junit-jupiter", version.ref = "junit" } mcauthlib = { group = "com.github.GeyserMC", name = "MCAuthLib", version.ref = "mcauthlib" } mcprotocollib = { group = "com.github.steveice10", name = "mcprotocollib", version.ref = "mcprotocollib" } -packetlib = { group = "com.github.steveice10", name = "packetlib", version.ref = "packetlib" } raknet = { group = "org.cloudburstmc.netty", name = "netty-transport-raknet", version.ref = "raknet" } sponge-api = { group = "org.spongepowered", name = "spongeapi", version.ref = "sponge" } terminalconsoleappender = { group = "net.minecrell", name = "terminalconsoleappender", version.ref = "terminalconsoleappender" }