diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f4a0e21ff..036d838ef 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -55,9 +55,9 @@ body: required: true - type: input attributes: - label: "Minecraft: Bedrock Edition Version" - description: "What version of Minecraft: Bedrock Edition are you using? Leave empty if the bug happens before you can connect with Minecraft: Bedrock Edition." - placeholder: "For example: 1.16.201" + label: "Minecraft: Bedrock Edition Device/Version" + description: "What version of Minecraft: Bedrock Edition are you using, and what device(s) does the bug occur on? Leave empty if the bug happens before you can connect with Minecraft: Bedrock Edition." + placeholder: "For example: 1.16.201, Nintendo Switch" - type: textarea attributes: label: Additional Context diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml new file mode 100644 index 000000000..598cab46a --- /dev/null +++ b/.github/workflows/sonarcloud.yml @@ -0,0 +1,36 @@ +name: SonarCloud +on: + push: + branches: + - master +jobs: + build: + name: SonarCloud + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + submodules: true + - name: Set up JDK 17 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: 17 + - name: Cache SonarCloud packages + uses: actions/cache@v1 + with: + path: ~/.sonar/cache + key: ${{ runner.os }}-sonar + restore-keys: ${{ runner.os }}-sonar + - name: Cache Maven packages + uses: actions/cache@v1 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + - name: Build and analyze + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=GeyserMC_Geyser \ No newline at end of file diff --git a/.gitignore b/.gitignore index 85f8a6e9e..f1baa3abb 100644 --- a/.gitignore +++ b/.gitignore @@ -239,8 +239,10 @@ nbdist/ run/ config.yml logs/ -public-key.pem +key.pem locales/ /cache/ /packs/ -/dump.json \ No newline at end of file +/dump.json +/saved-refresh-tokens.json +/languages/ \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 481c02310..ac10b06dd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,7 +22,9 @@ pipeline { stage ('Deploy') { when { - branch "master" + anyOf { + branch "master" + } } steps { diff --git a/LICENSE b/LICENSE index 0e368d546..b922bb9ca 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2019-2021 GeyserMC. http://geysermc.org +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 diff --git a/README.md b/README.md index d4b375a5c..aba8babf2 100644 --- a/README.md +++ b/README.md @@ -17,16 +17,16 @@ 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.17.30 - 1.17.41 + 1.18.0 - 1.18.2 and Minecraft Java 1.18/1.18.1. +### Currently supporting Minecraft Bedrock 1.19 and Minecraft Java 1.19.0. ## Setting Up -Take a look [here](https://github.com/GeyserMC/Geyser/wiki/Setup) for how to set up Geyser. +Take a look [here](https://wiki.geysermc.org/geyser/setup/) for how to set up Geyser. [![YouTube Video](https://img.youtube.com/vi/U7dZZ8w7Gi4/0.jpg)](https://www.youtube.com/watch?v=U7dZZ8w7Gi4) ## Links: - Website: https://geysermc.org -- Docs: https://github.com/GeyserMC/Geyser/wiki +- Docs: https://wiki.geysermc.org/geyser/ - Download: https://ci.geysermc.org - Discord: https://discord.gg/geysermc - Donate: https://opencollective.com/geysermc @@ -39,7 +39,7 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki/Setup) for how to set - Structure block UI ## What can't be fixed -There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://github.com/GeyserMC/Geyser/wiki/Current-Limitations) page. +There are a few things Geyser is unable to support due to various differences between Minecraft Bedrock and Java. For a list of these limitations, see the [Current Limitations](https://wiki.geysermc.org/geyser/current-limitations/) page. ## Compiling 1. Clone the repo to your computer diff --git a/ap/pom.xml b/ap/pom.xml index cc282dd55..0644044a1 100644 --- a/ap/pom.xml +++ b/ap/pom.xml @@ -6,9 +6,9 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT ap - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT \ No newline at end of file diff --git a/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java b/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java index 5a0b2d2f9..7ab760cec 100644 --- a/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java +++ b/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/ap/src/main/java/org/geysermc/processor/ClassProcessor.java b/ap/src/main/java/org/geysermc/processor/ClassProcessor.java index 409306f1f..a6259a853 100644 --- a/ap/src/main/java/org/geysermc/processor/ClassProcessor.java +++ b/ap/src/main/java/org/geysermc/processor/ClassProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java b/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java index eae2e5d97..971abd984 100644 --- a/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java +++ b/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java b/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java index cb49e8749..39d5f9fdf 100644 --- a/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java +++ b/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java b/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java index 5c46453e3..97687e981 100644 --- a/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java +++ b/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java b/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java index ad52533e9..3e6a7c412 100644 --- a/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java +++ b/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/api/base/pom.xml b/api/base/pom.xml index 0d7ed05da..1d051eaa3 100644 --- a/api/base/pom.xml +++ b/api/base/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT 4.0.0 diff --git a/api/base/src/main/java/org/geysermc/api/Geyser.java b/api/base/src/main/java/org/geysermc/api/Geyser.java index c5ae7fa4d..9f315faf4 100644 --- a/api/base/src/main/java/org/geysermc/api/Geyser.java +++ b/api/base/src/main/java/org/geysermc/api/Geyser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java index 1acf9b5f8..3549a912a 100644 --- a/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java +++ b/api/base/src/main/java/org/geysermc/api/GeyserApiBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/api/base/src/main/java/org/geysermc/api/session/Connection.java b/api/base/src/main/java/org/geysermc/api/session/Connection.java index dc4fb4701..3e997912b 100644 --- a/api/base/src/main/java/org/geysermc/api/session/Connection.java +++ b/api/base/src/main/java/org/geysermc/api/session/Connection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,6 +26,7 @@ package org.geysermc.api.session; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.common.value.qual.IntRange; import java.util.UUID; @@ -55,5 +56,13 @@ public interface Connection { */ String xuid(); - + /** + * Transfer the connection to a server. A Bedrock player can successfully transfer to the same server they are + * currently playing on. + * + * @param address The address of the server + * @param port The port of the server + * @return true if the transfer was a success + */ + boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port); } diff --git a/api/geyser/pom.xml b/api/geyser/pom.xml index 89349e8ac..2a933a2e0 100644 --- a/api/geyser/pom.xml +++ b/api/geyser/pom.xml @@ -5,7 +5,7 @@ org.geysermc api-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT 4.0.0 @@ -26,7 +26,7 @@ org.geysermc base-api - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java index 6a5e7ccab..074918881 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/GeyserApi.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index a38dc2f91..79260ac95 100644 --- a/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/geyser/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/api/pom.xml b/api/pom.xml index b3d0262ea..5d078fba5 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT api-parent diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 9dcd0943e..b2c661447 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-bungeecord @@ -14,7 +14,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile @@ -49,7 +49,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0-SNAPSHOT + 3.3.0 package diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java index 866a0657f..bc084a34e 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java index ded11fd91..54cb16edb 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java index 389f0e37f..2b1fa10c0 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java index fbc09956c..daeb20102 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeMain.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeMain.java index 224c500a1..8229f952a 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeMain.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeeMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java index 393517aa2..39fb9e134 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,6 +29,7 @@ import lombok.AllArgsConstructor; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.event.ProxyPingEvent; @@ -52,8 +53,11 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { CompletableFuture future = new CompletableFuture<>(); proxyServer.getPluginManager().callEvent(new ProxyPingEvent(new GeyserPendingConnection(inetSocketAddress), getPingInfo(), (event, throwable) -> { - if (throwable != null) future.completeExceptionally(throwable); - else future.complete(event); + if (throwable != null) { + future.completeExceptionally(throwable); + } else { + future.complete(event); + } })); ProxyPingEvent event = future.join(); ServerPing response = event.getResponse(); @@ -76,9 +80,12 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List private ServerPing getPingInfo() { return new ServerPing( - new ServerPing.Protocol(proxyServer.getName() + " " + proxyServer.getGameVersion(), ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1)), + new ServerPing.Protocol( + proxyServer.getName() + " " + ProtocolConstants.SUPPORTED_VERSIONS.get(0) + "-" + ProtocolConstants.SUPPORTED_VERSIONS.get(ProtocolConstants.SUPPORTED_VERSIONS.size() - 1), + ProtocolConstants.SUPPORTED_VERSION_IDS.get(ProtocolConstants.SUPPORTED_VERSION_IDS.size() - 1)), new ServerPing.Players(getDefaultListener().getMaxPlayers(), proxyServer.getOnlineCount(), null), - getDefaultListener().getMotd(), proxyServer.getConfig().getFaviconObject() + TextComponent.fromLegacyText(getDefaultListener().getMotd())[0], + proxyServer.getConfig().getFaviconObject() ); } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java index 36e6ffb1d..f35082359 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/GeyserBungeePlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java index 7dc04f95b..05df8ba97 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/BungeeCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java index f0a05687c..5bb323aac 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java index 06e5da71e..019544c28 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/geyser/platform/bungeecord/command/GeyserBungeeCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 3b0bdda55..7d6ac8f98 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-parent pom @@ -34,7 +34,7 @@ org.geysermc ap - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT provided diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 5d17d2619..d80408589 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,28 +6,43 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-spigot + + papermc + https://repo.papermc.io/repository/maven-public/ + viaversion-repo https://repo.viaversion.com + + + minecraft-repo + https://libraries.minecraft.net/ + org.geysermc core - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile - org.spigotmc - spigot-api - 1.15.2-R0.1-SNAPSHOT + io.papermc.paper + paper-api + 1.18.1-R0.1-SNAPSHOT + provided + + + io.papermc.paper + paper-mojangapi + 1.18.1-R0.1-SNAPSHOT provided @@ -39,7 +54,13 @@ org.geysermc.geyser.adapters spigot-all - 1.3-SNAPSHOT + 1.4-SNAPSHOT + + + me.lucko + commodore + 1.13 + compile @@ -66,7 +87,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0-SNAPSHOT + 3.3.0 package @@ -91,6 +112,10 @@ org.objectweb.asm org.geysermc.geyser.platform.spigot.shaded.asm + + me.lucko.commodore + org.geysermc.geyser.platform.spigot.shaded.commodore + @@ -114,6 +139,7 @@ io.netty:netty-codec-dns:* io.netty:netty-resolver-dns:* io.netty:netty-resolver-dns-native-macos:* + com.mojang:* diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java index 60bc05f13..3320ffa65 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java index 189ca2356..7f8213155 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java index 7f390f9d8..0fd8d849b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.platform.spigot; +import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.viaversion.viaversion.bukkit.handlers.BukkitChannelInitializer; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.*; @@ -34,10 +35,12 @@ import org.bukkit.Bukkit; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.network.netty.GeyserInjector; import org.geysermc.geyser.network.netty.LocalServerChannelWrapper; +import org.geysermc.geyser.network.netty.LocalSession; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; +import java.net.InetAddress; import java.util.List; public class GeyserSpigotInjector extends GeyserInjector { @@ -128,6 +131,8 @@ public class GeyserSpigotInjector extends GeyserInjector { allServerChannels.add(channelFuture); this.localChannel = channelFuture; this.serverSocketAddress = channelFuture.channel().localAddress(); + + workAroundWeirdBug(bootstrap); } @SuppressWarnings("unchecked") @@ -158,6 +163,19 @@ public class GeyserSpigotInjector extends GeyserInjector { return childHandler; } + /** + * Work around an odd bug where the first connection might not initialize all channel handlers on the main pipeline - + * send a dummy status request down that acts as the first connection, then. + * For the future, if someone wants to properly fix this - as of December 28, 2021, it happens on 1.16.5/1.17.1/1.18.1 EXCEPT Spigot 1.16.5 + */ + private void workAroundWeirdBug(GeyserBootstrap bootstrap) { + MinecraftProtocol protocol = new MinecraftProtocol(); + LocalSession session = new LocalSession(bootstrap.getGeyserConfig().getRemote().getAddress(), + bootstrap.getGeyserConfig().getRemote().getPort(), this.serverSocketAddress, + InetAddress.getLoopbackAddress().getHostAddress(), protocol, protocol.createHelper()); + session.connect(); + } + @Override public void shutdown() { if (this.allServerChannels != null) { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java index 98c85977f..fe56cba1c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotMain.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotMain.java index 5d18e4f94..4dfc40b2d 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotMain.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 a6ec9e329..19153b750 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -57,8 +57,8 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough { Bukkit.getOnlinePlayers().stream().map(Player::getName).forEach(geyserPingInfo.getPlayerList()::add); return geyserPingInfo; } catch (Exception e) { - logger.debug("Error while getting Bukkit ping passthrough: " + e.toString()); - return new GeyserPingInfo(null, null, null); + logger.debug("Error while getting Bukkit ping passthrough: " + e); + return null; } } @@ -79,5 +79,4 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough { return Collections.emptyIterator(); } } - } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java index 12a27190d..4ece501c4 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,40 +29,51 @@ import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.data.MappingData; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import me.lucko.commodore.CommodoreProvider; import org.bukkit.Bukkit; +import org.bukkit.command.PluginCommand; +import org.bukkit.permissions.Permission; +import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.java.JavaPlugin; import org.geysermc.common.PlatformType; -import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.Constants; import org.geysermc.geyser.GeyserBootstrap; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.adapters.spigot.SpigotAdapters; import org.geysermc.geyser.command.CommandManager; -import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.dump.BootstrapDumpInfo; -import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.level.WorldManager; +import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.ping.GeyserLegacyPingPassthrough; import org.geysermc.geyser.ping.IGeyserPingPassthrough; -import org.geysermc.geyser.Constants; -import org.geysermc.geyser.util.FileUtils; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.adapters.spigot.SpigotAdapters; +import org.geysermc.geyser.platform.spigot.command.GeyserBrigadierSupport; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandExecutor; import org.geysermc.geyser.platform.spigot.command.GeyserSpigotCommandManager; import org.geysermc.geyser.platform.spigot.command.SpigotCommandSender; import org.geysermc.geyser.platform.spigot.world.GeyserPistonListener; -import org.geysermc.geyser.platform.spigot.world.GeyserSpigot1_11CraftingListener; import org.geysermc.geyser.platform.spigot.world.GeyserSpigotBlockPlaceListener; import org.geysermc.geyser.platform.spigot.world.manager.*; +import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.util.FileUtils; import java.io.File; import java.io.IOException; import java.net.SocketAddress; import java.nio.file.Path; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.logging.Level; public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { + /** + * Determines if the plugin has been ran once before, including before /geyser reload. + */ + private static boolean INITIALIZED = false; + private GeyserSpigotCommandManager geyserCommandManager; private GeyserSpigotConfiguration geyserConfig; private GeyserSpigotInjector geyserInjector; @@ -168,8 +179,7 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { // Ensure that we have the latest 4.0.0 changes and not an older ViaVersion version Class.forName("com.viaversion.viaversion.api.ViaManager"); } catch (ClassNotFoundException e) { - geyserLogger.warning(GeyserLocale.getLocaleStringLog("geyser.bootstrap.viaversion.too_old", - "https://ci.viaversion.com/job/ViaVersion/")); + GeyserSpigotVersionChecker.sendOutdatedViaVersionMessage(geyserLogger); isViaVersion = false; if (this.geyserConfig.isDebugMode()) { e.printStackTrace(); @@ -231,17 +241,42 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { } geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass()); } - GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager); - Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); - Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); + PluginCommand pluginCommand = this.getCommand("geyser"); + pluginCommand.setExecutor(new GeyserSpigotCommandExecutor(geyser)); - if (isPre1_12) { - // Register events needed to send all recipes to the client - Bukkit.getServer().getPluginManager().registerEvents(new GeyserSpigot1_11CraftingListener(geyser), this); + if (!INITIALIZED) { + // Register permissions so they appear in, for example, LuckPerms' UI + // Re-registering permissions throws an error + for (Map.Entry entry : geyserCommandManager.getCommands().entrySet()) { + GeyserCommand command = entry.getValue(); + if (command.getAliases().contains(entry.getKey())) { + // Don't register aliases + continue; + } + + Bukkit.getPluginManager().addPermission(new Permission(command.getPermission(), + GeyserLocale.getLocaleStringLog(command.getDescription()), + command.isSuggestedOpOnly() ? PermissionDefault.OP : PermissionDefault.TRUE)); + } + + // Events cannot be unregistered - re-registering results in duplicate firings + GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(geyser, this.geyserWorldManager); + Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); + + Bukkit.getServer().getPluginManager().registerEvents(new GeyserPistonListener(geyser, this.geyserWorldManager), this); } - this.getCommand("geyser").setExecutor(new GeyserSpigotCommandExecutor(geyser)); + boolean brigadierSupported = CommodoreProvider.isSupported(); + geyserLogger.debug("Brigadier supported? " + brigadierSupported); + if (brigadierSupported) { + GeyserBrigadierSupport.loadBrigadier(this, pluginCommand); + } + + // Check to ensure the current setup can support the protocol version Geyser uses + GeyserSpigotVersionChecker.checkForSupportedProtocol(geyserLogger, isViaVersion); + + INITIALIZED = true; } @Override diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotVersionChecker.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotVersionChecker.java new file mode 100644 index 000000000..923209e59 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/GeyserSpigotVersionChecker.java @@ -0,0 +1,122 @@ +/* + * 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.platform.spigot; + +import com.viaversion.viaversion.api.Via; +import org.bukkit.Bukkit; +import org.bukkit.UnsafeValues; +import org.geysermc.geyser.GeyserLogger; +import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.text.GeyserLocale; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +public final class GeyserSpigotVersionChecker { + private static final String VIAVERSION_DOWNLOAD_URL = "https://ci.viaversion.com/job/ViaVersion/"; + + public static void checkForSupportedProtocol(GeyserLogger logger, boolean viaversion) { + if (viaversion) { + checkViaVersionSupportedVersions(logger); + return; + } + + try { + // This method is only present on later versions of Paper + UnsafeValues.class.getMethod("getProtocolVersion"); + if (Bukkit.getUnsafe().getProtocolVersion() != MinecraftProtocol.getJavaProtocolVersion()) { + sendOutdatedMessage(logger); + } + return; + } catch (NoSuchMethodException ignored) { + } + + // Otherwise, we can just try to find the SharedConstants class + // It isn't present in all server versions, but if we can't find it, then we're probably not in the latest version + Class sharedConstants; + try { + sharedConstants = Class.forName("net.minecraft.SharedConstants"); + } catch (ClassNotFoundException e) { + // We're using pre-1.17 + String prefix = Bukkit.getServer().getClass().getPackage().getName().replace("org.bukkit.craftbukkit", "net.minecraft.server"); + try { + sharedConstants = Class.forName(prefix + ".SharedConstants"); + } catch (ClassNotFoundException e2) { + sendOutdatedMessage(logger); + return; + } + } + for (Method method : sharedConstants.getMethods()) { + if (method.getReturnType() == int.class && Modifier.isStatic(method.getModifiers())) { + int protocolVersion; + try { + protocolVersion = (int) method.invoke(null); + } catch (IllegalAccessException | InvocationTargetException e) { + logger.warning("Could not determine server version! This is safe to ignore, but please report to the developers: " + e.getMessage()); + if (logger.isDebug()) { + e.printStackTrace(); + } + return; + } + if (protocolVersion != MinecraftProtocol.getJavaProtocolVersion()) { + sendOutdatedMessage(logger); + } + return; + } + } + sendOutdatedMessage(logger); + } + + private static void checkViaVersionSupportedVersions(GeyserLogger logger) { + // Run after ViaVersion has obtained the server protocol version + Via.getPlatform().runSync(() -> { + if (Via.getAPI().getSupportedVersions().contains(MinecraftProtocol.getJavaProtocolVersion())) { + // Via supports this protocol version; we will be able to connect. + return; + } + if (Via.getAPI().getFullSupportedVersions().contains(MinecraftProtocol.getJavaProtocolVersion())) { + // ViaVersion supports our protocol, but the user has blocked them from connecting. + logger.warning(GeyserLocale.getLocaleStringLog("geyser.bootstrap.viaversion.blocked", MinecraftProtocol.getAllSupportedJavaVersions())); + return; + } + // Else, presumably, ViaVersion is not updated. + sendOutdatedViaVersionMessage(logger); + }); + } + + public static void sendOutdatedViaVersionMessage(GeyserLogger logger) { + logger.warning(GeyserLocale.getLocaleStringLog("geyser.bootstrap.viaversion.too_old", + VIAVERSION_DOWNLOAD_URL)); + } + + private static void sendOutdatedMessage(GeyserLogger logger) { + logger.warning(GeyserLocale.getLocaleStringLog("geyser.bootstrap.no_supported_protocol", MinecraftProtocol.getAllSupportedJavaVersions(), VIAVERSION_DOWNLOAD_URL)); + } + + private GeyserSpigotVersionChecker() { + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java new file mode 100644 index 000000000..61900174c --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserBrigadierSupport.java @@ -0,0 +1,61 @@ +/* + * 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.platform.spigot.command; + +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import me.lucko.commodore.Commodore; +import me.lucko.commodore.CommodoreProvider; +import org.bukkit.Bukkit; +import org.bukkit.command.PluginCommand; +import org.geysermc.geyser.platform.spigot.GeyserSpigotPlugin; + +/** + * Needs to be a separate class so pre-1.13 loads correctly. + */ +public final class GeyserBrigadierSupport { + + public static void loadBrigadier(GeyserSpigotPlugin plugin, PluginCommand pluginCommand) { + // Enable command completions if supported + // This is beneficial because this is sent over the network and Bedrock can see it + Commodore commodore = CommodoreProvider.getCommodore(plugin); + LiteralArgumentBuilder builder = LiteralArgumentBuilder.literal("geyser"); + for (String command : plugin.getGeyserCommandManager().getCommands().keySet()) { + builder.then(LiteralArgumentBuilder.literal(command)); + } + commodore.register(pluginCommand, builder); + + try { + Class.forName("com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent"); + Bukkit.getServer().getPluginManager().registerEvents(new GeyserPaperCommandListener(), plugin); + plugin.getGeyserLogger().debug("Successfully registered AsyncPlayerSendCommandsEvent listener."); + } catch (ClassNotFoundException e) { + plugin.getGeyserLogger().debug("Not registering AsyncPlayerSendCommandsEvent listener."); + } + } + + private GeyserBrigadierSupport() { + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java new file mode 100644 index 000000000..00c1ba58d --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserPaperCommandListener.java @@ -0,0 +1,87 @@ +/* + * 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.platform.spigot.command; + +import com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent; +import com.mojang.brigadier.tree.CommandNode; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.command.GeyserCommand; + +import java.net.InetSocketAddress; +import java.util.Iterator; +import java.util.Map; + +public final class GeyserPaperCommandListener implements Listener { + + @EventHandler + @SuppressWarnings("deprecation") // Used to indicate an unstable event + public void onCommandSend(AsyncPlayerSendCommandsEvent event) { + // Documentation says to check (event.isAsynchronous() || !event.hasFiredAsync()), but as of Paper 1.18.2 + // event.hasFiredAsync is never true + if (event.isAsynchronous()) { + CommandNode geyserBrigadier = event.getCommandNode().getChild("geyser"); + if (geyserBrigadier != null) { + Player player = event.getPlayer(); + boolean isJavaPlayer = isProbablyJavaPlayer(player); + Map commands = GeyserImpl.getInstance().getCommandManager().getCommands(); + Iterator> it = geyserBrigadier.getChildren().iterator(); + + while (it.hasNext()) { + CommandNode subnode = it.next(); + GeyserCommand command = commands.get(subnode.getName()); + if (command != null) { + if ((command.isBedrockOnly() && isJavaPlayer) || !player.hasPermission(command.getPermission())) { + // Remove this from the node as we don't have permission to use it + it.remove(); + } + } + } + } + } + } + + /** + * This early on, there is a rare chance that Geyser has yet to process the connection. We'll try to minimize that + * chance, though. + */ + private boolean isProbablyJavaPlayer(Player player) { + if (GeyserImpl.getInstance().connectionByUuid(player.getUniqueId()) != null) { + // For sure this is a Bedrock player + return false; + } + + if (GeyserImpl.getInstance().getConfig().isUseDirectConnection()) { + InetSocketAddress address = player.getAddress(); + if (address != null) { + return address.getPort() != 0; + } + } + return true; + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java index af92091e5..b1bcfcaf8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java index 13ba3691c..6107d5b47 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/GeyserSpigotCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.platform.spigot.command; import org.bukkit.Bukkit; +import org.bukkit.Server; import org.bukkit.command.Command; import org.bukkit.command.CommandMap; import org.geysermc.geyser.GeyserImpl; @@ -35,16 +36,24 @@ import java.lang.reflect.Field; public class GeyserSpigotCommandManager extends CommandManager { - private static CommandMap COMMAND_MAP; + private static final CommandMap COMMAND_MAP; static { + CommandMap commandMap = null; try { - Field cmdMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap"); - cmdMapField.setAccessible(true); - COMMAND_MAP = (CommandMap) cmdMapField.get(Bukkit.getServer()); - } catch (NoSuchFieldException | IllegalAccessException ex) { - ex.printStackTrace(); + // Paper-only + Server.class.getMethod("getCommandMap"); + commandMap = Bukkit.getServer().getCommandMap(); + } catch (NoSuchMethodException e) { + try { + Field cmdMapField = Bukkit.getServer().getClass().getDeclaredField("commandMap"); + cmdMapField.setAccessible(true); + commandMap = (CommandMap) cmdMapField.get(Bukkit.getServer()); + } catch (NoSuchFieldException | IllegalAccessException ex) { + ex.printStackTrace(); + } } + COMMAND_MAP = commandMap; } public GeyserSpigotCommandManager(GeyserImpl geyser) { diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java index 7fbaac4f8..a05a6ebe0 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/command/SpigotCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 4d504bcf5..981d00b97 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -97,7 +97,7 @@ public class GeyserPistonListener implements Listener { int dX = Math.abs(location.getBlockX() - player.getLocation().getBlockX()) >> 4; int dZ = Math.abs(location.getBlockZ() - player.getLocation().getBlockZ()) >> 4; - if ((dX * dX + dZ * dZ) > session.getRenderDistance() * session.getRenderDistance()) { + if ((dX * dX + dZ * dZ) > session.getServerRenderDistance() * session.getServerRenderDistance()) { // Ignore pistons outside the player's render distance continue; } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigot1_11CraftingListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigot1_11CraftingListener.java deleted file mode 100644 index b6aea9a37..000000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigot1_11CraftingListener.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.platform.spigot.world; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; -import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.data.MappingData; -import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2; -import com.viaversion.viaversion.util.Pair; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.inventory.Recipe; -import org.bukkit.inventory.ShapedRecipe; -import org.bukkit.inventory.ShapelessRecipe; -import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.network.MinecraftProtocol; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; -import org.geysermc.geyser.util.InventoryUtils; - -import java.util.*; - -/** - * Used to send all available recipes from the server to the client, as a valid recipe book packet won't be sent by the server. - * Requires ViaVersion. - */ -public class GeyserSpigot1_11CraftingListener implements Listener { - - private final GeyserImpl geyser; - /** - * Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 item into 1.13. - */ - private final MappingData mappingData1_12to1_13; - /** - * The list of all protocols from the client's version to 1.13. - */ - private final List protocolList; - - public GeyserSpigot1_11CraftingListener(GeyserImpl geyser) { - this.geyser = geyser; - this.mappingData1_12to1_13 = Via.getManager().getProtocolManager().getProtocol(Protocol1_13To1_12_2.class).getMappingData(); - this.protocolList = Via.getManager().getProtocolManager().getProtocolPath(MinecraftProtocol.getJavaProtocolVersion(), - ProtocolVersion.v1_13.getVersion()); - } - - @EventHandler - public void onPlayerJoin(PlayerJoinEvent event) { - GeyserSession session = null; - for (GeyserSession otherSession : geyser.getSessionManager().getSessions().values()) { - if (otherSession.name().equals(event.getPlayer().getName())) { - session = otherSession; - break; - } - } - if (session == null) { - return; - } - - sendServerRecipes(session); - } - - public void sendServerRecipes(GeyserSession session) { - int netId = InventoryUtils.LAST_RECIPE_NET_ID; - - CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); - craftingDataPacket.setCleanRecipes(true); - - Iterator recipeIterator = Bukkit.getServer().recipeIterator(); - while (recipeIterator.hasNext()) { - Recipe recipe = recipeIterator.next(); - - Pair outputs = translateToBedrock(session, recipe.getResult()); - ItemStack javaOutput = outputs.getKey(); - ItemData output = outputs.getValue(); - if (output == null || output.getId() == 0) continue; // If items make air we don't want that - - boolean isNotAllAir = false; // Check for all-air recipes - if (recipe instanceof ShapedRecipe shapedRecipe) { - int size = shapedRecipe.getShape().length * shapedRecipe.getShape()[0].length(); - Ingredient[] ingredients = new Ingredient[size]; - ItemData[] input = new ItemData[size]; - for (int i = 0; i < input.length; i++) { - // Index is converting char to integer, adding i then converting back to char based on ASCII code - Pair result = translateToBedrock(session, shapedRecipe.getIngredientMap().get((char) ('a' + i))); - ingredients[i] = new Ingredient(new ItemStack[]{result.getKey()}); - input[i] = result.getValue(); - isNotAllAir |= input[i].getId() != 0; - } - - if (!isNotAllAir) continue; - UUID uuid = UUID.randomUUID(); - // Add recipe to our internal cache - ShapedRecipeData data = new ShapedRecipeData(shapedRecipe.getShape()[0].length(), shapedRecipe.getShape().length, - "", ingredients, javaOutput); - session.getCraftingRecipes().put(netId, - new com.github.steveice10.mc.protocol.data.game.recipe.Recipe(RecipeType.CRAFTING_SHAPED, uuid.toString(), data)); - - // Add recipe for Bedrock - craftingDataPacket.getCraftingData().add(CraftingData.fromShaped(uuid.toString(), - shapedRecipe.getShape()[0].length(), shapedRecipe.getShape().length, Arrays.asList(input), - Collections.singletonList(output), uuid, "crafting_table", 0, netId++)); - } else if (recipe instanceof ShapelessRecipe shapelessRecipe) { - Ingredient[] ingredients = new Ingredient[shapelessRecipe.getIngredientList().size()]; - ItemData[] input = new ItemData[shapelessRecipe.getIngredientList().size()]; - - for (int i = 0; i < input.length; i++) { - Pair result = translateToBedrock(session, shapelessRecipe.getIngredientList().get(i)); - ingredients[i] = new Ingredient(new ItemStack[]{result.getKey()}); - input[i] = result.getValue(); - isNotAllAir |= input[i].getId() != 0; - } - - if (!isNotAllAir) continue; - UUID uuid = UUID.randomUUID(); - // Add recipe to our internal cache - ShapelessRecipeData data = new ShapelessRecipeData("", ingredients, javaOutput); - session.getCraftingRecipes().put(netId, - new com.github.steveice10.mc.protocol.data.game.recipe.Recipe(RecipeType.CRAFTING_SHAPELESS, uuid.toString(), data)); - - // Add recipe for Bedrock - craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), - Arrays.asList(input), Collections.singletonList(output), uuid, "crafting_table", 0, netId++)); - } - } - - session.sendUpstreamPacket(craftingDataPacket); - } - - @SuppressWarnings("deprecation") - private Pair translateToBedrock(GeyserSession session, org.bukkit.inventory.ItemStack itemStack) { - if (itemStack != null && itemStack.getData() != null) { - if (itemStack.getType().getId() == 0) { - return new Pair<>(null, ItemData.AIR); - } - - int legacyId = (itemStack.getType().getId() << 4) | (itemStack.getData().getData() & 0xFFFF); - - if (itemStack.getType().getId() == 355 && itemStack.getData().getData() == (byte) 0) { // Handle bed color since the server will always be pre-1.12 - legacyId = (itemStack.getType().getId() << 4) | ((byte) 14 & 0xFFFF); - } - - // old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 and so on - int itemId; - if (mappingData1_12to1_13.getItemMappings().containsKey(legacyId)) { - itemId = mappingData1_12to1_13.getNewItemId(legacyId); - } else if (mappingData1_12to1_13.getItemMappings().containsKey((itemStack.getType().getId() << 4) | (0))) { - itemId = mappingData1_12to1_13.getNewItemId((itemStack.getType().getId() << 4) | (0)); - } else { - // No ID found, just send back air - return new Pair<>(null, ItemData.AIR); - } - - for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getProtocol().getMappingData(); - if (mappingData != null) { - itemId = mappingData.getNewItemId(itemId); - } - } - - ItemStack mcItemStack = new ItemStack(itemId, itemStack.getAmount()); - ItemData finalData = ItemTranslator.translateToBedrock(session, mcItemStack); - return new Pair<>(mcItemStack, finalData); - } - - // Empty slot, most likely - return new Pair<>(null, ItemData.AIR); - } - -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java index a8fcee3e5..62a56bd2d 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/GeyserSpigotBlockPlaceListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java index ea1fadd0e..670070a68 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java index f12968b1f..1936d608f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java index 1aacb73e7..3079c523f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java index caeb257f7..2e0491db8 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java index b1032671a..2db01ab4f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/geyser/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 8972b0ac6..a03549444 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/spigot/src/main/resources/plugin.yml index 18773402e..aa2747979 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/spigot/src/main/resources/plugin.yml @@ -9,34 +9,3 @@ commands: geyser: description: The main command for Geyser. usage: /geyser -permissions: - geyser.command.help: - description: Shows help for all registered commands. - default: true - geyser.command.offhand: - description: Puts an items in your offhand. - default: true - geyser.command.advancements: - description: Shows the advancements of the player on the server. - default: true - geyser.command.tooltips: - description: Toggles showing advanced tooltips on your items. - default: true - geyser.command.statistics: - description: Shows the statistics of the player on the server. - default: true - geyser.command.settings: - description: Modify user settings - default: true - geyser.command.list: - description: List all players connected through Geyser. - default: op - geyser.command.dump: - description: Dumps Geyser debug information for bug reports. - default: op - geyser.command.reload: - description: Reloads the Geyser configurations. Kicks all players when used! - default: false - geyser.command.version: - description: Shows the current Geyser version and checks for updates. - default: op diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index fa7989b43..8eba4d73d 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-sponge @@ -14,7 +14,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile @@ -48,7 +48,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0-SNAPSHOT + 3.3.0 package diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeConfiguration.java index b53160c29..29852aff0 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java index c947c34fd..e65684af2 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java index 7e0f2a410..4ab4e5346 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeMain.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeMain.java index c20b95cc1..553ad21d9 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeMain.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongeMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java index dcdeb53f5..7c01f18ce 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java index f20f94a79..f5d6613c7 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/GeyserSpongePlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java index 5b8496680..825d0bf78 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java index d6cc967a4..dce39870d 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/GeyserSpongeCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java index 07c0f410a..f57f3e276 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/geyser/platform/sponge/command/SpongeCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/pom.xml b/bootstrap/standalone/pom.xml index e8653ee8e..8ee94b793 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,19 +6,19 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-standalone - 2.16.0 + 2.17.1 org.geysermc core - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile @@ -47,17 +47,17 @@ org.jline jline-terminal - 3.20.0 + 3.21.0 org.jline jline-terminal-jna - 3.20.0 + 3.21.0 org.jline jline-reader - 3.20.0 + 3.21.0 org.apache.logging.log4j @@ -93,7 +93,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0-SNAPSHOT + 3.3.0 com.github.edwgiz @@ -132,7 +132,6 @@ implementation="com.github.edwgiz.mavenShadePlugin.log4j2CacheTransformer.PluginsCacheFileTransformer"> - ${project.build.directory}/dependency-reduced-pom.xml diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java index b599550e3..1e84e13d9 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -209,6 +209,7 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { return; } } + geyserLogger.setDebug(geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); // Allow libraries like Protocol to have their debug information passthrough @@ -275,6 +276,12 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { return Paths.get(System.getProperty("user.dir")); } + @Override + public Path getSavedUserLoginsFolder() { + // Return the location of the config + return new File(configFilename).getAbsoluteFile().getParentFile().toPath(); + } + @Override public BootstrapDumpInfo getDumpInfo() { return new GeyserStandaloneDumpInfo(this); diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneConfiguration.java index 9eb3eebd2..1102ed0a9 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneDumpInfo.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneDumpInfo.java index 7524578ec..109ca18f7 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneDumpInfo.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java index b585ebe7b..3bd2a3960 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/GeyserStandaloneLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java index d2b4656f0..6679c8950 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/LoopbackUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java index 83da038a1..03d780f3c 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/command/GeyserCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ANSIColor.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ANSIColor.java index 1d6057b8c..874f6d979 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ANSIColor.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ANSIColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ColorPane.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ColorPane.java index 0c8790ddd..c08f602d4 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ColorPane.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/ColorPane.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java index 56d211986..44faabdf5 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GeyserStandaloneGUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GraphPanel.java b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GraphPanel.java index 83100ddac..d8fca3e1b 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GraphPanel.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/geyser/platform/standalone/gui/GraphPanel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index e1e3331ef..36882a19e 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,7 +6,7 @@ org.geysermc bootstrap-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT bootstrap-velocity @@ -14,7 +14,7 @@ org.geysermc core - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile @@ -48,7 +48,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.3.0-SNAPSHOT + 3.3.0 package diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityConfiguration.java index 62e600290..4c8ea53cc 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java index c2d6d12a0..ffc7db291 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityInjector.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityInjector.java index 27cf9e815..e1a1030e3 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityInjector.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java index de9ea78d5..567870e7f 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityMain.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityMain.java index 35408ce9c..8e469b03b 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityMain.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java index a567233db..1a9b9bf26 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java index 8106192ac..6645ef595 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/GeyserVelocityPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java index 1034d6062..30f6c2efd 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java index 33f0d77c2..b42c8f76e 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/GeyserVelocityCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java index 3ef08d4e9..d5e4804ee 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/geyser/platform/velocity/command/VelocityCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/pom.xml b/common/pom.xml index 8e7be26f4..07fdb2b12 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,7 +6,7 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT common @@ -20,12 +20,12 @@ org.geysermc.cumulus cumulus - 1.0-SNAPSHOT + 1.1 com.google.code.gson gson - 2.8.6 + 2.8.9 \ No newline at end of file diff --git a/common/src/main/java/org/geysermc/common/PlatformType.java b/common/src/main/java/org/geysermc/common/PlatformType.java index 098fd3946..667d49a7a 100644 --- a/common/src/main/java/org/geysermc/common/PlatformType.java +++ b/common/src/main/java/org/geysermc/common/PlatformType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java b/common/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java index 619065836..86aba1ec4 100644 --- a/common/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java +++ b/common/src/main/java/org/geysermc/floodgate/crypto/AesCipher.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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/Floodgate + * 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.floodgate.crypto; diff --git a/common/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java b/common/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java index 54bfa0a4e..77dd46fde 100644 --- a/common/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java +++ b/common/src/main/java/org/geysermc/floodgate/crypto/AesKeyProducer.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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/Floodgate + * 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.floodgate.crypto; diff --git a/common/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java b/common/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java index 18fc5a04a..002a23f38 100644 --- a/common/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java +++ b/common/src/main/java/org/geysermc/floodgate/crypto/Base64Topping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java b/common/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java index 23497506a..2f7b442f4 100644 --- a/common/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java +++ b/common/src/main/java/org/geysermc/floodgate/crypto/FloodgateCipher.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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/Floodgate + * 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.floodgate.crypto; diff --git a/common/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java b/common/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java index fc2ac512d..4ee00f366 100644 --- a/common/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java +++ b/common/src/main/java/org/geysermc/floodgate/crypto/KeyProducer.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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/Floodgate + * 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.floodgate.crypto; diff --git a/common/src/main/java/org/geysermc/floodgate/crypto/Topping.java b/common/src/main/java/org/geysermc/floodgate/crypto/Topping.java index 689274269..3805c0bc5 100644 --- a/common/src/main/java/org/geysermc/floodgate/crypto/Topping.java +++ b/common/src/main/java/org/geysermc/floodgate/crypto/Topping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/NewsItem.java b/common/src/main/java/org/geysermc/floodgate/news/NewsItem.java index 5d9cd9d27..8ae28f422 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/NewsItem.java +++ b/common/src/main/java/org/geysermc/floodgate/news/NewsItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java b/common/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java index 78a8e4ed3..00e34b622 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java +++ b/common/src/main/java/org/geysermc/floodgate/news/NewsItemAction.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java b/common/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java index b11605fb4..9c2f3d15d 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java +++ b/common/src/main/java/org/geysermc/floodgate/news/NewsItemMessage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/NewsType.java b/common/src/main/java/org/geysermc/floodgate/news/NewsType.java index 8976cc6b6..ed7c1553b 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/NewsType.java +++ b/common/src/main/java/org/geysermc/floodgate/news/NewsType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java b/common/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java index 5cc574a57..f2ad6b309 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java +++ b/common/src/main/java/org/geysermc/floodgate/news/data/AnnouncementData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java b/common/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java index f13d5fd7b..7f2c7360f 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java +++ b/common/src/main/java/org/geysermc/floodgate/news/data/BuildSpecificData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java b/common/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java index 2545a97da..1e5fef4d6 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java +++ b/common/src/main/java/org/geysermc/floodgate/news/data/CheckAfterData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java b/common/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java index 8d05c93db..1479d20a1 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java +++ b/common/src/main/java/org/geysermc/floodgate/news/data/ConfigSpecificData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/news/data/ItemData.java b/common/src/main/java/org/geysermc/floodgate/news/data/ItemData.java index 122ee775d..64a1aedf3 100644 --- a/common/src/main/java/org/geysermc/floodgate/news/data/ItemData.java +++ b/common/src/main/java/org/geysermc/floodgate/news/data/ItemData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java new file mode 100644 index 000000000..37c5d4015 --- /dev/null +++ b/common/src/main/java/org/geysermc/floodgate/pluginmessage/PluginMessageChannels.java @@ -0,0 +1,45 @@ +/* + * 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.floodgate.pluginmessage; + +import com.google.common.base.Charsets; + +public final class PluginMessageChannels { + public static final String SKIN = "floodgate:skin"; + public static final String FORM = "floodgate:form"; + public static final String TRANSFER = "floodgate:transfer"; + + private static final byte[] FLOODGATE_REGISTER_DATA = String.join("\0", SKIN, FORM, TRANSFER).getBytes(Charsets.UTF_8); + + /** + * Get the prebuilt register data as a byte array + * + * @return the register data of the Floodgate channels + */ + public static byte[] getFloodgateRegisterData() { + return FLOODGATE_REGISTER_DATA; + } +} diff --git a/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java index 31696d97a..95fc62229 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java +++ b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java index f56d3a8c0..ef7709859 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java +++ b/common/src/main/java/org/geysermc/floodgate/util/DeviceOs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/util/FloodgateInfoHolder.java b/common/src/main/java/org/geysermc/floodgate/util/FloodgateInfoHolder.java index c7a681f9d..28b59b4a7 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/FloodgateInfoHolder.java +++ b/common/src/main/java/org/geysermc/floodgate/util/FloodgateInfoHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/common/src/main/java/org/geysermc/floodgate/util/InputMode.java b/common/src/main/java/org/geysermc/floodgate/util/InputMode.java index 3ce51634d..2bcfb88fb 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/InputMode.java +++ b/common/src/main/java/org/geysermc/floodgate/util/InputMode.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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 + * 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.floodgate.util; diff --git a/common/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java b/common/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java index 698e4522c..e0630d48c 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java +++ b/common/src/main/java/org/geysermc/floodgate/util/InvalidFormatException.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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 + * 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.floodgate.util; diff --git a/common/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java b/common/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java index f91bfafbc..681080a30 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java +++ b/common/src/main/java/org/geysermc/floodgate/util/LinkedPlayer.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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 + * 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.floodgate.util; diff --git a/common/src/main/java/org/geysermc/floodgate/util/UiProfile.java b/common/src/main/java/org/geysermc/floodgate/util/UiProfile.java index 298aaea83..d93042277 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/UiProfile.java +++ b/common/src/main/java/org/geysermc/floodgate/util/UiProfile.java @@ -1,27 +1,26 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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: + * 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 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 + * 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.floodgate.util; diff --git a/common/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java b/common/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java index b570d7b3d..61e6c63b1 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java +++ b/common/src/main/java/org/geysermc/floodgate/util/WebsocketEventType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/pom.xml b/core/pom.xml index de264f908..6fe54f8d5 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -6,14 +6,14 @@ org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT core 4.9.3 8.5.2 - 2.12.4 + 2.13.2 4.1.66.Final @@ -21,19 +21,19 @@ org.geysermc ap - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT provided org.geysermc geyser-api - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile org.geysermc common - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT compile @@ -52,7 +52,7 @@ com.fasterxml.jackson.core jackson-databind - ${jackson.version} + ${jackson.version}.1 compile @@ -72,7 +72,7 @@ com.nukkitx nbt - 2.1.0 + 2.2.1 compile @@ -83,7 +83,7 @@ com.nukkitx.fastutil - fastutil-long-long-maps + fastutil-int-long-maps ${fastutil.version} compile @@ -120,8 +120,8 @@ com.github.CloudburstMC.Protocol - bedrock-v475 - c22aa595 + bedrock-beta + be0cc73 compile @@ -147,23 +147,23 @@ - com.github.RednedEpic + com.github.GeyserMC MCAuthLib - 6c99331 + d9d773e compile - com.github.GeyserMC - MCProtocolLib - c247b1f + com.github.steveice10 + mcprotocollib + 1.19-SNAPSHOT compile - com.github.steveice10 + com.github.GeyserMC packetlib - com.github.steveice10 + com.github.GeyserMC mcauthlib @@ -171,7 +171,7 @@ com.github.steveice10 packetlib - 2.1-SNAPSHOT + 3.0 compile diff --git a/core/src/main/java/org/geysermc/connector/GeyserConnector.java b/core/src/main/java/org/geysermc/connector/GeyserConnector.java index 0ecc40c7e..b3307a134 100644 --- a/core/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/core/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 05f9de722..890290a01 100644 --- a/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -64,7 +64,7 @@ public class GeyserSession { } public int getRenderDistance() { - return this.handle.getRenderDistance(); + return this.handle.getServerRenderDistance(); } public boolean isSentSpawnPacket() { @@ -100,7 +100,7 @@ public class GeyserSession { } public void login() { - this.handle.login(); + throw new UnsupportedOperationException(); } public void authenticate(String username) { @@ -120,7 +120,7 @@ public class GeyserSession { } public void close() { - this.handle.close(); + throw new UnsupportedOperationException(); } public void executeInEventLoop(Runnable runnable) { diff --git a/core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java b/core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java index 3c9a5ee72..6b8e53d8e 100644 --- a/core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java +++ b/core/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/Constants.java b/core/src/main/java/org/geysermc/geyser/Constants.java index 23029d195..23fb76d16 100644 --- a/core/src/main/java/org/geysermc/geyser/Constants.java +++ b/core/src/main/java/org/geysermc/geyser/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,6 +37,8 @@ public final class Constants { public static final String FLOODGATE_DOWNLOAD_LOCATION = "https://ci.opencollab.dev/job/GeyserMC/job/Floodgate/job/master/"; + static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json"; + static { URI wsUri = null; try { diff --git a/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java b/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java index df7a049c6..0aa1d39c3 100644 --- a/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java +++ b/core/src/main/java/org/geysermc/geyser/FloodgateKeyLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -43,7 +43,7 @@ public class FloodgateKeyLoader { if (floodgateDataFolder != null) { Path autoKey = floodgateDataFolder.resolve("key.pem"); if (Files.exists(autoKey)) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); + logger.debug(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); return autoKey; } else { logger.error(GeyserLocale.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key")); @@ -52,7 +52,7 @@ public class FloodgateKeyLoader { Path floodgateKey; if (config.getFloodgateKeyFile().equals("public-key.pem")) { - logger.info("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead"); + logger.debug("Floodgate 2.0 doesn't use a public/private key system anymore. We'll search for key.pem instead"); floodgateKey = geyserDataFolder.resolve("key.pem"); } else { floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile()); diff --git a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java index 8797d972a..d40060310 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -97,6 +97,13 @@ public interface GeyserBootstrap { */ Path getConfigFolder(); + /** + * @return the folder where user tokens are saved. This should always point to the location of the config. + */ + default Path getSavedUserLoginsFolder() { + return getConfigFolder(); + } + /** * Information used for the bootstrap section of the debug dump * diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index bac5e0735..0cea9fbac 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser; import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.steveice10.packetlib.tcp.TcpSession; @@ -37,6 +38,7 @@ import io.netty.channel.kqueue.KQueue; import io.netty.util.NettyRuntime; import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.internal.SystemPropertyUtil; +import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; @@ -59,9 +61,12 @@ import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.PendingMicrosoftAuthentication; import org.geysermc.geyser.session.SessionManager; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.skin.FloodgateSkinUploader; +import org.geysermc.geyser.skin.SkinProvider; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; @@ -70,6 +75,9 @@ import org.geysermc.geyser.util.*; import javax.naming.directory.Attribute; import javax.naming.directory.InitialDirContext; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -77,6 +85,7 @@ import java.net.UnknownHostException; import java.security.Key; import java.text.DecimalFormat; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.regex.Matcher; @@ -112,35 +121,36 @@ public class GeyserImpl implements GeyserApi { private FloodgateCipher cipher; private FloodgateSkinUploader skinUploader; - private final NewsHandler newsHandler; + private NewsHandler newsHandler; private volatile boolean shuttingDown = false; - private final ScheduledExecutorService scheduledThread; + private ScheduledExecutorService scheduledThread; - private final BedrockServer bedrockServer; + private BedrockServer bedrockServer; private final PlatformType platformType; private final GeyserBootstrap bootstrap; - private final Metrics metrics; + private Metrics metrics; + + private PendingMicrosoftAuthentication pendingMicrosoftAuthentication; + @Getter(AccessLevel.NONE) + private Map savedRefreshTokens; private static GeyserImpl instance; private GeyserImpl(PlatformType platformType, GeyserBootstrap bootstrap) { - long startupTime = System.currentTimeMillis(); - - this.bootstrap = bootstrap; - instance = this; Geyser.set(this); - GeyserLogger logger = bootstrap.getGeyserLogger(); - GeyserConfiguration config = bootstrap.getGeyserConfig(); - this.platformType = platformType; + this.bootstrap = bootstrap; + + long startupTime = System.currentTimeMillis(); GeyserLocale.finalizeDefaultLocale(this); + GeyserLogger logger = bootstrap.getGeyserLogger(); logger.info("******************************************"); logger.info(""); @@ -148,10 +158,6 @@ public class GeyserImpl implements GeyserApi { logger.info(""); logger.info("******************************************"); - this.scheduledThread = Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("Geyser Scheduled Thread")); - - logger.setDebug(config.isDebugMode()); - /* Initialize translators and registries */ BlockRegistries.init(); Registries.init(); @@ -160,8 +166,49 @@ public class GeyserImpl implements GeyserApi { ItemTranslator.init(); MessageTranslator.init(); MinecraftLocale.init(); + + start(); + + GeyserConfiguration config = bootstrap.getGeyserConfig(); + + boolean isGui = false; + // This will check if we are in standalone and get the 'useGui' variable from there + if (platformType == PlatformType.STANDALONE) { + try { + Class cls = Class.forName("org.geysermc.geyser.platform.standalone.GeyserStandaloneBootstrap"); + isGui = (boolean) cls.getMethod("isUseGui").invoke(cls.cast(bootstrap)); + } catch (Exception e) { + logger.debug("Failed detecting if standalone is using a GUI; if this is a GeyserConnect instance this can be safely ignored."); + } + } + + double completeTime = (System.currentTimeMillis() - startupTime) / 1000D; + String message = GeyserLocale.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime)) + " "; + if (isGui) { + message += GeyserLocale.getLocaleStringLog("geyser.core.finish.gui"); + } else { + message += GeyserLocale.getLocaleStringLog("geyser.core.finish.console"); + } + + logger.info(message); + + if (platformType == PlatformType.STANDALONE) { + logger.warning(GeyserLocale.getLocaleStringLog("geyser.core.movement_warn")); + } else if (config.getRemote().getAuthType() == AuthType.FLOODGATE) { + VersionCheckUtils.checkForOutdatedFloodgate(logger); + } + } + + private void start() { + this.scheduledThread = Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("Geyser Scheduled Thread")); + + GeyserLogger logger = bootstrap.getGeyserLogger(); + GeyserConfiguration config = bootstrap.getGeyserConfig(); + ScoreboardUpdater.init(); + SkinProvider.registerCacheImageTask(this); + ResourcePack.loadPacks(); if (platformType != PlatformType.STANDALONE && config.getRemote().getAddress().equals("auto")) { @@ -202,18 +249,6 @@ public class GeyserImpl implements GeyserApi { // Ensure that PacketLib does not create an event loop for handling packets; we'll do that ourselves TcpSession.USE_EVENT_LOOP_FOR_PACKETS = false; - if (config.getRemote().getAuthType() == AuthType.FLOODGATE) { - try { - Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath()); - cipher = new AesCipher(new Base64Topping()); - cipher.init(key); - logger.info(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); - skinUploader = new FloodgateSkinUploader(this).start(); - } catch (Exception exception) { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); - } - } - String branch = "unknown"; int buildNumber = -1; if (this.productionEnvironment()) { @@ -231,7 +266,10 @@ public class GeyserImpl implements GeyserApi { } else { logger.debug("Not getting git properties for the news handler as we are in a development environment."); } - newsHandler = new NewsHandler(branch, buildNumber); + + pendingMicrosoftAuthentication = new PendingMicrosoftAuthentication(config.getPendingAuthenticationTimeout()); + + this.newsHandler = new NewsHandler(branch, buildNumber); CooldownUtils.setDefaultShowCooldown(config.getShowCooldown()); DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether @@ -271,19 +309,39 @@ public class GeyserImpl implements GeyserApi { if (shouldStartListener) { bedrockServer.bind().whenComplete((avoid, throwable) -> { if (throwable == null) { - logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); + logger.info(GeyserLocale.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), + String.valueOf(config.getBedrock().getPort()))); } else { - logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); - throwable.printStackTrace(); + String address = config.getBedrock().getAddress(); + int port = config.getBedrock().getPort(); + logger.severe(GeyserLocale.getLocaleStringLog("geyser.core.fail", address, String.valueOf(port))); + if (!"0.0.0.0".equals(address)) { + logger.info(ChatColor.GREEN + "Suggestion: try setting `address` under `bedrock` in the Geyser config back to 0.0.0.0"); + logger.info(ChatColor.GREEN + "Then, restart this server."); + } } }).join(); } + if (config.getRemote().getAuthType() == AuthType.FLOODGATE) { + try { + Key key = new AesKeyProducer().produceFrom(config.getFloodgateKeyPath()); + cipher = new AesCipher(new Base64Topping()); + cipher.init(key); + logger.debug(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); + // Note: this is positioned after the bind so the skin uploader doesn't try to run if Geyser fails + // to load successfully. Spigot complains about class loader if the plugin is disabled. + skinUploader = new FloodgateSkinUploader(this).start(); + } catch (Exception exception) { + logger.severe(GeyserLocale.getLocaleStringLog("geyser.auth.floodgate.bad_key"), exception); + } + } + if (config.getMetrics().isEnabled()) { metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger("")); metrics.addCustomChart(new Metrics.SingleLineChart("players", sessionManager::size)); // Prevent unwanted words best we can - metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> config.getRemote().getAuthType().toString().toLowerCase())); + metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> config.getRemote().getAuthType().toString().toLowerCase(Locale.ROOT))); metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::getPlatformName)); metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", GeyserLocale::getDefaultLocale)); metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserImpl.VERSION)); @@ -367,30 +425,45 @@ public class GeyserImpl implements GeyserApi { metrics = null; } - boolean isGui = false; - // This will check if we are in standalone and get the 'useGui' variable from there - if (platformType == PlatformType.STANDALONE) { - try { - Class cls = Class.forName("org.geysermc.geyser.platform.standalone.GeyserStandaloneBootstrap"); - isGui = (boolean) cls.getMethod("isUseGui").invoke(cls.cast(bootstrap)); - } catch (Exception e) { - logger.debug("Failed detecting if standalone is using a GUI; if this is a GeyserConnect instance this can be safely ignored."); + if (config.getRemote().getAuthType() == AuthType.ONLINE) { + if (config.getUserAuths() != null && !config.getUserAuths().isEmpty()) { + getLogger().warning("The 'userAuths' config section is now deprecated, and will be removed in the near future! " + + "Please migrate to the new 'saved-user-logins' config option: " + + "https://wiki.geysermc.org/geyser/understanding-the-config/"); } - } - double completeTime = (System.currentTimeMillis() - startupTime) / 1000D; - String message = GeyserLocale.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime)) + " "; - if (isGui) { - message += GeyserLocale.getLocaleStringLog("geyser.core.finish.gui"); + // May be written/read to on multiple threads from each GeyserSession as well as writing the config + savedRefreshTokens = new ConcurrentHashMap<>(); + + File tokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); + if (tokensFile.exists()) { + TypeReference> type = new TypeReference<>() { }; + + Map refreshTokenFile = null; + try { + refreshTokenFile = JSON_MAPPER.readValue(tokensFile, type); + } catch (IOException e) { + logger.error("Cannot load saved user tokens!", e); + } + if (refreshTokenFile != null) { + List validUsers = config.getSavedUserLogins(); + boolean doWrite = false; + for (Map.Entry entry : refreshTokenFile.entrySet()) { + String user = entry.getKey(); + if (!validUsers.contains(user)) { + // Perform a write to this file to purge the now-unused name + doWrite = true; + continue; + } + savedRefreshTokens.put(user, entry.getValue()); + } + if (doWrite) { + scheduleRefreshTokensWrite(); + } + } + } } else { - message += GeyserLocale.getLocaleStringLog("geyser.core.finish.console"); - } - logger.info(message); - - if (platformType == PlatformType.STANDALONE) { - logger.warning(GeyserLocale.getLocaleStringLog("geyser.core.movement_warn")); - } else if (config.getRemote().getAuthType() == AuthType.FLOODGATE) { - VersionCheckUtils.checkForOutdatedFloodgate(logger); + savedRefreshTokens = null; } newsHandler.handleNews(null, NewsItemAction.ON_SERVER_STARTED); @@ -447,6 +520,8 @@ public class GeyserImpl implements GeyserApi { newsHandler.shutdown(); this.getCommandManager().getCommands().clear(); + ResourcePack.PACKS.clear(); + bootstrap.getGeyserLogger().info(GeyserLocale.getLocaleStringLog("geyser.core.shutdown.done")); } @@ -469,7 +544,17 @@ public class GeyserImpl implements GeyserApi { } public static GeyserImpl start(PlatformType platformType, GeyserBootstrap bootstrap) { - return new GeyserImpl(platformType, bootstrap); + if (instance == null) { + return new GeyserImpl(platformType, bootstrap); + } + + // We've been reloaded + if (instance.isShuttingDown()) { + instance.shuttingDown = false; + instance.start(); + } + + return instance; } public GeyserLogger getLogger() { @@ -488,6 +573,39 @@ public class GeyserImpl implements GeyserApi { return bootstrap.getWorldManager(); } + @Nullable + public String refreshTokenFor(@NonNull String bedrockName) { + return savedRefreshTokens.get(bedrockName); + } + + public void saveRefreshToken(@NonNull String bedrockName, @NonNull String refreshToken) { + if (!getConfig().getSavedUserLogins().contains(bedrockName)) { + // Do not save this login + return; + } + + // We can safely overwrite old instances because MsaAuthenticationService#getLoginResponseFromRefreshToken + // refreshes the token for us + if (!Objects.equals(refreshToken, savedRefreshTokens.put(bedrockName, refreshToken))) { + scheduleRefreshTokensWrite(); + } + } + + private void scheduleRefreshTokensWrite() { + scheduledThread.execute(() -> { + // Ensure all writes are handled on the same thread + File savedTokens = getBootstrap().getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile(); + TypeReference> type = new TypeReference<>() { }; + try (FileWriter writer = new FileWriter(savedTokens)) { + JSON_MAPPER.writerFor(type) + .withDefaultPrettyPrinter() + .writeValue(writer, savedRefreshTokens); + } catch (IOException e) { + getLogger().error("Unable to write saved refresh tokens!", e); + } + }); + } + public static GeyserImpl getInstance() { return instance; } diff --git a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java index 266132f63..b47801cb5 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserLogger.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,6 +25,8 @@ package org.geysermc.geyser; +import javax.annotation.Nullable; + public interface GeyserLogger { /** @@ -78,6 +80,15 @@ public interface GeyserLogger { */ void debug(String message); + /** + * Logs an object to console if debug mode is enabled + * + * @param object the object to log + */ + default void debug(@Nullable Object object) { + debug(String.valueOf(object)); + } + /** * Sets if the logger should print debug messages * diff --git a/core/src/main/java/org/geysermc/geyser/GeyserMain.java b/core/src/main/java/org/geysermc/geyser/GeyserMain.java index 9ddbbbe86..8726c1b24 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserMain.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java b/core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java index de66c2fe3..5fa5f688b 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java b/core/src/main/java/org/geysermc/geyser/command/CommandManager.java index 5e4fe3dd5..60af8c4e5 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandManager.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/CommandSender.java b/core/src/main/java/org/geysermc/geyser/command/CommandSender.java index 962883e3d..d9d1bcfbc 100644 --- a/core/src/main/java/org/geysermc/geyser/command/CommandSender.java +++ b/core/src/main/java/org/geysermc/geyser/command/CommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java index 6971ad44d..a22c69c04 100644 --- a/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/GeyserCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -86,4 +86,13 @@ public abstract class GeyserCommand { public boolean isBedrockOnly() { return false; } + + /** + * Used for permission defaults on server implementations. + * + * @return if this command is designated to be used only by server operators. + */ + public boolean isSuggestedOpOnly() { + return false; + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java index edd4691e3..18546c914 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancedTooltipsCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java index 41bb8e6cd..169158572 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/AdvancementsCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java index 1b69f48fb..0bac381ba 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/DumpCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -145,4 +145,9 @@ public class DumpCommand extends GeyserCommand { public List getSubCommands() { return Arrays.asList("offline", "full", "logs"); } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java index 633912300..85682b294 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/HelpCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java index 3ff648570..0a4cfa023 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ListCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -51,4 +51,9 @@ public class ListCommand extends GeyserCommand { sender.sendMessage(message); } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } 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 934cd8c87..b0d0e1ce6 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,11 +28,11 @@ 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 com.nukkitx.math.vector.Vector3i; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.command.GeyserCommand; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.BlockUtils; public class OffhandCommand extends GeyserCommand { @@ -46,8 +46,8 @@ public class OffhandCommand extends GeyserCommand { return; } - ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, BlockUtils.POSITION_ZERO, - Direction.DOWN); + ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, + Direction.DOWN, session.getNextSequence()); session.sendDownstreamPacket(releaseItemPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java index 1a72e1734..e970e5d3d 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/ReloadCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -54,4 +54,9 @@ public class ReloadCommand extends GeyserCommand { geyser.getSessionManager().disconnectAll("geyser.commands.reload.kick"); geyser.reload(); } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java index 349f7288b..58d778ba9 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/SettingsCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java index c570770b7..e54b0fb9b 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StatisticsCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java index 6b74f9c8b..9c7bd8140 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/StopCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -54,4 +54,9 @@ public class StopCommand extends GeyserCommand { geyser.getBootstrap().onDisable(); } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java index 4dd93ee74..f4f62892a 100644 --- a/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java +++ b/core/src/main/java/org/geysermc/geyser/command/defaults/VersionCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -100,4 +100,9 @@ public class VersionCommand extends GeyserCommand { } } } + + @Override + public boolean isSuggestedOpOnly() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/configuration/EmoteOffhandWorkaroundOption.java b/core/src/main/java/org/geysermc/geyser/configuration/EmoteOffhandWorkaroundOption.java index 87421ad92..fd44d3903 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/EmoteOffhandWorkaroundOption.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/EmoteOffhandWorkaroundOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 57cb5fb09..1f188cf40 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -44,6 +44,9 @@ public interface GeyserConfiguration { IRemoteConfiguration getRemote(); + List getSavedUserLogins(); + + @Deprecated Map getUserAuths(); boolean isCommandSuggestions(); @@ -76,6 +79,10 @@ public interface GeyserConfiguration { boolean isShowCoordinates(); + boolean isDisableBedrockScaffolding(); + + boolean isAlwaysQuickChangeArmor(); + EmoteOffhandWorkaroundOption getEmoteOffhandWorkaround(); String getDefaultLocale(); @@ -94,8 +101,14 @@ public interface GeyserConfiguration { boolean isAllowCustomSkulls(); + int getMaxVisibleCustomSkulls(); + + int getCustomSkullRenderDistance(); + IMetricsInfo getMetrics(); + int getPendingAuthenticationTimeout(); + interface IBedrockConfiguration { String getAddress(); 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 e3c937aae..30a947e53 100644 --- a/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java +++ b/core/src/main/java/org/geysermc/geyser/configuration/GeyserJacksonConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,9 +35,9 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.text.AsteriskSerializer; -import org.geysermc.geyser.network.CIDRMatcher; import org.geysermc.geyser.text.GeyserLocale; import java.io.IOException; @@ -62,6 +62,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration private BedrockConfiguration bedrock = new BedrockConfiguration(); private RemoteConfiguration remote = new RemoteConfiguration(); + @JsonProperty("saved-user-logins") + private List savedUserLogins = Collections.emptyList(); + @JsonProperty("floodgate-key-file") private String floodgateKeyFile = "key.pem"; @@ -105,6 +108,12 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("show-coordinates") private boolean showCoordinates = true; + @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; @@ -121,6 +130,12 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @JsonProperty("allow-custom-skulls") private boolean allowCustomSkulls = true; + @JsonProperty("max-visible-custom-skulls") + private int maxVisibleCustomSkulls = 128; + + @JsonProperty("custom-skull-render-distance") + private int customSkullRenderDistance = 32; + @JsonProperty("add-non-bedrock-items") private boolean addNonBedrockItems = true; @@ -135,6 +150,9 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration private MetricsInfo metrics = new MetricsInfo(); + @JsonProperty("pending-authentication-timeout") + private int pendingAuthenticationTimeout = 120; + @Getter @JsonIgnoreProperties(ignoreUnknown = true) public static class BedrockConfiguration implements IBedrockConfiguration { @@ -228,8 +246,21 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration public static class MetricsInfo implements IMetricsInfo { private boolean enabled = true; + @JsonDeserialize(using = MetricsIdDeserializer.class) @JsonProperty("uuid") private String uniqueId = UUID.randomUUID().toString(); + + private static class MetricsIdDeserializer extends JsonDeserializer { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String uuid = p.getValueAsString(); + if ("generateduuid".equals(uuid)) { + // Compensate for configs not copied from the jar + return UUID.randomUUID().toString(); + } + return uuid; + } + } } @JsonProperty("scoreboard-packet-threshold") diff --git a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java index 6b421f912..0bbc1c0ed 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/BootstrapDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java index 7d4807050..1c9be8c3e 100644 --- a/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java +++ b/core/src/main/java/org/geysermc/geyser/dump/DumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -40,6 +40,7 @@ import org.geysermc.geyser.text.AsteriskSerializer; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.CpuUtils; import org.geysermc.geyser.util.FileUtils; import org.geysermc.geyser.util.WebUtils; import org.geysermc.floodgate.util.DeviceOs; @@ -54,10 +55,7 @@ import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import java.nio.file.Paths; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; +import java.util.*; import java.util.stream.Collectors; @Getter @@ -67,6 +65,9 @@ public class DumpInfo { private final DumpInfo.VersionInfo versionInfo; private final int cpuCount; + private final String cpuName; + private final Locale systemLocale; + private final String systemEncoding; private Properties gitInfo; private final GeyserConfiguration config; private final Floodgate floodgate; @@ -81,6 +82,9 @@ public class DumpInfo { this.versionInfo = new VersionInfo(); this.cpuCount = Runtime.getRuntime().availableProcessors(); + this.cpuName = CpuUtils.tryGetProcessorName(); + this.systemLocale = Locale.getDefault(); + this.systemEncoding = System.getProperty("file.encoding"); try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource("git.properties")) { this.gitInfo = new Properties(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index f66a0c56b..566b3daff 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -32,7 +32,6 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import lombok.Setter; import lombok.experimental.Accessors; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.entity.factory.BaseEntityFactory; import org.geysermc.geyser.entity.factory.EntityFactory; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.registry.Registries; @@ -52,10 +51,6 @@ import java.util.function.BiConsumer; public record EntityDefinition(EntityFactory factory, EntityType entityType, String identifier, float width, float height, float offset, List> translators) { - public static Builder inherited(BaseEntityFactory factory, EntityDefinition parent) { - return inherited((EntityFactory) factory, parent); - } - public static Builder inherited(EntityFactory factory, EntityDefinition parent) { return new Builder<>(factory, parent.entityType, parent.identifier, parent.width, parent.height, parent.offset, new ObjectArrayList<>(parent.translators)); } @@ -64,7 +59,6 @@ public record EntityDefinition(EntityFactory factory, Entit return new Builder<>(factory); } - public void translateMetadata(T entity, EntityMetadata> metadata) { EntityMetadataTranslator>> translator = (EntityMetadataTranslator>>) this.translators.get(metadata.getId()); if (translator == null) { 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 e1f2169ef..73814628f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,9 +31,6 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEnt import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.geyser.entity.factory.BaseEntityFactory; -import org.geysermc.geyser.entity.factory.ExperienceOrbEntityFactory; -import org.geysermc.geyser.entity.factory.PaintingEntityFactory; import org.geysermc.geyser.entity.type.*; import org.geysermc.geyser.entity.type.living.*; import org.geysermc.geyser.entity.type.living.animal.*; @@ -50,10 +47,11 @@ import org.geysermc.geyser.entity.type.living.monster.raid.RaidParticipantEntity import org.geysermc.geyser.entity.type.living.monster.raid.SpellcasterIllagerEntity; import org.geysermc.geyser.entity.type.living.monster.raid.VindicatorEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.translator.text.MessageTranslator; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.translator.text.MessageTranslator; public final class EntityDefinitions { + public static final EntityDefinition ALLAY; public static final EntityDefinition AREA_EFFECT_CLOUD; public static final EntityDefinition ARMOR_STAND; public static final EntityDefinition ARROW; @@ -66,11 +64,12 @@ public final class EntityDefinitions { public static final EntityDefinition CAVE_SPIDER; public static final EntityDefinition CHEST_MINECART; public static final EntityDefinition CHICKEN; + public static final EntityDefinition CHEST_BOAT; public static final EntityDefinition COD; public static final EntityDefinition COMMAND_BLOCK_MINECART; - public static final EntityDefinition COW; + public static final EntityDefinition COW; public static final EntityDefinition CREEPER; - public static final EntityDefinition DOLPHIN; + public static final EntityDefinition DOLPHIN; public static final EntityDefinition DONKEY; public static final EntityDefinition DRAGON_FIREBALL; public static final EntityDefinition DROWNED; @@ -82,7 +81,7 @@ public final class EntityDefinitions { public static final EntityDefinition ENDER_PEARL; public static final EntityDefinition END_CRYSTAL; public static final EntityDefinition EVOKER; - public static final EntityDefinition EVOKER_FANGS; + public static final EntityDefinition EVOKER_FANGS; public static final EntityDefinition EXPERIENCE_BOTTLE; public static final EntityDefinition EXPERIENCE_ORB; public static final EntityDefinition EYE_OF_ENDER; @@ -91,6 +90,7 @@ public final class EntityDefinitions { public static final EntityDefinition FIREWORK_ROCKET; public static final EntityDefinition FISHING_BOBBER; public static final EntityDefinition FOX; + public static final EntityDefinition FROG; public static final EntityDefinition FURNACE_MINECART; // Not present on Bedrock public static final EntityDefinition GHAST; public static final EntityDefinition GIANT; @@ -135,7 +135,7 @@ public final class EntityDefinitions { public static final EntityDefinition SHULKER_BULLET; public static final EntityDefinition SILVERFISH; public static final EntityDefinition SKELETON; - public static final EntityDefinition SKELETON_HORSE; + public static final EntityDefinition SKELETON_HORSE; public static final EntityDefinition SLIME; public static final EntityDefinition SMALL_FIREBALL; public static final EntityDefinition SNOWBALL; @@ -146,6 +146,7 @@ public final class EntityDefinitions { public static final EntityDefinition SQUID; public static final EntityDefinition STRAY; public static final EntityDefinition STRIDER; + public static final EntityDefinition TADPOLE; public static final EntityDefinition TNT; public static final EntityDefinition TNT_MINECART; public static final EntityDefinition TRADER_LLAMA; @@ -156,6 +157,7 @@ public final class EntityDefinitions { public static final EntityDefinition VILLAGER; public static final EntityDefinition VINDICATOR; public static final EntityDefinition WANDERING_TRADER; + public static final EntityDefinition WARDEN; public static final EntityDefinition WITCH; public static final EntityDefinition WITHER; public static final EntityDefinition WITHER_SKELETON; @@ -163,7 +165,7 @@ public final class EntityDefinitions { public static final EntityDefinition WOLF; public static final EntityDefinition ZOGLIN; public static final EntityDefinition ZOMBIE; - public static final EntityDefinition ZOMBIE_HORSE; + public static final EntityDefinition ZOMBIE_HORSE; public static final EntityDefinition ZOMBIE_VILLAGER; public static final EntityDefinition ZOMBIFIED_PIGLIN; @@ -177,14 +179,14 @@ public final class EntityDefinitions { public static final EntityDefinition WITHER_SKULL_DANGEROUS; static { - EntityDefinition entityBase = EntityDefinition.builder((BaseEntityFactory) Entity::new) + EntityDefinition entityBase = EntityDefinition.builder(Entity::new) .addTranslator(MetadataType.BYTE, Entity::setFlags) .addTranslator(MetadataType.INT, Entity::setAir) // Air/bubbles .addTranslator(MetadataType.OPTIONAL_CHAT, Entity::setDisplayName) .addTranslator(MetadataType.BOOLEAN, Entity::setDisplayNameVisible) - .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.SILENT, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) + .addTranslator(MetadataType.BOOLEAN, Entity::setSilent) .addTranslator(MetadataType.BOOLEAN, Entity::setGravity) - .addTranslator(MetadataType.POSE, Entity::setPose) + .addTranslator(MetadataType.POSE, (entity, entityMetadata) -> entity.setPose(entityMetadata.getValue())) .addTranslator(MetadataType.INT, Entity::setFreezing) .build(); @@ -212,6 +214,9 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight) .addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityData.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything .build(); + CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT) + .type(EntityType.CHEST_BOAT) + .build(); DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) .type(EntityType.DRAGON_FIREBALL) .heightAndWidth(1.0f) @@ -224,11 +229,11 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, (enderCrystalEntity, entityMetadata) -> enderCrystalEntity.setFlag(EntityFlag.SHOW_BOTTOM, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) // There is a base located on the ender crystal .build(); - EXPERIENCE_ORB = EntityDefinition.inherited((ExperienceOrbEntityFactory) ExpOrbEntity::new, entityBase) + EXPERIENCE_ORB = EntityDefinition.inherited(null, entityBase) .type(EntityType.EXPERIENCE_ORB) .identifier("minecraft:xp_orb") .build(); - EVOKER_FANGS = EntityDefinition.inherited(entityBase.factory(), entityBase) + EVOKER_FANGS = EntityDefinition.builder(EvokerFangsEntity::new) // No entity metadata to listen to as of 1.18.1 .type(EntityType.EVOKER_FANGS) .height(0.8f).width(0.5f) .identifier("minecraft:evocation_fang") @@ -275,8 +280,9 @@ public final class EntityDefinitions { .type(EntityType.LLAMA_SPIT) .heightAndWidth(0.25f) .build(); - PAINTING = EntityDefinition.inherited((PaintingEntityFactory) PaintingEntity::new, entityBase) + PAINTING = EntityDefinition.inherited(null, entityBase) .type(EntityType.PAINTING) + .addTranslator(MetadataType.PAINTING_VARIANT, PaintingEntity::setPaintingType) .build(); SHULKER_BULLET = EntityDefinition.inherited(ThrowableEntity::new, entityBase) .type(EntityType.SHULKER_BULLET) @@ -444,6 +450,10 @@ public final class EntityDefinitions { // Extends mob { + ALLAY = EntityDefinition.inherited(AllayEntity::new, mobEntityBase) + .type(EntityType.ALLAY) + .height(0.6f).width(0.35f) + .build(); BAT = EntityDefinition.inherited(BatEntity::new, mobEntityBase) .type(EntityType.BAT) .height(0.9f).width(0.5f) @@ -462,7 +472,7 @@ public final class EntityDefinitions { .addTranslator(MetadataType.BOOLEAN, (entity, entityMetadata) -> entity.setFlag(EntityFlag.POWERED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataType.BOOLEAN, CreeperEntity::setIgnited) .build(); - DOLPHIN = EntityDefinition.inherited(WaterEntity::new, mobEntityBase) + DOLPHIN = EntityDefinition.inherited(DolphinEntity::new, mobEntityBase) .type(EntityType.DOLPHIN) .height(0.6f).width(0.9f) //TODO check @@ -553,6 +563,11 @@ public final class EntityDefinitions { .height(0.8f).width(0.4f) .addTranslator(MetadataType.BYTE, VexEntity::setVexFlags) .build(); + WARDEN = EntityDefinition.inherited(WardenEntity::new, mobEntityBase) + .type(EntityType.WARDEN) + .height(2.9f).width(0.9f) + .addTranslator(MetadataType.INT, WardenEntity::setAngerLevel) + .build(); WITHER = EntityDefinition.inherited(WitherEntity::new, mobEntityBase) .type(EntityType.WITHER) .height(3.5f).width(0.9f) @@ -637,6 +652,10 @@ public final class EntityDefinitions { .type(EntityType.SALMON) .height(0.5f).width(0.7f) .build(); + TADPOLE = EntityDefinition.inherited(TadpoleEntity::new, abstractFishEntityBase) + .type(EntityType.TADPOLE) + .height(0.3f).width(0.4f) + .build(); TROPICAL_FISH = EntityDefinition.inherited(TropicalFishEntity::new, abstractFishEntityBase) .type(EntityType.TROPICAL_FISH) .heightAndWidth(0.6f) @@ -726,7 +745,7 @@ public final class EntityDefinitions { .type(EntityType.CHICKEN) .height(0.7f).width(0.4f) .build(); - COW = EntityDefinition.inherited(AnimalEntity::new, ageableEntityBase) + COW = EntityDefinition.inherited(CowEntity::new, ageableEntityBase) .type(EntityType.COW) .height(1.4f).width(0.9f) .build(); @@ -738,6 +757,12 @@ public final class EntityDefinitions { .addTranslator(null) // Trusted player 1 .addTranslator(null) // Trusted player 2 .build(); + FROG = EntityDefinition.inherited(FrogEntity::new, ageableEntityBase) + .type(EntityType.FROG) + .heightAndWidth(0.5f) + .addTranslator(MetadataType.FROG_VARIANT, FrogEntity::setFrogVariant) + .addTranslator(MetadataType.OPTIONAL_VARINT, FrogEntity::setTongueTarget) + .build(); HOGLIN = EntityDefinition.inherited(HoglinEntity::new, ageableEntityBase) .type(EntityType.HOGLIN) .height(1.4f).width(1.3965f) @@ -748,14 +773,14 @@ public final class EntityDefinitions { .height(1.3f).width(0.9f) .addTranslator(MetadataType.BOOLEAN, GoatEntity::setScreamer) .build(); - MOOSHROOM = EntityDefinition.inherited(MooshroomEntity::new, ageableEntityBase) // TODO remove class + MOOSHROOM = EntityDefinition.inherited(MooshroomEntity::new, ageableEntityBase) .type(EntityType.MOOSHROOM) .height(1.4f).width(0.9f) - .addTranslator(MetadataType.STRING, (entity, entityMetadata) -> entity.getDirtyMetadata().put(EntityData.VARIANT, entityMetadata.getValue().equals("brown") ? 1 : 0)) + .addTranslator(MetadataType.STRING, MooshroomEntity::setVariant) .build(); OCELOT = EntityDefinition.inherited(OcelotEntity::new, ageableEntityBase) .type(EntityType.OCELOT) - .height(0.35f).width(0.3f) + .height(0.7f).width(0.6f) .addTranslator(MetadataType.BOOLEAN, (ocelotEntity, entityMetadata) -> ocelotEntity.setFlag(EntityFlag.TRUSTING, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .build(); PANDA = EntityDefinition.inherited(PandaEntity::new, ageableEntityBase) @@ -786,7 +811,7 @@ public final class EntityDefinitions { .build(); SHEEP = EntityDefinition.inherited(SheepEntity::new, ageableEntityBase) .type(EntityType.SHEEP) - .heightAndWidth(0.9f) + .height(1.3f).width(0.9f) .addTranslator(MetadataType.BYTE, SheepEntity::setSheepFlags) .build(); STRIDER = EntityDefinition.inherited(StriderEntity::new, ageableEntityBase) @@ -835,11 +860,11 @@ public final class EntityDefinitions { .height(1.6f).width(1.3965f) .addTranslator(MetadataType.INT, HorseEntity::setHorseVariant) .build(); - SKELETON_HORSE = EntityDefinition.inherited(abstractHorseEntityBase.factory(), abstractHorseEntityBase) + SKELETON_HORSE = EntityDefinition.inherited(SkeletonHorseEntity::new, abstractHorseEntityBase) .type(EntityType.SKELETON_HORSE) .height(1.6f).width(1.3965f) .build(); - ZOMBIE_HORSE = EntityDefinition.inherited(abstractHorseEntityBase.factory(), abstractHorseEntityBase) + ZOMBIE_HORSE = EntityDefinition.inherited(ZombieHorseEntity::new, abstractHorseEntityBase) .type(EntityType.ZOMBIE_HORSE) .height(1.6f).width(1.3965f) .build(); @@ -874,7 +899,7 @@ public final class EntityDefinitions { CAT = EntityDefinition.inherited(CatEntity::new, tameableEntityBase) .type(EntityType.CAT) .height(0.35f).width(0.3f) - .addTranslator(MetadataType.INT, CatEntity::setCatVariant) + .addTranslator(MetadataType.CAT_VARIANT, CatEntity::setCatVariant) .addTranslator(MetadataType.BOOLEAN, CatEntity::setResting) .addTranslator(null) // "resting state one" //TODO .addTranslator(MetadataType.INT, CatEntity::setCollarColor) diff --git a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java index f50548f15..c896c239e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java +++ b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.Map; /** * A write-only wrapper for temporarily storing entity metadata that will be sent to Bedrock. */ -public class GeyserDirtyMetadata { +public final class GeyserDirtyMetadata { private final Map metadata = new Object2ObjectLinkedOpenHashMap<>(); public void put(EntityData entityData, Object value) { @@ -52,4 +52,9 @@ public class GeyserDirtyMetadata { public boolean hasEntries() { return !metadata.isEmpty(); } + + @Override + public String toString() { + return metadata.toString(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/InteractiveTagManager.java b/core/src/main/java/org/geysermc/geyser/entity/InteractiveTagManager.java deleted file mode 100644 index f8e1f43aa..000000000 --- a/core/src/main/java/org/geysermc/geyser/entity/InteractiveTagManager.java +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2019-2021 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; - -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import lombok.Getter; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.living.MobEntity; -import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; -import org.geysermc.geyser.entity.type.living.animal.horse.HorseEntity; -import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; -import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity; -import org.geysermc.geyser.entity.type.living.merchant.VillagerEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.registry.type.ItemMapping; - -import java.util.EnumSet; -import java.util.Set; - -public class InteractiveTagManager { - /** - * All entity types that can be leashed on Java Edition - */ - private static final Set LEASHABLE_MOB_TYPES = EnumSet.of(EntityType.AXOLOTL, EntityType.BEE, EntityType.CAT, EntityType.CHICKEN, - EntityType.COW, EntityType.DOLPHIN, EntityType.DONKEY, EntityType.FOX, EntityType.GOAT, EntityType.GLOW_SQUID, EntityType.HOGLIN, - EntityType.HORSE, EntityType.SKELETON_HORSE, EntityType.ZOMBIE_HORSE, EntityType.IRON_GOLEM, EntityType.LLAMA, - EntityType.TRADER_LLAMA, EntityType.MOOSHROOM, EntityType.MULE, EntityType.OCELOT, EntityType.PARROT, EntityType.PIG, - EntityType.POLAR_BEAR, EntityType.RABBIT, EntityType.SHEEP, EntityType.SNOW_GOLEM, EntityType.SQUID, EntityType.STRIDER, - EntityType.WOLF, EntityType.ZOGLIN); - - private static final Set SADDLEABLE_WHEN_TAMED_MOB_TYPES = EnumSet.of(EntityType.DONKEY, EntityType.HORSE, - EntityType.ZOMBIE_HORSE, EntityType.MULE); - - /** - * Update the suggestion that the client currently has on their screen for this entity (for example, "Feed" or "Ride") - * - * @param session the Bedrock client session - * @param interactEntity the entity that the client is currently facing. - */ - public static void updateTag(GeyserSession session, Entity interactEntity) { - ItemMapping mapping = session.getPlayerInventory().getItemInHand().getMapping(session); - String javaIdentifierStripped = mapping.getJavaIdentifier().replace("minecraft:", ""); - EntityType entityType = interactEntity.getDefinition().entityType(); - if (entityType == null) { - // Likely a technical entity; we don't need to worry about this - return; - } - - InteractiveTag interactiveTag = InteractiveTag.NONE; - - if (interactEntity instanceof MobEntity mobEntity && mobEntity.getLeashHolderBedrockId() == session.getPlayerEntity().getGeyserId()) { - // Unleash the entity - interactiveTag = InteractiveTag.REMOVE_LEASH; - } else if (javaIdentifierStripped.equals("saddle") && !interactEntity.getFlag(EntityFlag.SADDLED) && - ((SADDLEABLE_WHEN_TAMED_MOB_TYPES.contains(entityType) && interactEntity.getFlag(EntityFlag.TAMED) && !session.isSneaking()) || - entityType == EntityType.PIG || entityType == EntityType.STRIDER)) { - // Entity can be saddled and the conditions meet (entity can be saddled and, if needed, is tamed) - interactiveTag = InteractiveTag.SADDLE; - } else if (javaIdentifierStripped.equals("name_tag") && session.getPlayerInventory().getItemInHand().getNbt() != null && - session.getPlayerInventory().getItemInHand().getNbt().contains("display")) { - // Holding a named name tag - interactiveTag = InteractiveTag.NAME; - } else if (interactEntity instanceof MobEntity mobEntity &&javaIdentifierStripped.equals("lead") - && LEASHABLE_MOB_TYPES.contains(entityType) && mobEntity.getLeashHolderBedrockId() == -1L) { - // Holding a leash and the mob is leashable for sure - // (Plugins can change this behavior so that's something to look into in the far far future) - interactiveTag = InteractiveTag.LEASH; - } else if (interactEntity instanceof AnimalEntity && ((AnimalEntity) interactEntity).canEat(javaIdentifierStripped, mapping)) { - // This animal can be fed - interactiveTag = InteractiveTag.FEED; - } else { - switch (entityType) { - case BOAT: - if (interactEntity.getPassengers().size() < 2) { - interactiveTag = InteractiveTag.BOARD_BOAT; - } - break; - case CAT: - if (interactEntity.getFlag(EntityFlag.TAMED) && - ((CatEntity) interactEntity).getOwnerBedrockId() == session.getPlayerEntity().getGeyserId()) { - // Tamed and owned by player - can sit/stand - interactiveTag = interactEntity.getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; - break; - } - break; - case MOOSHROOM: - // Shear the mooshroom - if (javaIdentifierStripped.equals("shears")) { - interactiveTag = InteractiveTag.MOOSHROOM_SHEAR; - break; - } - // Bowls are acceptable here - else if (javaIdentifierStripped.equals("bowl")) { - interactiveTag = InteractiveTag.MOOSHROOM_MILK_STEW; - break; - } - // Fall down to COW as this works on mooshrooms - case COW: - if (javaIdentifierStripped.equals("bucket")) { - // Milk the cow - interactiveTag = InteractiveTag.MILK; - } - break; - case CREEPER: - if (javaIdentifierStripped.equals("flint_and_steel")) { - // Today I learned that you can ignite a creeper with flint and steel! Huh. - interactiveTag = InteractiveTag.IGNITE_CREEPER; - } - break; - case DONKEY: - case LLAMA: - case MULE: - if (interactEntity.getFlag(EntityFlag.TAMED) && !interactEntity.getFlag(EntityFlag.CHESTED) - && javaIdentifierStripped.equals("chest")) { - // Can attach a chest - interactiveTag = InteractiveTag.ATTACH_CHEST; - break; - } - // Intentional fall-through - case HORSE: - case SKELETON_HORSE: - case TRADER_LLAMA: - case ZOMBIE_HORSE: - boolean tamed = interactEntity.getFlag(EntityFlag.TAMED); - if (session.isSneaking() && tamed && (interactEntity instanceof HorseEntity || interactEntity.getFlag(EntityFlag.CHESTED))) { - interactiveTag = InteractiveTag.OPEN_CONTAINER; - break; - } - if (!interactEntity.getFlag(EntityFlag.BABY)) { - // Can't ride a baby - if (tamed) { - interactiveTag = InteractiveTag.RIDE_HORSE; - } else if (mapping.getJavaId() == 0) { - // Can't hide an untamed entity without having your hand empty - interactiveTag = InteractiveTag.MOUNT; - } - } - break; - case MINECART: - if (interactEntity.getPassengers().isEmpty()) { - interactiveTag = InteractiveTag.RIDE_MINECART; - } - break; - case CHEST_MINECART: - case COMMAND_BLOCK_MINECART: - case HOPPER_MINECART: - interactiveTag = InteractiveTag.OPEN_CONTAINER; - break; - case PIG: - if (interactEntity.getFlag(EntityFlag.SADDLED)) { - interactiveTag = InteractiveTag.MOUNT; - } - break; - case PIGLIN: - if (!interactEntity.getFlag(EntityFlag.BABY) && javaIdentifierStripped.equals("gold_ingot")) { - interactiveTag = InteractiveTag.BARTER; - } - break; - case SHEEP: - if (!interactEntity.getFlag(EntityFlag.SHEARED)) { - if (javaIdentifierStripped.equals("shears")) { - // Shear the sheep - interactiveTag = InteractiveTag.SHEAR; - } else if (javaIdentifierStripped.contains("_dye")) { - // Dye the sheep - interactiveTag = InteractiveTag.DYE; - } - } - break; - case STRIDER: - if (interactEntity.getFlag(EntityFlag.SADDLED)) { - interactiveTag = InteractiveTag.RIDE_STRIDER; - } - break; - case VILLAGER: - VillagerEntity villager = (VillagerEntity) interactEntity; - if (villager.isCanTradeWith() && !villager.isBaby()) { // Not a nitwit, has a profession and is not a baby - interactiveTag = InteractiveTag.TRADE; - } - break; - case WANDERING_TRADER: - interactiveTag = InteractiveTag.TRADE; // Since you can always trade with a wandering villager, presumably. - break; - case WOLF: - if (javaIdentifierStripped.equals("bone") && !interactEntity.getFlag(EntityFlag.TAMED)) { - // Bone and untamed - can tame - interactiveTag = InteractiveTag.TAME; - } else if (interactEntity.getFlag(EntityFlag.TAMED) && - ((WolfEntity) interactEntity).getOwnerBedrockId() == session.getPlayerEntity().getGeyserId()) { - // Tamed and owned by player - can sit/stand - interactiveTag = interactEntity.getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; - } - break; - case ZOMBIE_VILLAGER: - // We can't guarantee the existence of the weakness effect so we just always show it. - if (javaIdentifierStripped.equals("golden_apple")) { - interactiveTag = InteractiveTag.CURE; - } - break; - default: - break; - } - } - session.getPlayerEntity().getDirtyMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue()); - session.getPlayerEntity().updateBedrockMetadata(); - } - - /** - * All interactive tags in enum form. For potential API usage. - */ - public enum InteractiveTag { - NONE((Void) null), - IGNITE_CREEPER("creeper"), - EDIT, - LEAVE_BOAT("exit.boat"), - FEED, - FISH("fishing"), - MILK, - MOOSHROOM_SHEAR("mooshear"), - MOOSHROOM_MILK_STEW("moostew"), - BOARD_BOAT("ride.boat"), - RIDE_MINECART("ride.minecart"), - RIDE_HORSE("ride.horse"), - RIDE_STRIDER("ride.strider"), - SHEAR, - SIT, - STAND, - TALK, - TAME, - DYE, - CURE, - OPEN_CONTAINER("opencontainer"), - CREATE_MAP("createMap"), - TAKE_PICTURE("takepicture"), - SADDLE, - MOUNT, - BOOST, - WRITE, - LEASH, - REMOVE_LEASH("unleash"), - NAME, - ATTACH_CHEST("attachchest"), - TRADE, - POSE_ARMOR_STAND("armorstand.pose"), - EQUIP_ARMOR_STAND("armorstand.equip"), - READ, - WAKE_VILLAGER("wakevillager"), - BARTER; - - /** - * The full string that should be passed on to the client. - */ - @Getter - private final String value; - - InteractiveTag(Void isNone) { - this.value = ""; - } - - InteractiveTag(String value) { - this.value = "action.interact." + value; - } - - InteractiveTag() { - this.value = "action.interact." + name().toLowerCase(); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java index 86f2a1923..ba3117518 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java +++ b/core/src/main/java/org/geysermc/geyser/entity/attribute/GeyserAttributeType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/entity/factory/EntityFactory.java b/core/src/main/java/org/geysermc/geyser/entity/factory/EntityFactory.java index 774166d44..9f23cdc78 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/factory/EntityFactory.java +++ b/core/src/main/java/org/geysermc/geyser/entity/factory/EntityFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,7 +25,17 @@ package org.geysermc.geyser.entity.factory; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.session.GeyserSession; +import java.util.UUID; + +/** + * Represents a constructor to create an entity. + */ public interface EntityFactory { + + T create(GeyserSession session, int javaId, long bedrockId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java index b80db2570..963e0b70a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AbstractArrowEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class AbstractArrowEntity extends Entity { - public AbstractArrowEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AbstractArrowEntity(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); // Set the correct texture if using the resource pack @@ -70,8 +70,8 @@ public class AbstractArrowEntity extends Entity { super.setMotion(motion); double horizontalSpeed = Math.sqrt(motion.getX() * motion.getX() + motion.getZ() * motion.getZ()); - this.yaw = (float) Math.toDegrees(Math.atan2(motion.getX(), motion.getZ())); - this.pitch = (float) Math.toDegrees(Math.atan2(motion.getY(), horizontalSpeed)); - this.headYaw = yaw; + setYaw((float) Math.toDegrees(Math.atan2(motion.getX(), motion.getZ()))); + setPitch((float) Math.toDegrees(Math.atan2(motion.getY(), horizontalSpeed))); + setHeadYaw(getYaw()); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java index 6063c81f9..164fbf705 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,7 +39,7 @@ import java.util.UUID; public class AreaEffectCloudEntity extends Entity { - public AreaEffectCloudEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AreaEffectCloudEntity(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); } @@ -47,18 +47,19 @@ public class AreaEffectCloudEntity extends Entity { protected void initializeMetadata() { super.initializeMetadata(); // Without this the cloud doesn't appear, - dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, 600); + dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, Integer.MAX_VALUE); // This disabled client side shrink of the cloud dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 0.0f); - dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, -0.005f); - dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f); + dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, Float.MIN_VALUE); + dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, Float.MIN_VALUE); setFlag(EntityFlag.FIRE_IMMUNE, true); } public void setRadius(FloatEntityMetadata entityMetadata) { - float value = entityMetadata.getPrimitiveValue(); + // Anything less than 0.5 will cause the cloud to despawn + float value = Math.max(entityMetadata.getPrimitiveValue(), 0.5f); dirtyMetadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, value); dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * value); } 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 ac1b3fcbd..9fd96f46b 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type; 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 com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.packet.AnimatePacket; @@ -35,6 +36,8 @@ import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -65,7 +68,7 @@ public class BoatEntity extends Entity { // Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it private final float ROWING_SPEED = 0.05f; - public BoatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { // Initial rotation is incorrect super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90); @@ -78,14 +81,18 @@ public class BoatEntity extends Entity { public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { // We don't include the rotation (y) as it causes the boat to appear sideways setPosition(position.add(0d, this.definition.offset(), 0d)); - this.yaw = yaw + 90; - this.headYaw = yaw + 90; + setYaw(yaw + 90); + setHeadYaw(yaw + 90); setOnGround(isOnGround); MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); moveEntityPacket.setRuntimeEntityId(geyserId); - // Minimal glitching when ClientboundMoveVehiclePacket is sent - moveEntityPacket.setPosition(session.getRidingVehicleEntity() == this ? position.up(EntityDefinitions.PLAYER.offset() - this.definition.offset()) : this.position); + if (session.getPlayerEntity().getVehicle() == this && session.getPlayerEntity().isRidingInFront()) { + // Minimal glitching when ClientboundMoveVehiclePacket is sent + moveEntityPacket.setPosition(position.up(EntityDefinitions.PLAYER.offset() - this.definition.offset())); + } else { + moveEntityPacket.setPosition(this.position); + } moveEntityPacket.setRotation(getBedrockRotation()); moveEntityPacket.setOnGround(isOnGround); moveEntityPacket.setTeleported(teleported); @@ -128,7 +135,7 @@ public class BoatEntity extends Entity { paddleTimeLeft = 0f; if (!this.passengers.isEmpty()) { // Get the entity by the first stored passenger and convey motion in this manner - Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong()); + Entity entity = this.passengers.get(0); if (entity != null) { updateLeftPaddle(session, entity); } @@ -144,7 +151,7 @@ public class BoatEntity extends Entity { if (isPaddlingRight) { paddleTimeRight = 0f; if (!this.passengers.isEmpty()) { - Entity entity = session.getEntityCache().getEntityByJavaId(this.passengers.iterator().nextLong()); + Entity entity = this.passengers.get(0); if (entity != null) { updateRightPaddle(session, entity); } @@ -154,6 +161,27 @@ public class BoatEntity extends Entity { } } + @Override + protected InteractiveTag testInteraction(Hand hand) { + if (session.isSneaking()) { + return InteractiveTag.NONE; + } else if (passengers.size() < 2) { + return InteractiveTag.BOARD_BOAT; + } else { + return InteractiveTag.NONE; + } + } + + @Override + public InteractionResult interact(Hand hand) { + if (session.isSneaking()) { + return InteractionResult.PASS; + } else { + // TODO: the client also checks for "out of control" ticks + return InteractionResult.SUCCESS; + } + } + private void updateLeftPaddle(GeyserSession session, Entity rower) { if (isPaddlingLeft) { paddleTimeLeft += ROWING_SPEED; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java new file mode 100644 index 000000000..724bf921e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ChestBoatEntity.java @@ -0,0 +1,51 @@ +/* + * 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.entity.type; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import java.util.UUID; + +public class ChestBoatEntity extends BoatEntity { + public ChestBoatEntity(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 InteractiveTag testInteraction(Hand hand) { + return passengers.isEmpty() && !session.isSneaking() ? super.testInteraction(hand) : InteractiveTag.OPEN_CONTAINER; + } + + @Override + public InteractionResult interact(Hand hand) { + return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java index 1764c721e..251eb98a0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/CommandBlockMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,16 +25,22 @@ package org.geysermc.geyser.entity.type; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; import java.util.UUID; public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity { - public CommandBlockMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public CommandBlockMinecartEntity(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); } @@ -55,4 +61,30 @@ public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity { dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getCommandBlockRuntimeId()); dirtyMetadata.put(EntityData.DISPLAY_OFFSET, 6); } + + @Override + protected InteractiveTag testInteraction(Hand hand) { + if (session.canUseCommandBlocks()) { + return InteractiveTag.OPEN_CONTAINER; + } else { + return InteractiveTag.NONE; + } + } + + @Override + public InteractionResult interact(Hand hand) { + if (session.canUseCommandBlocks()) { + // Client-side GUI required + ContainerOpenPacket openPacket = new ContainerOpenPacket(); + openPacket.setBlockPosition(Vector3i.ZERO); + openPacket.setId((byte) 1); + openPacket.setType(ContainerType.COMMAND_BLOCK); + openPacket.setUniqueEntityId(geyserId); + session.sendUpstreamPacket(openPacket); + + return InteractionResult.SUCCESS; + } else { + return InteractionResult.PASS; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java index ec00c30be..ab43bf7b3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/DefaultBlockMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -43,7 +43,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity { public int customBlockOffset = 0; public boolean showCustomBlock = false; - public DefaultBlockMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public DefaultBlockMinecartEntity(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); dirtyMetadata.put(EntityData.CUSTOM_DISPLAY, (byte) 1); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java index aa907b7c6..f9e4af7c1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/EnderCrystalEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,7 +26,6 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -39,7 +38,7 @@ import java.util.UUID; public class EnderCrystalEntity extends Entity { - public EnderCrystalEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public EnderCrystalEntity(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,13 +49,12 @@ public class EnderCrystalEntity extends Entity { setFlag(EntityFlag.FIRE_IMMUNE, true); } - public void setBlockTarget(EntityMetadata, ?> entityMetadata) { + public void setBlockTarget(EntityMetadata, ?> entityMetadata) { // Show beam // Usually performed client-side on Bedrock except for Ender Dragon respawn event - Optional optionalPos = entityMetadata.getValue(); + Optional optionalPos = entityMetadata.getValue(); if (optionalPos.isPresent()) { - Position pos = optionalPos.get(); - dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.from(pos.getX(), pos.getY(), pos.getZ())); + dirtyMetadata.put(EntityData.BLOCK_TARGET, optionalPos.get()); } else { dirtyMetadata.put(EntityData.BLOCK_TARGET, Vector3i.ZERO); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index 479ec2e8c..144d1cbf9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -30,16 +30,14 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; -import com.nukkitx.protocol.bedrock.packet.AddEntityPacket; -import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket; -import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; -import it.unimi.dsi.fastutil.longs.LongOpenHashSet; +import com.nukkitx.protocol.bedrock.packet.*; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -48,8 +46,13 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.GeyserDirtyMetadata; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.MathUtils; +import java.util.Collections; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -58,7 +61,7 @@ import java.util.UUID; public class Entity { protected final GeyserSession session; - protected long entityId; + protected int entityId; protected final long geyserId; protected UUID uuid; @@ -79,6 +82,9 @@ public class Entity { protected EntityDefinition definition; + /** + * Indicates if the entity has been initialized and spawned + */ protected boolean valid; /* Metadata about this specific entity */ @@ -88,9 +94,12 @@ public class Entity { private float boundingBoxWidth; @Setter(AccessLevel.NONE) protected String nametag = ""; + @Setter(AccessLevel.NONE) + protected boolean silent = false; /* Metadata end */ - protected LongOpenHashSet passengers = new LongOpenHashSet(); + protected List passengers = Collections.emptyList(); + protected Entity vehicle; /** * A container to store temporary metadata before it's sent to Bedrock. */ @@ -109,7 +118,7 @@ public class Entity { @Setter(AccessLevel.PROTECTED) // For players private boolean flagsDirty = false; - public Entity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public Entity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { this.session = session; this.entityId = entityId; @@ -134,13 +143,19 @@ public class Entity { */ protected void initializeMetadata() { dirtyMetadata.put(EntityData.SCALE, 1f); - dirtyMetadata.put(EntityData.COLOR, 0); + dirtyMetadata.put(EntityData.COLOR, (byte) 0); dirtyMetadata.put(EntityData.MAX_AIR_SUPPLY, getMaxAir()); setDimensions(Pose.STANDING); setFlag(EntityFlag.HAS_GRAVITY, true); setFlag(EntityFlag.HAS_COLLISION, true); setFlag(EntityFlag.CAN_SHOW_NAME, true); setFlag(EntityFlag.CAN_CLIMB, true); + // Let the Java server (or us) supply all sounds for an entity + setClientSideSilent(); + } + + protected void setClientSideSilent() { + setFlag(EntityFlag.SILENT, true); } public void spawnEntity() { @@ -181,11 +196,11 @@ public class Entity { public boolean despawnEntity() { if (!valid) return true; - for (long passenger : passengers) { // Make sure all passengers on the despawned entity are updated - Entity entity = session.getEntityCache().getEntityByJavaId(passenger); - if (entity == null) continue; - entity.setFlag(EntityFlag.RIDING, false); - entity.updateBedrockMetadata(); + for (Entity passenger : passengers) { // Make sure all passengers on the despawned entity are updated + if (passenger == null) continue; + passenger.setVehicle(null); + passenger.setFlag(EntityFlag.RIDING, false); + passenger.updateBedrockMetadata(); } RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket(); @@ -197,7 +212,7 @@ public class Entity { } public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(relX, relY, relZ, yaw, pitch, this.headYaw, isOnGround); + moveRelative(relX, relY, relZ, yaw, pitch, getHeadYaw(), isOnGround); } public void moveRelative(double relX, double relY, double relZ, float yaw, float pitch, float headYaw, boolean isOnGround) { @@ -218,7 +233,7 @@ public class Entity { } public void moveAbsolute(Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) { - moveAbsolute(position, yaw, pitch, this.headYaw, isOnGround, teleported); + moveAbsolute(position, yaw, pitch, getHeadYaw(), isOnGround, teleported); } public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYaw, boolean isOnGround, boolean teleported) { @@ -247,7 +262,8 @@ public class Entity { * @param isOnGround Whether the entity is currently on the ground. */ public void teleport(Vector3f position, float yaw, float pitch, boolean isOnGround) { - moveAbsolute(position, yaw, pitch, isOnGround, false); + // teleport will always set the headYaw to yaw + moveAbsolute(position, yaw, pitch, yaw, isOnGround, false); } /** @@ -255,7 +271,7 @@ public class Entity { * @param headYaw The new head rotation of the entity. */ public void updateHeadLookRotation(float headYaw) { - moveRelative(0, 0, 0, headYaw, pitch, this.headYaw, onGround); + moveRelative(0, 0, 0, getYaw(), getPitch(), headYaw, isOnGround()); } /** @@ -268,7 +284,7 @@ public class Entity { * @param isOnGround Whether the entity is currently on the ground. */ public void updatePositionAndRotation(double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(moveX, moveY, moveZ, this.yaw, pitch, yaw, isOnGround); + moveRelative(moveX, moveY, moveZ, yaw, pitch, getHeadYaw(), isOnGround); } /** @@ -343,7 +359,7 @@ public class Entity { dirtyMetadata.put(EntityData.AIR_SUPPLY, (short) MathUtils.constrain(amount, 0, getMaxAir())); } - protected int getMaxAir() { + protected short getMaxAir() { return 300; } @@ -362,6 +378,10 @@ public class Entity { dirtyMetadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0)); } + public final void setSilent(BooleanEntityMetadata entityMetadata) { + silent = entityMetadata.getPrimitiveValue(); + } + public void setGravity(BooleanEntityMetadata entityMetadata) { setFlag(EntityFlag.HAS_GRAVITY, !entityMetadata.getPrimitiveValue()); } @@ -369,9 +389,7 @@ public class Entity { /** * Usually used for bounding box and not animation. */ - public void setPose(EntityMetadata entityMetadata) { - Pose pose = entityMetadata.getValue(); - + public void setPose(Pose pose) { setFlag(EntityFlag.SLEEPING, pose.equals(Pose.SLEEPING)); // Triggered when crawling setFlag(EntityFlag.SWIMMING, pose.equals(Pose.SWIMMING)); @@ -387,11 +405,15 @@ public class Entity { setBoundingBoxWidth(definition.width()); } - public void setBoundingBoxHeight(float height) { + public boolean setBoundingBoxHeight(float height) { if (height != boundingBoxHeight) { boundingBoxHeight = height; dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, boundingBoxHeight); + + updatePassengerOffsets(); + return true; } + return false; } public void setBoundingBoxWidth(float width) { @@ -427,20 +449,100 @@ public class Entity { } /** - * x = Pitch, y = HeadYaw, z = Yaw + * x = Pitch, y = Yaw, z = HeadYaw * * @return the bedrock rotation */ public Vector3f getBedrockRotation() { - return Vector3f.from(pitch, headYaw, yaw); + return Vector3f.from(getPitch(), getYaw(), getHeadYaw()); + } + + /** + * Update the mount offsets of each passenger on this vehicle + */ + protected void updatePassengerOffsets() { + for (Entity passenger : passengers) { + if (passenger != null) { + boolean rider = passengers.get(0) == this; + EntityUtils.updateMountOffset(passenger, this, rider, true, passengers.size() > 1); + passenger.updateBedrockMetadata(); + } + } + } + + /** + * Update this entity's mount offset + */ + protected void updateMountOffset() { + if (vehicle != null) { + boolean rider = vehicle.getPassengers().get(0) == this; + EntityUtils.updateMountOffset(this, vehicle, rider, true, vehicle.getPassengers().size() > 1); + updateBedrockMetadata(); + } + } + + public boolean isAlive() { + return this.valid; + } + + /** + * Update the suggestion that the client currently has on their screen for this entity (for example, "Feed" or "Ride") + */ + public final void updateInteractiveTag() { + InteractiveTag tag = InteractiveTag.NONE; + for (Hand hand: EntityUtils.HANDS) { + tag = testInteraction(hand); + if (tag != InteractiveTag.NONE) { + break; + } + } + session.getPlayerEntity().getDirtyMetadata().put(EntityData.INTERACTIVE_TAG, tag.getValue()); + session.getPlayerEntity().updateBedrockMetadata(); + } + + /** + * Test interacting with the given hand to see if we should send a tag to the Bedrock client. + * Should usually mirror {@link #interact(Hand)} without any side effects. + */ + protected InteractiveTag testInteraction(Hand hand) { + return InteractiveTag.NONE; + } + + /** + * Simulates interacting with an entity. The code here should mirror Java Edition code to the best of its ability, + * to ensure packet parity as well as functionality parity (such as sound effect responses). + */ + public InteractionResult interact(Hand hand) { + return InteractionResult.PASS; + } + + /** + * Simulates interacting with this entity at a specific click point. As of Java Edition 1.18.1, this is only used for armor stands. + */ + public InteractionResult interactAt(Hand hand) { + return InteractionResult.PASS; + } + + /** + * Send an entity event of the specified type to the Bedrock player from this entity. + */ + public final void playEntityEvent(EntityEventType type) { + playEntityEvent(type, 0); + } + + /** + * Send an entity event of the specified type with the specified data to the Bedrock player from this entity. + */ + public final void playEntityEvent(EntityEventType type, int data) { + EntityEventPacket packet = new EntityEventPacket(); + packet.setRuntimeEntityId(geyserId); + packet.setType(type); + packet.setData(data); + session.sendUpstreamPacket(packet); } @SuppressWarnings("unchecked") public I as(Class entityClass) { return entityClass.isInstance(this) ? (I) this : null; } - - public boolean is(Class entityClass) { - return entityClass.isInstance(this); - } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java new file mode 100644 index 000000000..af7dca68c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/EvokerFangsEntity.java @@ -0,0 +1,70 @@ +/* + * 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.entity.type; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public class EvokerFangsEntity extends Entity implements Tickable { + private int limitedLife = 22; + private boolean attackStarted = false; + + public EvokerFangsEntity(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); + // As of 1.18.2 Bedrock, this line is required for the entity to be visible + // 22 is the starting number on Java Edition + dirtyMetadata.put(EntityData.LIMITED_LIFE, this.limitedLife); + } + + @Override + public void tick() { + if (attackStarted) { + if (--this.limitedLife > 0 && this.limitedLife % 2 == 0) { // Matches Bedrock behavior + dirtyMetadata.put(EntityData.LIMITED_LIFE, this.limitedLife); + updateBedrockMetadata(); + } + } + } + + public void setAttackStarted() { + this.attackStarted = true; + if (!silent) { + // Play the chomp sound + PlaySoundPacket packet = new PlaySoundPacket(); + packet.setPosition(this.position); + packet.setSound("mob.evocation_fangs.attack"); + packet.setVolume(1.0f); + packet.setPitch(ThreadLocalRandom.current().nextFloat() * 0.2f + 0.85f); + session.sendUpstreamPacket(packet); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java index 8196d03ff..6000b361e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ExpOrbEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -32,7 +32,7 @@ import org.geysermc.geyser.session.GeyserSession; public class ExpOrbEntity extends Entity { - public ExpOrbEntity(GeyserSession session, int amount, long entityId, long geyserId, Vector3f position) { + public ExpOrbEntity(GeyserSession session, int amount, int entityId, long geyserId, Vector3f position) { super(session, entityId, geyserId, null, EntityDefinitions.EXPERIENCE_ORB, position, Vector3f.ZERO, 0, 0, 0); this.dirtyMetadata.put(EntityData.EXPERIENCE_VALUE, amount); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java index 1f690036f..3e64cfcea 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FallingBlockEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,8 +36,8 @@ import java.util.UUID; public class FallingBlockEntity extends Entity { - public FallingBlockEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, int javaId) { - super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, 0f); + public FallingBlockEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, int javaId) { + super(session, entityId, geyserId, uuid, EntityDefinitions.FALLING_BLOCK, position, motion, yaw, pitch, headYaw); this.dirtyMetadata.put(EntityData.VARIANT, session.getBlockMappings().getBedrockBlockId(javaId)); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java index 52796d67b..135f58906 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireballEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,7 +39,7 @@ public class FireballEntity extends ThrowableEntity { */ protected int futureTicks = 3; - public FireballEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public FireballEntity(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, Vector3f.ZERO, yaw, pitch, headYaw); float magnitude = motion.length(); @@ -72,6 +72,6 @@ public class FireballEntity extends ThrowableEntity { @Override public void tick() { - moveAbsoluteImmediate(tickMovement(position), yaw, pitch, headYaw, false, false); + moveAbsoluteImmediate(tickMovement(position), getYaw(), getPitch(), getHeadYaw(), false, false); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java index 075178b55..fa22422ba 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FireworkEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -50,7 +50,7 @@ import java.util.UUID; public class FireworkEntity extends Entity { - public FireworkEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public FireworkEntity(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); } 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 b5774bd78..75bdd9021 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,17 +28,16 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.PlayerEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.level.physics.BoundingBox; -import org.geysermc.geyser.translator.collision.BlockCollision; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.registry.BlockRegistries; 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; import java.util.UUID; @@ -50,13 +49,13 @@ public class FishingHookEntity extends ThrowableEntity { private boolean inWater = false; @Getter - private final boolean isOwnerSessionPlayer; + private final long bedrockOwnerId; @Getter private long bedrockTargetId; private final BoundingBox boundingBox; - public FishingHookEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, PlayerEntity owner) { + public FishingHookEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, PlayerEntity owner) { super(session, entityId, geyserId, uuid, EntityDefinitions.FISHING_BOBBER, position, motion, yaw, pitch, 0f); this.boundingBox = new BoundingBox(0.125, 0.125, 0.125, 0.25, 0.25, 0.25); @@ -66,25 +65,13 @@ public class FishingHookEntity extends ThrowableEntity { // so that it can be handled by moveAbsoluteImmediate. setBoundingBoxHeight(128); - isOwnerSessionPlayer = owner.getGeyserId() == session.getPlayerEntity().getGeyserId(); - this.dirtyMetadata.put(EntityData.OWNER_EID, owner.getGeyserId()); - } - - @Override - public void spawnEntity() { - - super.spawnEntity(); + this.bedrockOwnerId = owner.getGeyserId(); + this.dirtyMetadata.put(EntityData.OWNER_EID, this.bedrockOwnerId); } public void setHookedEntity(IntEntityMetadata entityMetadata) { int hookedEntityId = entityMetadata.getPrimitiveValue() - 1; - Entity entity; - if (session.getPlayerEntity().getEntityId() == hookedEntityId) { - entity = session.getPlayerEntity(); - } else { - entity = session.getEntityCache().getEntityByJavaId(hookedEntityId); - } - + Entity entity = session.getEntityCache().getEntityByJavaId(hookedEntityId); if (entity != null) { bedrockTargetId = entity.getGeyserId(); dirtyMetadata.put(EntityData.TARGET_EID, bedrockTargetId); @@ -141,7 +128,7 @@ public class FishingHookEntity extends ThrowableEntity { } private void sendSplashSound(GeyserSession session) { - if (!getFlag(EntityFlag.SILENT)) { + if (!silent) { float volume = (float) (0.2f * Math.sqrt(0.2 * (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) + motion.getY() * motion.getY())); if (volume > 1) { volume = 1; @@ -164,7 +151,7 @@ public class FishingHookEntity extends ThrowableEntity { float gravity = getGravity(); motion = motion.down(gravity); - moveAbsoluteImmediate(position.add(motion), yaw, pitch, headYaw, onGround, false); + moveAbsoluteImmediate(position.add(motion), getYaw(), getPitch(), getHeadYaw(), isOnGround(), false); float drag = getDrag(); motion = motion.mul(drag); @@ -172,7 +159,7 @@ public class FishingHookEntity extends ThrowableEntity { @Override protected float getGravity() { - if (!isInWater() && !onGround) { + if (!isInWater() && !isOnGround()) { return 0.03f; } return 0; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java index ab34cb751..dbd9bf91f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/FurnaceMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,22 +26,25 @@ package org.geysermc.geyser.entity.type; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.util.InteractionResult; import java.util.UUID; public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { private boolean hasFuel = false; - public FurnaceMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public FurnaceMinecartEntity(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); } public void setHasFuel(BooleanEntityMetadata entityMetadata) { + // Note: Java ticks this entity and gives it particles if it has fuel hasFuel = entityMetadata.getPrimitiveValue(); updateDefaultBlockMetadata(); } @@ -51,4 +54,10 @@ public class FurnaceMinecartEntity extends DefaultBlockMinecartEntity { dirtyMetadata.put(EntityData.DISPLAY_ITEM, session.getBlockMappings().getBedrockBlockId(hasFuel ? BlockStateValues.JAVA_FURNACE_LIT_ID : BlockStateValues.JAVA_FURNACE_ID)); dirtyMetadata.put(EntityData.DISPLAY_OFFSET, 6); } + + @Override + public InteractionResult interact(Hand hand) { + // Always works since you can "push" it this way + return InteractionResult.SUCCESS; + } } 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 dd98f9aba..f36a7c732 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -46,7 +46,7 @@ public class ItemEntity extends ThrowableEntity { private int waterLevel = -1; - public ItemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + 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); } @@ -76,10 +76,10 @@ public class ItemEntity extends ThrowableEntity { if (isInWater()) { return; } - if (!onGround || (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) > 0.00001) { + if (!isOnGround() || (motion.getX() * motion.getX() + motion.getZ() * motion.getZ()) > 0.00001) { float gravity = getGravity(); motion = motion.down(gravity); - moveAbsoluteImmediate(position.add(motion), yaw, pitch, headYaw, onGround, false); + moveAbsoluteImmediate(position.add(motion), getYaw(), getPitch(), getHeadYaw(), isOnGround(), false); float drag = getDrag(); motion = motion.mul(drag, 0.98f, drag); } @@ -124,7 +124,7 @@ public class ItemEntity extends ThrowableEntity { @Override protected float getGravity() { - if (getFlag(EntityFlag.HAS_GRAVITY) && !onGround && !isInWater()) { + if (getFlag(EntityFlag.HAS_GRAVITY) && !isOnGround() && !isInWater()) { // Gravity can change if the item is in water/lava, but // the server calculates the motion & position for us return 0.04f; @@ -134,7 +134,7 @@ public class ItemEntity extends ThrowableEntity { @Override protected float getDrag() { - if (onGround) { + if (isOnGround()) { Vector3i groundBlockPos = position.toInt().down(1); int blockState = session.getGeyser().getWorldManager().getBlockAt(session, groundBlockPos); return BlockStateValues.getSlipperiness(blockState) * 0.98f; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java index 0f73de739..bc7736e9b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ItemFrameEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,6 +29,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; @@ -37,12 +38,13 @@ import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import com.nukkitx.protocol.bedrock.v465.Bedrock_v465; import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.item.ItemTranslator; -import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InventoryUtils; import java.util.UUID; @@ -77,18 +79,16 @@ public class ItemFrameEntity extends Entity { */ private boolean changed = true; - public ItemFrameEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, Direction direction) { - super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, 0f); + public ItemFrameEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, Direction direction) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); NbtMapBuilder blockBuilder = NbtMap.builder() .putString("name", this.definition.entityType() == EntityType.GLOW_ITEM_FRAME ? "minecraft:glow_frame" : "minecraft:frame") .putInt("version", session.getBlockMappings().getBlockStateVersion()); NbtMapBuilder statesBuilder = NbtMap.builder() .putInt("facing_direction", direction.ordinal()) - .putByte("item_frame_map_bit", (byte) 0); - if (session.getUpstream().getProtocolVersion() >= Bedrock_v465.V465_CODEC.getProtocolVersion()) { - statesBuilder.putByte("item_frame_photo_bit", (byte) 0); - } + .putByte("item_frame_map_bit", (byte) 0) + .putByte("item_frame_photo_bit", (byte) 0); blockBuilder.put("states", statesBuilder.build()); bedrockRuntimeId = session.getBlockMappings().getItemFrame(blockBuilder.build()); @@ -208,6 +208,11 @@ public class ItemFrameEntity extends Entity { changed = false; } + @Override + public InteractionResult interact(Hand hand) { + return InventoryUtils.isEmpty(heldItem) && session.getPlayerInventory().getItemInHand(hand).isEmpty() ? InteractionResult.PASS : InteractionResult.SUCCESS; + } + /** * Finds the Java entity ID of an item frame from its Bedrock position. * @param position position of item frame in Bedrock. diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java index 63e964a55..4ff1dfe7c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LeashKnotEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,17 +25,24 @@ package org.geysermc.geyser.entity.type; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; import java.util.UUID; public class LeashKnotEntity extends Entity { - public LeashKnotEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public LeashKnotEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { // Position is incorrect by default super(session, entityId, geyserId, uuid, definition, position.add(0.5f, 0.25f, 0.5f), motion, yaw, pitch, headYaw); } + @Override + public InteractionResult interact(Hand hand) { + // Un-leashing the knot + return InteractionResult.SUCCESS; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LightningEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LightningEntity.java index 1f5af0492..3adb30e24 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LightningEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LightningEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.concurrent.ThreadLocalRandom; public class LightningEntity extends Entity { - public LightningEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public LightningEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java index 2aff7f9e1..2550643d3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/LivingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,10 +29,12 @@ import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute; import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.AttributeData; @@ -48,16 +50,14 @@ import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.ChunkUtils; +import org.geysermc.geyser.util.InteractionResult; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Optional; -import java.util.UUID; +import java.util.*; @Getter @Setter @@ -80,7 +80,7 @@ public class LivingEntity extends Entity { */ private boolean isMaxFrozenState = false; - public LivingEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public LivingEntity(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); } @@ -94,13 +94,15 @@ public class LivingEntity extends Entity { public void setLivingEntityFlags(ByteEntityMetadata entityMetadata) { byte xd = entityMetadata.getPrimitiveValue(); - // Blocking gets triggered when using a bow, but if we set USING_ITEM for all items, it may look like - // you're "mining" with ex. a shield. + boolean isUsingItem = (xd & 0x01) == 0x01; + boolean isUsingOffhand = (xd & 0x02) == 0x02; + ItemMapping shield = session.getItemMappings().getStoredItems().shield(); - boolean isUsingShield = (getHand().getId() == shield.getBedrockId() || - getHand().equals(ItemData.AIR) && getOffHand().getId() == shield.getBedrockId()); - setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield); - setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01); + boolean isUsingShield = hasShield(isUsingOffhand, shield); + + setFlag(EntityFlag.USING_ITEM, isUsingItem && !isUsingShield); + // Override the blocking + setFlag(EntityFlag.BLOCKING, isUsingItem && isUsingShield); // Riptide spin attack setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04); @@ -116,12 +118,11 @@ public class LivingEntity extends Entity { session.sendUpstreamPacket(attributesPacket); } - public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { - Optional optionalPos = entityMetadata.getValue(); + public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { + Optional optionalPos = entityMetadata.getValue(); if (optionalPos.isPresent()) { - Position bedPosition = optionalPos.get(); - Vector3i vector = Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ()); - dirtyMetadata.put(EntityData.BED_POSITION, vector); + Vector3i bedPosition = optionalPos.get(); + dirtyMetadata.put(EntityData.BED_POSITION, bedPosition); int bed = session.getGeyser().getWorldManager().getBlockAt(session, bedPosition); // Bed has to be updated, or else player is floating in the air ChunkUtils.updateBlock(session, bed, bedPosition); @@ -129,7 +130,7 @@ public class LivingEntity extends Entity { // Has to be a byte or it does not work // (Bed position is what actually triggers sleep - "pose" is only optional) dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 2); - return vector; + return bedPosition; } else { // Player is no longer sleeping dirtyMetadata.put(EntityData.PLAYER_FLAGS, (byte) 0); @@ -137,6 +138,14 @@ public class LivingEntity extends Entity { } } + protected boolean hasShield(boolean offhand, ItemMapping shieldMapping) { + if (offhand) { + return offHand.getId() == shieldMapping.getBedrockId(); + } else { + return hand.getId() == shieldMapping.getBedrockId(); + } + } + @Override protected boolean isShaking() { return isMaxFrozenState; @@ -169,6 +178,36 @@ public class LivingEntity extends Entity { return new AttributeData(GeyserAttributeType.HEALTH.getBedrockIdentifier(), 0f, this.maxHealth, (float) Math.ceil(this.health), this.maxHealth); } + @Override + public boolean isAlive() { + return this.valid && health > 0f; + } + + @Override + public InteractionResult interact(Hand hand) { + GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand); + if (itemStack.getJavaId() == session.getItemMappings().getStoredItems().nameTag()) { + InteractionResult result = checkInteractWithNameTag(itemStack); + if (result.consumesAction()) { + return result; + } + } + + return super.interact(hand); + } + + /** + * Checks to see if a nametag interaction would go through. + */ + protected final InteractionResult checkInteractWithNameTag(GeyserItemStack itemStack) { + CompoundTag nbt = itemStack.getNbt(); + if (nbt != null && nbt.get("display") instanceof CompoundTag displayTag && displayTag.get("Name") instanceof StringTag) { + // The mob shall be named + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + public void updateArmor(GeyserSession session) { if (!valid) return; @@ -255,7 +294,9 @@ public class LivingEntity extends Entity { if (javaAttribute.getType() instanceof AttributeType.Builtin type) { switch (type) { case GENERIC_MAX_HEALTH -> { - this.maxHealth = (float) AttributeUtils.calculateValue(javaAttribute); + // Since 1.18.0, setting the max health to 0 or below causes the entity to die on Bedrock but not on Java + // See https://github.com/GeyserMC/Geyser/issues/2971 + this.maxHealth = Math.max((float) AttributeUtils.calculateValue(javaAttribute), 1f); newAttributes.add(createHealthAttribute()); } case GENERIC_ATTACK_DAMAGE -> newAttributes.add(calculateAttribute(javaAttribute, GeyserAttributeType.ATTACK_DAMAGE)); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java index ffb5e4018..6f722864b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/MinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,16 +27,20 @@ package org.geysermc.geyser.entity.type; 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 com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; import java.util.UUID; public class MinecartEntity extends Entity { - public MinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public MinecartEntity(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.add(0d, definition.offset(), 0d), motion, yaw, pitch, headYaw); } @@ -62,6 +66,41 @@ public class MinecartEntity extends Entity { @Override public Vector3f getBedrockRotation() { // Note: minecart rotation on rails does not care about the actual rotation value - return Vector3f.from(0, yaw, 0); + return Vector3f.from(0, getYaw(), 0); + } + + @Override + protected InteractiveTag testInteraction(Hand hand) { + if (definition == EntityDefinitions.CHEST_MINECART || definition == EntityDefinitions.HOPPER_MINECART) { + return InteractiveTag.OPEN_CONTAINER; + } else { + if (session.isSneaking()) { + return InteractiveTag.NONE; + } else if (!passengers.isEmpty()) { + // Can't enter if someone is inside + return InteractiveTag.NONE; + } else { + // Attempt to enter + return InteractiveTag.RIDE_MINECART; + } + } + } + + @Override + public InteractionResult interact(Hand hand) { + if (definition == EntityDefinitions.CHEST_MINECART || definition == EntityDefinitions.HOPPER_MINECART) { + // Opening the UI of this minecart + return InteractionResult.SUCCESS; + } else { + if (session.isSneaking()) { + return InteractionResult.PASS; + } else if (!passengers.isEmpty()) { + // Can't enter if someone is inside + return InteractionResult.PASS; + } else { + // Attempt to enter + return InteractionResult.SUCCESS; + } + } } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java index e97bb7090..cdd9449e5 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/PaintingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,33 +25,45 @@ package org.geysermc.geyser.entity.type; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.AddPaintingPacket; -import org.geysermc.geyser.entity.EntityDefinitions; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.level.PaintingType; +import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; public class PaintingEntity extends Entity { private static final double OFFSET = -0.46875; - private final PaintingType paintingName; - private final int direction; + private final Direction direction; - public PaintingEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction) { - super(session, entityId, geyserId, uuid, EntityDefinitions.PAINTING, position, Vector3f.ZERO, 0f, 0f, 0f); - this.paintingName = paintingName; + public PaintingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw, Direction direction) { + super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); this.direction = direction; } @Override public void spawnEntity() { + // Wait until we get the metadata needed + } + + public void setPaintingType(ObjectEntityMetadata entityMetadata) { + PaintingType type = PaintingType.getByPaintingType(entityMetadata.getValue()); AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId); - addPaintingPacket.setMotive(paintingName.getBedrockName()); - addPaintingPacket.setPosition(fixOffset()); - addPaintingPacket.setDirection(direction); + addPaintingPacket.setMotive(type.getBedrockName()); + addPaintingPacket.setPosition(fixOffset(type)); + addPaintingPacket.setDirection(switch (direction) { + //TODO this doesn't seem right. Why did it work fine before? + case SOUTH -> 0; + case WEST -> 1; + case NORTH -> 2; + case EAST -> 3; + default -> 0; + }); session.sendUpstreamPacket(addPaintingPacket); valid = true; @@ -64,17 +76,17 @@ public class PaintingEntity extends Entity { // Do nothing, as head look messes up paintings } - private Vector3f fixOffset() { + private Vector3f fixOffset(PaintingType paintingName) { Vector3f position = super.position; position = position.add(0.5, 0.5, 0.5); double widthOffset = paintingName.getWidth() > 1 ? 0.5 : 0; double heightOffset = paintingName.getHeight() > 1 && paintingName.getHeight() != 3 ? 0.5 : 0; return switch (direction) { - case 0 -> position.add(widthOffset, heightOffset, OFFSET); - case 1 -> position.add(-OFFSET, heightOffset, widthOffset); - case 2 -> position.add(-widthOffset, heightOffset, -OFFSET); - case 3 -> position.add(OFFSET, heightOffset, -widthOffset); + case SOUTH -> position.add(widthOffset, heightOffset, OFFSET); + case WEST -> position.add(-OFFSET, heightOffset, widthOffset); + case NORTH -> position.add(-widthOffset, heightOffset, -OFFSET); + case EAST -> position.add(OFFSET, heightOffset, -widthOffset); default -> position; }; } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java index 2cd4cf3f6..5f7c906e9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/SpawnerMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class SpawnerMinecartEntity extends DefaultBlockMinecartEntity { - public SpawnerMinecartEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SpawnerMinecartEntity(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); } 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 e7edd32d5..38f4dba25 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,7 +38,7 @@ import java.util.UUID; public class TNTEntity extends Entity implements Tickable { private int currentTick; - public TNTEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TNTEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java index d68779c9f..ad8b60bdb 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -44,7 +44,7 @@ public class ThrowableEntity extends Entity implements Tickable { protected Vector3f lastJavaPosition; - public ThrowableEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ThrowableEntity(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); this.lastJavaPosition = position; } @@ -56,7 +56,7 @@ public class ThrowableEntity extends Entity implements Tickable { */ @Override public void tick() { - moveAbsoluteImmediate(position.add(motion), yaw, pitch, headYaw, onGround, false); + moveAbsoluteImmediate(position.add(motion), getYaw(), getPitch(), getHeadYaw(), isOnGround(), false); float drag = getDrag(); float gravity = getGravity(); motion = motion.mul(drag).down(gravity); @@ -89,20 +89,20 @@ public class ThrowableEntity extends Entity implements Tickable { } setPosition(position); - if (this.yaw != yaw) { + if (getYaw() != yaw) { moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_YAW); moveEntityDeltaPacket.setYaw(yaw); - this.yaw = yaw; + setYaw(yaw); } - if (this.pitch != pitch) { + if (getPitch() != pitch) { moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_PITCH); moveEntityDeltaPacket.setPitch(pitch); - this.pitch = pitch; + setPitch(pitch); } - if (this.headYaw != headYaw) { + if (getHeadYaw() != headYaw) { moveEntityDeltaPacket.getFlags().add(MoveEntityDeltaPacket.Flag.HAS_HEAD_YAW); moveEntityDeltaPacket.setHeadYaw(headYaw); - this.headYaw = headYaw; + setHeadYaw(headYaw); } if (!moveEntityDeltaPacket.getFlags().isEmpty()) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index 2cee252ec..47031e27b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -44,7 +44,7 @@ public class ThrowableItemEntity extends ThrowableEntity { private int age; private boolean invisible; - public ThrowableItemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ThrowableItemEntity(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); setFlag(EntityFlag.INVISIBLE, true); invisible = false; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index 3b4d5674a..6f6125f2d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -44,7 +44,7 @@ import java.util.UUID; public class ThrownPotionEntity extends ThrowableItemEntity { private static final EnumSet NON_ENCHANTED_POTIONS = EnumSet.of(Potion.WATER, Potion.MUNDANE, Potion.THICK, Potion.AWKWARD); - public ThrownPotionEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ThrownPotionEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java b/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java index 696f9008f..06bf45b3d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Tickable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java index a60c0ab33..d296019c1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TippedArrowEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,7 +39,7 @@ import java.util.UUID; */ public class TippedArrowEntity extends AbstractArrowEntity { - public TippedArrowEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TippedArrowEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/TridentEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/TridentEntity.java index 65591fb50..09d315b19 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/TridentEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/TridentEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,7 @@ import java.util.UUID; public class TridentEntity extends AbstractArrowEntity { - public TridentEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TridentEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java index f645fae34..f70d4afc1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/WitherSkullEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class WitherSkullEntity extends FireballEntity { private boolean isCharged; - public WitherSkullEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public WitherSkullEntity(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); this.futureTicks = 1; diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java index 8fedce1e7..842c94e95 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AbstractFishEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,16 +25,21 @@ package org.geysermc.geyser.entity.type.living; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import javax.annotation.Nonnull; import java.util.UUID; public class AbstractFishEntity extends WaterEntity { - public AbstractFishEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AbstractFishEntity(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); setFlag(EntityFlag.CAN_SWIM, true); @@ -42,4 +47,14 @@ public class AbstractFishEntity extends WaterEntity { setFlag(EntityFlag.CAN_CLIMB, false); setFlag(EntityFlag.HAS_GRAVITY, false); } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (EntityUtils.attemptToBucket(session, itemInHand)) { + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java index b04247a7a..2d1de8ed2 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AgeableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class AgeableEntity extends CreatureEntity { - public AgeableEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AgeableEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java new file mode 100644 index 000000000..ab444c4ab --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AllayEntity.java @@ -0,0 +1,70 @@ +/* + * 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.entity.type.living; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class AllayEntity extends MobEntity { + public AllayEntity(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); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!this.hand.isValid() && !itemInHand.isEmpty()) { + return InteractiveTag.GIVE_ITEM_TO_ALLAY; + } else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { + // Seems like there isn't a good tag for this yet + return InteractiveTag.GIVE_ITEM_TO_ALLAY; + } else { + return super.testMobInteraction(hand, itemInHand); + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!this.hand.isValid() && !itemInHand.isEmpty()) { + //TODO play sound? + return InteractionResult.SUCCESS; + } else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { + //TOCHECK also play sound here? + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java index 693a0cd46..d4c627a8e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/AmbientEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,12 @@ import java.util.UUID; public class AmbientEntity extends MobEntity { - public AmbientEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AmbientEntity(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 boolean canBeLeashed() { + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index fb459bf54..04e4727d0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,8 +26,8 @@ package org.geysermc.geyser.entity.type.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Rotation; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; @@ -39,6 +39,8 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.MathUtils; import java.util.Optional; import java.util.UUID; @@ -78,14 +80,12 @@ public class ArmorStandEntity extends LivingEntity { */ private boolean positionUpdateRequired = false; - public ArmorStandEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ArmorStandEntity(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 public void spawnEntity() { - this.pitch = yaw; - this.headYaw = yaw; super.spawnEntity(); } @@ -136,7 +136,7 @@ public class ArmorStandEntity extends LivingEntity { } isSmall = newIsSmall; - if (!isMarker) { + if (!isMarker && !isInvisible) { // Addition for isInvisible check caused by https://github.com/GeyserMC/Geyser/issues/2780 toggleSmallStatus(); } } @@ -146,13 +146,14 @@ public class ArmorStandEntity extends LivingEntity { isMarker = (xd & 0x10) == 0x10; if (oldIsMarker != isMarker) { if (isMarker) { - dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.0f); - dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.0f); + setBoundingBoxWidth(0.0f); + setBoundingBoxHeight(0.0f); dirtyMetadata.put(EntityData.SCALE, 0f); } else { toggleSmallStatus(); } + updateMountOffset(); updateSecondEntityStatus(false); } @@ -162,27 +163,27 @@ public class ArmorStandEntity extends LivingEntity { setFlag(EntityFlag.ADMIRING, (xd & 0x08) == 0x08); // Has no baseplate } - public void setHeadRotation(EntityMetadata entityMetadata) { + public void setHeadRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.MARK_VARIANT, EntityFlag.INTERESTED, EntityFlag.CHARGED, EntityFlag.POWERED, entityMetadata.getValue()); } - public void setBodyRotation(EntityMetadata entityMetadata) { + public void setBodyRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.VARIANT, EntityFlag.IN_LOVE, EntityFlag.CELEBRATING, EntityFlag.CELEBRATING_SPECIAL, entityMetadata.getValue()); } - public void setLeftArmRotation(EntityMetadata entityMetadata) { + public void setLeftArmRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.TRADE_TIER, EntityFlag.CHARGING, EntityFlag.CRITICAL, EntityFlag.DANCING, entityMetadata.getValue()); } - public void setRightArmRotation(EntityMetadata entityMetadata) { + public void setRightArmRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.MAX_TRADE_TIER, EntityFlag.ELDER, EntityFlag.EMOTING, EntityFlag.IDLING, entityMetadata.getValue()); } - public void setLeftLegRotation(EntityMetadata entityMetadata) { + public void setLeftLegRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.SKIN_ID, EntityFlag.IS_ILLAGER_CAPTAIN, EntityFlag.IS_IN_UI, EntityFlag.LINGERING, entityMetadata.getValue()); } - public void setRightLegRotation(EntityMetadata entityMetadata) { + public void setRightLegRotation(EntityMetadata entityMetadata) { onRotationUpdate(EntityData.HURT_DIRECTION, EntityFlag.IS_PREGNANT, EntityFlag.SHEARED, EntityFlag.STALKING, entityMetadata.getValue()); } @@ -197,13 +198,13 @@ public class ArmorStandEntity extends LivingEntity { * @param negativeZToggle the flag to set true if the Z value of rotation is negative * @param rotation the Java rotation value */ - private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Rotation rotation) { + private void onRotationUpdate(EntityData dataLeech, EntityFlag negativeXToggle, EntityFlag negativeYToggle, EntityFlag negativeZToggle, Vector3f rotation) { // Indicate that rotation should be checked setFlag(EntityFlag.BRIBED, true); - int rotationX = getRotation(rotation.getPitch()); - int rotationY = getRotation(rotation.getYaw()); - int rotationZ = getRotation(rotation.getRoll()); + int rotationX = MathUtils.wrapDegreesToInt(rotation.getX()); + int rotationY = MathUtils.wrapDegreesToInt(rotation.getY()); + int rotationZ = MathUtils.wrapDegreesToInt(rotation.getZ()); // The top bit acts like binary and determines if each rotation goes above 100 // We don't do this for the negative values out of concerns of the number being too big int topBit = (Math.abs(rotationX) >= 100 ? 4 : 0) + (Math.abs(rotationY) >= 100 ? 2 : 0) + (Math.abs(rotationZ) >= 100 ? 1 : 0); @@ -236,6 +237,16 @@ public class ArmorStandEntity extends LivingEntity { } } + @Override + public InteractionResult interactAt(Hand hand) { + if (!isMarker && session.getPlayerInventory().getItemInHand(hand).getJavaId() != session.getItemMappings().getStoredItems().nameTag()) { + // Java Edition returns SUCCESS if in spectator mode, but this is overrided with an earlier check on the client + return InteractionResult.CONSUME; + } else { + return InteractionResult.PASS; + } + } + @Override public void setHelmet(ItemData helmet) { super.setHelmet(helmet); @@ -305,7 +316,7 @@ public class ArmorStandEntity extends LivingEntity { // Create the second entity. It doesn't need to worry about the items, but it does need to worry about // the metadata as it will hold the name tag. secondEntity = new ArmorStandEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), null, - EntityDefinitions.ARMOR_STAND, position, motion, yaw, pitch, headYaw); + EntityDefinitions.ARMOR_STAND, position, motion, getYaw(), getPitch(), getHeadYaw()); secondEntity.primaryEntity = false; if (!this.positionRequiresOffset) { // Ensure the offset is applied for the 0 scale @@ -361,23 +372,12 @@ public class ArmorStandEntity extends LivingEntity { } } - private int getRotation(float rotation) { - rotation = rotation % 360f; - if (rotation < -180f) { - rotation += 360f; - } else if (rotation >= 180f) { - // 181 -> -179 - rotation = -(180 - (rotation - 180)); - } - return (int) rotation; - } - /** * If this armor stand is not a marker, set its bounding box size and scale. */ private void toggleSmallStatus() { - dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, isSmall ? 0.25f : definition.width()); - dirtyMetadata.put(EntityData.BOUNDING_BOX_HEIGHT, isSmall ? 0.9875f : definition.height()); + setBoundingBoxWidth(isSmall ? 0.25f : definition.width()); + setBoundingBoxHeight(isSmall ? 0.9875f : definition.height()); dirtyMetadata.put(EntityData.SCALE, isSmall ? 0.55f : 1f); } @@ -425,9 +425,14 @@ public class ArmorStandEntity extends LivingEntity { MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); moveEntityPacket.setRuntimeEntityId(geyserId); moveEntityPacket.setPosition(position); - moveEntityPacket.setRotation(Vector3f.from(yaw, yaw, yaw)); - moveEntityPacket.setOnGround(onGround); + moveEntityPacket.setRotation(getBedrockRotation()); + moveEntityPacket.setOnGround(isOnGround()); moveEntityPacket.setTeleported(false); session.sendUpstreamPacket(moveEntityPacket); } + + @Override + public Vector3f getBedrockRotation() { + return Vector3f.from(getYaw(), getYaw(), getYaw()); + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java index 0a72a431e..f6bfd8e26 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/BatEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class BatEntity extends AmbientEntity { - public BatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public BatEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/CreatureEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/CreatureEntity.java index b5e7557da..c19b00b21 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/CreatureEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/CreatureEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,7 @@ import java.util.UUID; public class CreatureEntity extends MobEntity { - public CreatureEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public CreatureEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java new file mode 100644 index 000000000..5d49f3e85 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/DolphinEntity.java @@ -0,0 +1,67 @@ +/* + * 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.entity.type.living; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class DolphinEntity extends WaterEntity { + public DolphinEntity(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 boolean canBeLeashed() { + return true; + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { + return InteractiveTag.FEED; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!itemInHand.isEmpty() && session.getTagCache().isFish(itemInHand)) { + // Feed + return InteractionResult.SUCCESS; + } + return super.mobInteract(hand, itemInHand); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/FlyingEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/FlyingEntity.java index 91f839bc3..10d9dc417 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/FlyingEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/FlyingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,7 @@ import java.util.UUID; public class FlyingEntity extends MobEntity { - public FlyingEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public FlyingEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/GlowSquidEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/GlowSquidEntity.java index b5950b7bc..277eee027 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/GlowSquidEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/GlowSquidEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -32,7 +32,7 @@ import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; public class GlowSquidEntity extends SquidEntity { - public GlowSquidEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public GlowSquidEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/GolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/GolemEntity.java index eb94e1406..c6f5727a4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/GolemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/GolemEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,7 @@ import java.util.UUID; public class GolemEntity extends CreatureEntity { - public GolemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public GolemEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java index f86392ed3..e5cbb2f89 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/IronGolemEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,21 +25,39 @@ package org.geysermc.geyser.entity.type.living; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import javax.annotation.Nonnull; import java.util.UUID; public class IronGolemEntity extends GolemEntity { - public IronGolemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public IronGolemEntity(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); // Indicate that we should show cracks through a resource pack setFlag(EntityFlag.BRIBED, true); // Required, or else the overlay is black dirtyMetadata.put(EntityData.COLOR_2, (byte) 0); } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().ironIngot()) { + if (health < maxHealth) { + // Healing the iron golem + return InteractionResult.SUCCESS; + } else { + return InteractionResult.PASS; + } + } + return super.mobInteract(hand, itemInHand); + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/MagmaCubeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/MagmaCubeEntity.java index 03cf9f3dc..2d988373c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/MagmaCubeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/MagmaCubeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class MagmaCubeEntity extends SlimeEntity { - public MagmaCubeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public MagmaCubeEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java index e82b813d7..723a9c431 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/MobEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,14 +26,21 @@ package org.geysermc.geyser.entity.type.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.LivingEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.item.StoredItemMappings; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class MobEntity extends LivingEntity { @@ -43,7 +50,7 @@ public class MobEntity extends LivingEntity { @Getter private long leashHolderBedrockId; - public MobEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public MobEntity(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); } @@ -62,4 +69,95 @@ public class MobEntity extends LivingEntity { this.leashHolderBedrockId = bedrockId; dirtyMetadata.put(EntityData.LEASH_HOLDER_EID, bedrockId); } + + @Override + protected final InteractiveTag testInteraction(Hand hand) { + if (!isAlive()) { + // dead lol + return InteractiveTag.NONE; + } else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) { + return InteractiveTag.REMOVE_LEASH; + } else { + GeyserItemStack itemStack = session.getPlayerInventory().getItemInHand(hand); + StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); + if (itemStack.getJavaId() == storedItems.lead() && canBeLeashed()) { + // We shall leash + return InteractiveTag.LEASH; + } else if (itemStack.getJavaId() == storedItems.nameTag()) { + InteractionResult result = checkInteractWithNameTag(itemStack); + if (result.consumesAction()) { + return InteractiveTag.NAME; + } + } + + InteractiveTag tag = testMobInteraction(hand, itemStack); + return tag != InteractiveTag.NONE ? tag : super.testInteraction(hand); + } + } + + @Override + public final InteractionResult interact(Hand hand) { + if (!isAlive()) { + // dead lol + return InteractionResult.PASS; + } else if (leashHolderBedrockId == session.getPlayerEntity().getGeyserId()) { + // TODO looks like the client assumes it will go through and removes the attachment itself? + return InteractionResult.SUCCESS; + } else { + GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(hand); + InteractionResult result = checkPriorityInteractions(itemInHand); + if (result.consumesAction()) { + return result; + } else { + InteractionResult mobResult = mobInteract(hand, itemInHand); + return mobResult.consumesAction() ? mobResult : super.interact(hand); + } + } + } + + private InteractionResult checkPriorityInteractions(GeyserItemStack itemInHand) { + StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); + if (itemInHand.getJavaId() == storedItems.lead() && canBeLeashed()) { + // We shall leash + return InteractionResult.SUCCESS; + } else if (itemInHand.getJavaId() == storedItems.nameTag()) { + InteractionResult result = checkInteractWithNameTag(itemInHand); + if (result.consumesAction()) { + return result; + } + } else { + ItemMapping mapping = itemInHand.getMapping(session); + if (mapping.getJavaIdentifier().endsWith("_spawn_egg")) { + // Using the spawn egg on this entity to create a child + return InteractionResult.CONSUME; + } + } + + return InteractionResult.PASS; + } + + @Nonnull + protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + return InteractiveTag.NONE; + } + + @Nonnull + protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + return InteractionResult.PASS; + } + + protected boolean canBeLeashed() { + return isNotLeashed() && !isEnemy(); + } + + protected final boolean isNotLeashed() { + return leashHolderBedrockId == -1L; + } + + /** + * Returns if the entity is hostile. Used to determine if it can be leashed. + */ + protected boolean isEnemy() { + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java index 100ed764d..26cf2d627 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SlimeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,11 +35,16 @@ import java.util.UUID; public class SlimeEntity extends MobEntity { - public SlimeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SlimeEntity(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); } public void setScale(IntEntityMetadata entityMetadata) { dirtyMetadata.put(EntityData.SCALE, 0.10f + entityMetadata.getPrimitiveValue()); } + + @Override + protected boolean isEnemy() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java index 1d8375529..b075de882 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/SnowGolemEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,16 +26,21 @@ package org.geysermc.geyser.entity.type.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class SnowGolemEntity extends GolemEntity { - public SnowGolemEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SnowGolemEntity(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); } @@ -44,4 +49,24 @@ public class SnowGolemEntity extends GolemEntity { // Handle the visibility of the pumpkin setFlag(EntityFlag.SHEARED, (xd & 0x10) != 0x10); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) { + // Shearing the snow golem + return InteractiveTag.SHEAR; + } + return InteractiveTag.NONE; + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (session.getItemMappings().getStoredItems().shears() == itemInHand.getJavaId() && isAlive() && !getFlag(EntityFlag.SHEARED)) { + // Shearing the snow golem + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } } 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 b0e2fcb9e..552f6a46c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -41,7 +41,7 @@ public class SquidEntity extends WaterEntity implements Tickable { private boolean inWater; - public SquidEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + 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); } @@ -117,7 +117,12 @@ public class SquidEntity extends WaterEntity implements Tickable { @Override public Vector3f getBedrockRotation() { - return Vector3f.from(pitch, yaw, yaw); + return Vector3f.from(getPitch(), getYaw(), getYaw()); + } + + @Override + protected boolean canBeLeashed() { + return isNotLeashed(); } private void checkInWater() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java new file mode 100644 index 000000000..034dffc65 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/TadpoleEntity.java @@ -0,0 +1,66 @@ +/* + * 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.entity.type.living; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class TadpoleEntity extends AbstractFishEntity { + public TadpoleEntity(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); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (isFood(itemInHand)) { + return InteractiveTag.FEED; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (isFood(itemInHand)) { + //TODO particles + return InteractionResult.SUCCESS; + } + return super.mobInteract(hand, itemInHand); + } + + private boolean isFood(GeyserItemStack itemStack) { + return itemStack.getJavaId() == session.getItemMappings().getStoredItems().slimeBall(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java index acacd1f52..44275a7b1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/WaterEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,12 @@ import java.util.UUID; public class WaterEntity extends CreatureEntity { - public WaterEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public WaterEntity(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 boolean canBeLeashed() { + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java index c7c15b288..0da53b7c6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AnimalEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,20 +25,33 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.AgeableEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class AnimalEntity extends AgeableEntity { - public AnimalEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AnimalEntity(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); } + public final boolean canEat(GeyserItemStack itemStack) { + ItemMapping mapping = itemStack.getMapping(session); + String handIdentifier = mapping.getJavaIdentifier(); + return canEat(handIdentifier.replace("minecraft:", ""), mapping); + } + /** * @param javaIdentifierStripped the stripped Java identifier of the item that is potential breeding food. For example, * wheat. @@ -48,4 +61,28 @@ public class AnimalEntity extends AgeableEntity { // This is what it defaults to. OK. return javaIdentifierStripped.equals("wheat"); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (canEat(itemInHand)) { + return InteractiveTag.FEED; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (canEat(itemInHand)) { + // FEED + if (getFlag(EntityFlag.BABY)) { + playEntityEvent(EntityEventType.BABY_ANIMAL_FEED); + return InteractionResult.SUCCESS; + } else { + return InteractionResult.CONSUME; + } + } + return super.mobInteract(hand, itemInHand); + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java index 4dfa5fa8d..ca7ee57a2 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/AxolotlEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,17 +27,22 @@ package org.geysermc.geyser.entity.type.living.animal; 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 com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import javax.annotation.Nonnull; import java.util.UUID; public class AxolotlEntity extends AnimalEntity { - public AxolotlEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AxolotlEntity(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); } @@ -56,11 +61,26 @@ public class AxolotlEntity extends AnimalEntity { @Override public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { - return javaIdentifierStripped.equals("tropical_fish_bucket"); + return session.getTagCache().isAxolotlTemptItem(mapping); } @Override - protected int getMaxAir() { + protected short getMaxAir() { return 6000; } + + @Override + protected boolean canBeLeashed() { + return true; + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (EntityUtils.attemptToBucket(session, itemInHand)) { + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java index 7f9ec4255..09b1b73c5 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/BeeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -40,7 +40,7 @@ import java.util.UUID; public class BeeEntity extends AnimalEntity { - public BeeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public BeeEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java index 506714dbc..c5fad8bb8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class ChickenEntity extends AnimalEntity { - public ChickenEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ChickenEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java new file mode 100644 index 000000000..3fd55d073 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java @@ -0,0 +1,66 @@ +/* + * 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.entity.type.living.animal; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class CowEntity extends AnimalEntity { + public CowEntity(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); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { + return super.testMobInteraction(hand, itemInHand); + } + + return InteractiveTag.MILK; + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (getFlag(EntityFlag.BABY) || !itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { + return super.mobInteract(hand, itemInHand); + } + + session.playSoundEvent(SoundEvent.MILK, position); + return InteractionResult.SUCCESS; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java index 127a70a0f..5ae3bd524 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FoxEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,7 +38,7 @@ import java.util.UUID; public class FoxEntity extends AnimalEntity { - public FoxEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public FoxEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java new file mode 100644 index 000000000..97af056a0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/FrogEntity.java @@ -0,0 +1,81 @@ +/* + * 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.entity.type.living.animal; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.OptionalInt; +import java.util.UUID; + +public class FrogEntity extends AnimalEntity { + public FrogEntity(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 + public void setPose(Pose pose) { + setFlag(EntityFlag.JUMP_GOAL_JUMP, pose == Pose.LONG_JUMPING); + setFlag(EntityFlag.CROAKING, pose == Pose.CROAKING); + setFlag(EntityFlag.EAT_MOB, pose == Pose.USING_TONGUE); + + super.setPose(pose); + } + + public void setFrogVariant(IntEntityMetadata entityMetadata) { + int variant = entityMetadata.getPrimitiveValue(); + dirtyMetadata.put(EntityData.VARIANT, switch (variant) { + case 1 -> 2; // White + case 2 -> 1; // Green + default -> variant; + }); + } + + public void setTongueTarget(ObjectEntityMetadata entityMetadata) { + OptionalInt entityId = entityMetadata.getValue(); + if (entityId.isPresent()) { + Entity entity = session.getEntityCache().getEntityByJavaId(entityId.getAsInt()); + if (entity != null) { + dirtyMetadata.put(EntityData.TARGET_EID, entity.getGeyserId()); + } + } else { + dirtyMetadata.put(EntityData.TARGET_EID, 0L); + } + } + + @Override + public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { + return mapping.getJavaId() == session.getItemMappings().getStoredItems().slimeBall(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java index 708a95134..a6f2e268e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/GoatEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,21 +27,25 @@ package org.geysermc.geyser.entity.type.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; -import lombok.Getter; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import javax.annotation.Nonnull; import java.util.UUID; public class GoatEntity extends AnimalEntity { private static final float LONG_JUMPING_HEIGHT = 1.3f * 0.7f; private static final float LONG_JUMPING_WIDTH = 0.9f * 0.7f; - @Getter private boolean isScreamer; - public GoatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public GoatEntity(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); } @@ -59,4 +63,15 @@ public class GoatEntity extends AnimalEntity { super.setDimensions(pose); } } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!getFlag(EntityFlag.BABY) && itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { + session.playSoundEvent(isScreamer ? SoundEvent.MILK_SCREAMER : SoundEvent.MILK, position); + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java index ed0feed97..a96d3072c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/HoglinEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,16 +29,15 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanE import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; -import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; public class HoglinEntity extends AnimalEntity { private boolean isImmuneToZombification; - public HoglinEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public HoglinEntity(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,11 +49,21 @@ public class HoglinEntity extends AnimalEntity { @Override protected boolean isShaking() { - return (!isImmuneToZombification && !session.getDimension().equals(DimensionUtils.NETHER)) || super.isShaking(); + return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking(); } @Override public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("crimson_fungus"); } + + @Override + protected boolean canBeLeashed() { + return isNotLeashed(); + } + + @Override + protected boolean isEnemy() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 15473c8ac..d2b8420fd 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,15 +25,63 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class MooshroomEntity extends AnimalEntity { + private boolean isBrown = false; - public MooshroomEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public MooshroomEntity(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); } + + public void setVariant(ObjectEntityMetadata entityMetadata) { + isBrown = entityMetadata.getValue().equals("brown"); + dirtyMetadata.put(EntityData.VARIANT, isBrown ? 1 : 0); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); + if (!isBaby()) { + if (itemInHand.getJavaId() == storedItems.bowl()) { + // Stew + return InteractiveTag.MOOSHROOM_MILK_STEW; + } else if (isAlive() && itemInHand.getJavaId() == storedItems.shears()) { + // Shear items + return InteractiveTag.MOOSHROOM_SHEAR; + } + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + StoredItemMappings storedItems = session.getItemMappings().getStoredItems(); + boolean isBaby = isBaby(); + if (!isBaby && itemInHand.getJavaId() == storedItems.bowl()) { + // Stew + return InteractionResult.SUCCESS; + } else if (!isBaby && isAlive() && itemInHand.getJavaId() == storedItems.shears()) { + // Shear items + return InteractionResult.SUCCESS; + } else if (isBrown && session.getTagCache().isSmallFlower(itemInHand) && itemInHand.getMapping(session).isHasSuspiciousStewEffect()) { + // ? + return InteractionResult.SUCCESS; + } + return super.mobInteract(hand, itemInHand); + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java index 5244e3538..af1fe0bad 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/OcelotEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,16 +25,22 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class OcelotEntity extends AnimalEntity { - public OcelotEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public OcelotEntity(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); } @@ -42,4 +48,26 @@ public class OcelotEntity extends AnimalEntity { public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon"); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) { + // Attempt to feed + return InteractiveTag.FEED; + } else { + return super.testMobInteraction(hand, itemInHand); + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!getFlag(EntityFlag.TRUSTING) && canEat(itemInHand) && session.getPlayerEntity().getPosition().distanceSquared(position) < 9f) { + // Attempt to feed + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java index 7548ccef1..51f595526 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PandaEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,22 +27,28 @@ package org.geysermc.geyser.entity.type.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.UUID; public class PandaEntity extends AnimalEntity { - private int mainGene; - private int hiddenGene; + private Gene mainGene = Gene.NORMAL; + private Gene hiddenGene = Gene.NORMAL; - public PandaEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PandaEntity(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); } @@ -61,12 +67,12 @@ public class PandaEntity extends AnimalEntity { } public void setMainGene(ByteEntityMetadata entityMetadata) { - mainGene = entityMetadata.getPrimitiveValue(); + mainGene = Gene.fromId(entityMetadata.getPrimitiveValue()); updateAppearance(); } public void setHiddenGene(ByteEntityMetadata entityMetadata) { - hiddenGene = entityMetadata.getPrimitiveValue(); + hiddenGene = Gene.fromId(entityMetadata.getPrimitiveValue()); updateAppearance(); } @@ -86,23 +92,81 @@ public class PandaEntity extends AnimalEntity { return javaIdentifierStripped.equals("bamboo"); } + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (mainGene == Gene.WORRIED && session.isThunder()) { + return InteractiveTag.NONE; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (mainGene == Gene.WORRIED && session.isThunder()) { + // Huh! + return InteractionResult.PASS; + } else if (getFlag(EntityFlag.LAYING_DOWN)) { + // Stop the panda from laying down + // TODO laying up is client-side? + return InteractionResult.SUCCESS; + } else if (canEat(itemInHand)) { + if (getFlag(EntityFlag.BABY)) { + playEntityEvent(EntityEventType.BABY_ANIMAL_FEED); + } + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + + @Override + protected boolean canBeLeashed() { + return false; + } + /** * Update the panda's appearance, and take into consideration the recessive brown and weak traits that only show up * when both main and hidden genes match */ private void updateAppearance() { - if (mainGene == 4 || mainGene == 5) { - // Main gene is a recessive trait + if (mainGene.isRecessive) { if (mainGene == hiddenGene) { // Main and hidden genes match; this is what the panda looks like. - dirtyMetadata.put(EntityData.VARIANT, mainGene); + dirtyMetadata.put(EntityData.VARIANT, mainGene.ordinal()); } else { // Genes have no effect on appearance - dirtyMetadata.put(EntityData.VARIANT, 0); + dirtyMetadata.put(EntityData.VARIANT, Gene.NORMAL.ordinal()); } } else { // No need to worry about hidden gene - dirtyMetadata.put(EntityData.VARIANT, mainGene); + dirtyMetadata.put(EntityData.VARIANT, mainGene.ordinal()); + } + } + + enum Gene { + NORMAL(false), + LAZY(false), + WORRIED(false), + PLAYFUL(false), + BROWN(true), + WEAK(true), + AGGRESSIVE(false); + + private static final Gene[] VALUES = values(); + + private final boolean isRecessive; + + Gene(boolean isRecessive) { + this.isRecessive = isRecessive; + } + + @Nullable + private static Gene fromId(int id) { + if (id < 0 || id >= VALUES.length) { + return NORMAL; + } + return VALUES[id]; } } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java index 0be4c78f1..db8a1ccd8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,16 +25,23 @@ package org.geysermc.geyser.entity.type.living.animal; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class PigEntity extends AnimalEntity { - public PigEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PigEntity(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); } @@ -42,4 +49,37 @@ public class PigEntity extends AnimalEntity { public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot"); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { + // Mount + return InteractiveTag.MOUNT; + } else { + InteractiveTag superTag = super.testMobInteraction(hand, itemInHand); + if (superTag != InteractiveTag.NONE) { + return superTag; + } else { + return EntityUtils.attemptToSaddle(session, this, itemInHand).consumesAction() + ? InteractiveTag.SADDLE : InteractiveTag.NONE; + } + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { + // Mount + return InteractionResult.SUCCESS; + } else { + InteractionResult superResult = super.mobInteract(hand, itemInHand); + if (superResult.consumesAction()) { + return superResult; + } else { + return EntityUtils.attemptToSaddle(session, this, itemInHand); + } + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java index 727804dbc..b677c135e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PolarBearEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class PolarBearEntity extends AnimalEntity { - public PolarBearEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PolarBearEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java index 66853babf..76ba15e09 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PufferFishEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class PufferFishEntity extends AbstractFishEntity { - public PufferFishEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PufferFishEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java index a1d80ac72..966e500b4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/RabbitEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,7 +38,7 @@ import java.util.UUID; public class RabbitEntity extends AnimalEntity { - public RabbitEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public RabbitEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java index 757c5b574..0febfdb11 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/SheepEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,23 +26,74 @@ package org.geysermc.geyser.entity.type.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.geyser.util.ItemUtils; +import javax.annotation.Nonnull; import java.util.UUID; public class SheepEntity extends AnimalEntity { + private int color; - public SheepEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SheepEntity(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); } public void setSheepFlags(ByteEntityMetadata entityMetadata) { - byte xd = ((ByteEntityMetadata) entityMetadata).getPrimitiveValue(); + byte xd = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.SHEARED, (xd & 0x10) == 0x10); - dirtyMetadata.put(EntityData.COLOR, xd); + color = xd & 15; + dirtyMetadata.put(EntityData.COLOR, (byte) color); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().shears()) { + return InteractiveTag.SHEAR; + } else { + InteractiveTag tag = super.testMobInteraction(hand, itemInHand); + if (tag != InteractiveTag.NONE) { + return tag; + } else { + int color = ItemUtils.dyeColorFor(itemInHand.getJavaId()); + if (canDye(color)) { + return InteractiveTag.DYE; + } + return InteractiveTag.NONE; + } + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().shears()) { + return InteractionResult.CONSUME; + } else { + InteractionResult superResult = super.mobInteract(hand, itemInHand); + if (superResult.consumesAction()) { + return superResult; + } else { + int color = ItemUtils.dyeColorFor(itemInHand.getJavaId()); + if (canDye(color)) { + // Dyeing the sheep + return InteractionResult.SUCCESS; + } + return InteractionResult.PASS; + } + } + } + + private boolean canDye(int color) { + return color != -1 && color != this.color && !getFlag(EntityFlag.SHEARED); } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java index d684fba06..f8d549299 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/StriderEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,20 +26,26 @@ package org.geysermc.geyser.entity.type.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.EntityUtils; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class StriderEntity extends AnimalEntity { private boolean isCold = false; - public StriderEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public StriderEntity(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); setFlag(EntityFlag.FIRE_IMMUNE, true); @@ -60,12 +66,8 @@ public class StriderEntity extends AnimalEntity { // Needs to copy the parent state if (getFlag(EntityFlag.RIDING)) { boolean parentShaking = false; - //TODO optimize - for (Entity ent : session.getEntityCache().getEntities().values()) { - if (ent.getPassengers().contains(entityId) && ent instanceof StriderEntity) { - parentShaking = ent.getFlag(EntityFlag.SHAKING); - break; - } + if (vehicle instanceof StriderEntity) { + parentShaking = vehicle.getFlag(EntityFlag.SHAKING); } setFlag(EntityFlag.BREATHING, !parentShaking); @@ -76,10 +78,9 @@ public class StriderEntity extends AnimalEntity { } // Update the passengers if we have any - for (long passenger : passengers) { - Entity passengerEntity = session.getEntityCache().getEntityByJavaId(passenger); - if (passengerEntity != null) { - passengerEntity.updateBedrockMetadata(); + for (Entity passenger : passengers) { + if (passenger != null) { + passenger.updateBedrockMetadata(); } } @@ -95,4 +96,37 @@ public class StriderEntity extends AnimalEntity { public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("warped_fungus"); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { + // Mount Strider + return InteractiveTag.RIDE_STRIDER; + } else { + InteractiveTag tag = super.testMobInteraction(hand, itemInHand); + if (tag != InteractiveTag.NONE) { + return tag; + } else { + return EntityUtils.attemptToSaddle(session, this, itemInHand).consumesAction() + ? InteractiveTag.SADDLE : InteractiveTag.NONE; + } + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!canEat(itemInHand) && getFlag(EntityFlag.SADDLED) && passengers.isEmpty() && !session.isSneaking()) { + // Mount Strider + return InteractionResult.SUCCESS; + } else { + InteractionResult superResult = super.mobInteract(hand, itemInHand); + if (superResult.consumesAction()) { + return superResult; + } else { + return EntityUtils.attemptToSaddle(session, this, itemInHand); + } + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java index b883c91a9..384ba30d4 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TropicalFishEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -48,7 +48,7 @@ public class TropicalFishEntity extends AbstractFishEntity { private static final List VARIANT_NAMES = ImmutableList.of("kob", "sunstreak", "snooper", "dasher", "brinely", "spotty", "flopper", "stripey", "glitter", "blockfish", "betty", "clayfish"); private static final List COLOR_NAMES = ImmutableList.of("white", "orange", "magenta", "light_blue", "yellow", "lime", "pink", "gray", "light_gray", "cyan", "purple", "blue", "brown", "green", "red", "black"); - public TropicalFishEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TropicalFishEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java index e892d7d5e..79a7b8f50 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/TurtleEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class TurtleEntity extends AnimalEntity { - public TurtleEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TurtleEntity(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); } @@ -52,4 +52,9 @@ public class TurtleEntity extends AnimalEntity { public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("seagrass"); } + + @Override + protected boolean canBeLeashed() { + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java index 7d0a3cf9a..867d9f799 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/AbstractHorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.entity.type.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -37,9 +38,13 @@ import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.Set; import java.util.UUID; @@ -51,7 +56,7 @@ public class AbstractHorseEntity extends AnimalEntity { private static final Set DONKEY_AND_HORSE_FOODS = ImmutableSet.of("golden_apple", "enchanted_golden_apple", "golden_carrot", "sugar", "apple", "wheat", "hay_block"); - public AbstractHorseEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AbstractHorseEntity(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); // Specifies the size of the entity's inventory. Required to place slots in the entity. @@ -122,4 +127,164 @@ public class AbstractHorseEntity extends AnimalEntity { public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return testHorseInteraction(hand, itemInHand); + } + + @Nonnull + protected final InteractiveTag testHorseInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + boolean isBaby = isBaby(); + if (!isBaby) { + if (getFlag(EntityFlag.TAMED) && session.isSneaking()) { + return InteractiveTag.OPEN_CONTAINER; + } + + if (!passengers.isEmpty()) { + return super.testMobInteraction(hand, itemInHand); + } + } + + if (!itemInHand.isEmpty()) { + if (canEat(itemInHand)) { + return InteractiveTag.FEED; + } + + if (testSaddle(itemInHand)) { + return InteractiveTag.SADDLE; + } + + if (!getFlag(EntityFlag.TAMED)) { + // Horse will become mad + return InteractiveTag.NONE; + } + + if (testForChest(itemInHand)) { + return InteractiveTag.ATTACH_CHEST; + } + + if (additionalTestForInventoryOpen(itemInHand) || !isBaby && !getFlag(EntityFlag.SADDLED) && itemInHand.getJavaId() == session.getItemMappings().getStoredItems().saddle()) { + // Will open the inventory to be saddled + return InteractiveTag.OPEN_CONTAINER; + } + } + + if (isBaby) { + return super.testMobInteraction(hand, itemInHand); + } else { + return InteractiveTag.MOUNT; + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return mobHorseInteract(hand, itemInHand); + } + + @Nonnull + protected final InteractionResult mobHorseInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + boolean isBaby = isBaby(); + if (!isBaby) { + if (getFlag(EntityFlag.TAMED) && session.isSneaking()) { + // Will open the inventory + return InteractionResult.SUCCESS; + } + + if (!passengers.isEmpty()) { + return super.mobInteract(hand, itemInHand); + } + } + + if (!itemInHand.isEmpty()) { + if (canEat(itemInHand)) { + if (isBaby) { + playEntityEvent(EntityEventType.BABY_ANIMAL_FEED); + } + return InteractionResult.CONSUME; + } + + if (testSaddle(itemInHand)) { + return InteractionResult.SUCCESS; + } + + if (!getFlag(EntityFlag.TAMED)) { + // Horse will become mad + return InteractionResult.SUCCESS; + } + + if (testForChest(itemInHand)) { + // TODO looks like chest is also handled client side + return InteractionResult.SUCCESS; + } + + // Note: yes, this code triggers for llamas too. lol (as of Java Edition 1.18.1) + if (additionalTestForInventoryOpen(itemInHand) || (!isBaby && !getFlag(EntityFlag.SADDLED) && itemInHand.getJavaId() == session.getItemMappings().getStoredItems().saddle())) { + // Will open the inventory to be saddled + return InteractionResult.SUCCESS; + } + } + + if (isBaby) { + return super.mobInteract(hand, itemInHand); + } else { + // Attempt to mount + // TODO client-set flags sitting standing? + return InteractionResult.SUCCESS; + } + } + + protected boolean testSaddle(@Nonnull GeyserItemStack itemInHand) { + return isAlive() && !getFlag(EntityFlag.BABY) && getFlag(EntityFlag.TAMED); + } + + protected boolean testForChest(@Nonnull GeyserItemStack itemInHand) { + return false; + } + + protected boolean additionalTestForInventoryOpen(@Nonnull GeyserItemStack itemInHand) { + return itemInHand.getMapping(session).getJavaIdentifier().endsWith("_horse_armor"); + } + + /* Just a place to stuff common code for the undead variants without having duplicate code */ + + protected final InteractiveTag testUndeadHorseInteraction(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!getFlag(EntityFlag.TAMED)) { + return InteractiveTag.NONE; + } else if (isBaby()) { + return testHorseInteraction(hand, itemInHand); + } else if (session.isSneaking()) { + return InteractiveTag.OPEN_CONTAINER; + } else if (!passengers.isEmpty()) { + return testHorseInteraction(hand, itemInHand); + } else { + if (session.getItemMappings().getStoredItems().saddle() == itemInHand.getJavaId()) { + return InteractiveTag.OPEN_CONTAINER; + } + + if (testSaddle(itemInHand)) { + return InteractiveTag.SADDLE; + } + + return InteractiveTag.RIDE_HORSE; + } + } + + protected final InteractionResult undeadHorseInteract(@Nonnull Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (!getFlag(EntityFlag.TAMED)) { + return InteractionResult.PASS; + } else if (isBaby()) { + return mobHorseInteract(hand, itemInHand); + } else if (session.isSneaking()) { + // Opens inventory + return InteractionResult.SUCCESS; + } else if (!passengers.isEmpty()) { + return mobHorseInteract(hand, itemInHand); + } else { + // The client tests for saddle but it doesn't matter for us at this point. + return InteractionResult.SUCCESS; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ChestedHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ChestedHorseEntity.java index ccf30dbc8..7d59be713 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ChestedHorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ChestedHorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,14 +26,17 @@ package org.geysermc.geyser.entity.type.living.animal.horse; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import javax.annotation.Nonnull; import java.util.UUID; public class ChestedHorseEntity extends AbstractHorseEntity { - public ChestedHorseEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ChestedHorseEntity(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); } @@ -41,4 +44,21 @@ public class ChestedHorseEntity extends AbstractHorseEntity { protected int getContainerBaseSize() { return 16; } + + @Override + protected boolean testSaddle(@Nonnull GeyserItemStack itemInHand) { + // Not checked here + return false; + } + + @Override + protected boolean testForChest(@Nonnull GeyserItemStack itemInHand) { + return itemInHand.getJavaId() == session.getItemMappings().getStoredItems().chest() && !getFlag(EntityFlag.CHESTED); + } + + @Override + protected boolean additionalTestForInventoryOpen(@Nonnull GeyserItemStack itemInHand) { + // Armor won't work on these + return false; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java index 31b5b7890..d084ed3e3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/HorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class HorseEntity extends AbstractHorseEntity { - public HorseEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public HorseEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java index c18778c81..c2548daaf 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/LlamaEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,14 +31,14 @@ import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; public class LlamaEntity extends ChestedHorseEntity { - public LlamaEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public LlamaEntity(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); dirtyMetadata.put(EntityData.CONTAINER_STRENGTH_MODIFIER, 3); // Presumably 3 slots for every 1 strength diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java similarity index 51% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.java rename to core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java index 433d78477..4d07c7d13 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPaintingTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/SkeletonHorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,27 +23,33 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.java.entity.spawn; +package org.geysermc.geyser.entity.type.living.animal.horse; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddPaintingPacket; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.PaintingEntity; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.PaintingType; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; -@Translator(packet = ClientboundAddPaintingPacket.class) -public class JavaAddPaintingTranslator extends PacketTranslator { +import javax.annotation.Nonnull; +import java.util.UUID; +public class SkeletonHorseEntity extends AbstractHorseEntity { + public SkeletonHorseEntity(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); + } + + @Nonnull @Override - public void translate(GeyserSession session, ClientboundAddPaintingPacket packet) { - Vector3f position = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()); + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return testUndeadHorseInteraction(hand, itemInHand); + } - PaintingEntity entity = new PaintingEntity(session, packet.getEntityId(), - session.getEntityCache().getNextEntityId().incrementAndGet(), packet.getUuid(), - position, PaintingType.getByPaintingType(packet.getPaintingType()), packet.getDirection().getHorizontalIndex()); - - session.getEntityCache().spawnEntity(entity); + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return undeadHorseInteract(hand, itemInHand); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/TraderLlamaEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/TraderLlamaEntity.java index 770d30a05..ff3fba9b0 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/TraderLlamaEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/TraderLlamaEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class TraderLlamaEntity extends LlamaEntity { - public TraderLlamaEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TraderLlamaEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java new file mode 100644 index 000000000..659a8bad8 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/horse/ZombieHorseEntity.java @@ -0,0 +1,55 @@ +/* + * 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.entity.type.living.animal.horse; + +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; + +import javax.annotation.Nonnull; +import java.util.UUID; + +public class ZombieHorseEntity extends AbstractHorseEntity { + public ZombieHorseEntity(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); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return testUndeadHorseInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + return undeadHorseInteract(hand, itemInHand); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java index 5538621d9..022535592 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/CatEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,20 +28,25 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class CatEntity extends TameableEntity { private byte collarColor; - public CatEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public CatEntity(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); } @@ -98,4 +103,28 @@ public class CatEntity extends TameableEntity { public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { return javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon"); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + boolean tamed = getFlag(EntityFlag.TAMED); + if (tamed && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { + // Toggle sitting + return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; + } else { + return !canEat(itemInHand) || health >= maxHealth && tamed ? InteractiveTag.NONE : InteractiveTag.FEED; + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + boolean tamed = getFlag(EntityFlag.TAMED); + if (tamed && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { + return InteractionResult.SUCCESS; + } else { + // Attempt to feed + return !canEat(itemInHand) || health >= maxHealth && tamed ? InteractionResult.PASS : InteractionResult.SUCCESS; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java index 05f0a6ad5..2b49168dd 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/ParrotEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,21 +25,67 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class ParrotEntity extends TameableEntity { - public ParrotEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ParrotEntity(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 public boolean canEat(String javaIdentifierStripped, ItemMapping mapping) { - return javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie"); + return false; + } + + private boolean isTameFood(String javaIdentifierStripped) { + return javaIdentifierStripped.contains("seeds"); + } + + private boolean isPoisonousFood(String javaIdentifierStripped) { + return javaIdentifierStripped.equals("cookie"); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + String javaIdentifierStripped = itemInHand.getMapping(session).getJavaIdentifier().replace("minecraft:", ""); + boolean tame = getFlag(EntityFlag.TAMED); + if (!tame && isTameFood(javaIdentifierStripped)) { + return InteractiveTag.FEED; + } else if (isPoisonousFood(javaIdentifierStripped)) { + return InteractiveTag.FEED; + } else if (onGround && tame && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { + // Sitting/standing + return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + String javaIdentifierStripped = itemInHand.getMapping(session).getJavaIdentifier().replace("minecraft:", ""); + boolean tame = getFlag(EntityFlag.TAMED); + if (!tame && isTameFood(javaIdentifierStripped)) { + return InteractionResult.SUCCESS; + } else if (isPoisonousFood(javaIdentifierStripped)) { + return InteractionResult.SUCCESS; + } else if (onGround && tame && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { + // Sitting/standing + return InteractionResult.SUCCESS; + } + return super.mobInteract(hand, itemInHand); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java index d12839e92..33b2144e8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/TameableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -46,7 +46,7 @@ public class TameableEntity extends AnimalEntity { @Getter protected long ownerBedrockId; - public TameableEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public TameableEntity(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); } @@ -61,17 +61,30 @@ public class TameableEntity extends AnimalEntity { // Note: Must be set for wolf collar color to work if (entityMetadata.getValue().isPresent()) { // Owner UUID of entity - Entity entity = session.getEntityCache().getPlayerEntity(entityMetadata.getValue().get()); + UUID uuid = entityMetadata.getValue().get(); + Entity entity; + if (uuid.equals(session.getPlayerEntity().getUuid())) { + entity = session.getPlayerEntity(); + } else { + entity = session.getEntityCache().getPlayerEntity(uuid); + } // Used as both a check since the player isn't in the entity cache and a normal fallback if (entity == null) { - entity = session.getPlayerEntity(); + // Set to tame, but indicate that we are not the player that owns this + ownerBedrockId = Long.MAX_VALUE; + } else { + // Translate to entity ID + ownerBedrockId = entity.getGeyserId(); } - // Translate to entity ID - ownerBedrockId = entity.getGeyserId(); } else { // Reset ownerBedrockId = 0L; } dirtyMetadata.put(EntityData.OWNER_EID, ownerBedrockId); } + + @Override + protected boolean canBeLeashed() { + return isNotLeashed(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java index 13bb8e17d..bc5209bcb 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,14 +27,20 @@ package org.geysermc.geyser.entity.type.living.animal.tameable; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import org.geysermc.geyser.util.ItemUtils; +import javax.annotation.Nonnull; import java.util.Set; import java.util.UUID; @@ -49,7 +55,7 @@ public class WolfEntity extends TameableEntity { private byte collarColor; - public WolfEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public WolfEntity(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); } @@ -90,4 +96,45 @@ public class WolfEntity extends TameableEntity { // Cannot be a baby to eat these foods return WOLF_FOODS.contains(javaIdentifierStripped) && !isBaby(); } + + @Override + protected boolean canBeLeashed() { + return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed(); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (getFlag(EntityFlag.ANGRY)) { + return InteractiveTag.NONE; + } + if (itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bone") && !getFlag(EntityFlag.TAMED)) { + // Bone and untamed - can tame + return InteractiveTag.TAME; + } else { + int color = ItemUtils.dyeColorFor(itemInHand.getJavaId()); + if (color != -1) { + // If this fails, as of Java Edition 1.18.1, you cannot toggle sit/stand + if (color != this.collarColor) { + return InteractiveTag.DYE; + } + } else if (getFlag(EntityFlag.TAMED) && ownerBedrockId == session.getPlayerEntity().getGeyserId()) { + // Tamed and owned by player - can sit/stand + return getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; + } + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (ownerBedrockId == session.getPlayerEntity().getGeyserId() || getFlag(EntityFlag.TAMED) + || itemInHand.getMapping(session).getJavaIdentifier().equals("minecraft:bone") && !getFlag(EntityFlag.ANGRY)) { + // Sitting toggle or feeding; not angry + return InteractionResult.CONSUME; + } else { + return InteractionResult.PASS; + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java index 7981c9b23..e6538ebad 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/AbstractMerchantEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,16 +25,56 @@ package org.geysermc.geyser.entity.type.living.merchant; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.living.AgeableEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class AbstractMerchantEntity extends AgeableEntity { - public AbstractMerchantEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AbstractMerchantEntity(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 boolean canBeLeashed() { + return false; + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + String javaIdentifier = itemInHand.getMapping(session).getJavaIdentifier(); + if (!javaIdentifier.equals("minecraft:villager_spawn_egg") + && (definition != EntityDefinitions.VILLAGER || !getFlag(EntityFlag.SLEEPING) && ((VillagerEntity) this).isCanTradeWith())) { + // An additional check we know cannot work + if (!isBaby()) { + return InteractiveTag.TRADE; + } + } + return super.testMobInteraction(hand, itemInHand); + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + String javaIdentifier = itemInHand.getMapping(session).getJavaIdentifier(); + if (!javaIdentifier.equals("minecraft:villager_spawn_egg") + && (definition != EntityDefinitions.VILLAGER || !getFlag(EntityFlag.SLEEPING)) + && (definition != EntityDefinitions.WANDERING_TRADER || !getFlag(EntityFlag.BABY))) { + // Trading time + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java index 012fb05f2..e77d34f23 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/merchant/VillagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,59 +26,55 @@ package org.geysermc.geyser.entity.type.living.merchant; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.metadata.VillagerData; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import lombok.Getter; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; import java.util.Optional; import java.util.UUID; public class VillagerEntity extends AbstractMerchantEntity { - /** * A map of Java profession IDs to Bedrock IDs */ - public static final Int2IntMap VILLAGER_PROFESSIONS = new Int2IntOpenHashMap(); + private static final int[] VILLAGER_PROFESSIONS = new int[15]; /** * A map of all Java region IDs (plains, savanna...) to Bedrock */ - public static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap(); + private static final int[] VILLAGER_REGIONS = new int[7]; static { // Java villager profession IDs -> Bedrock - VILLAGER_PROFESSIONS.put(0, 0); - VILLAGER_PROFESSIONS.put(1, 8); - VILLAGER_PROFESSIONS.put(2, 11); - VILLAGER_PROFESSIONS.put(3, 6); - VILLAGER_PROFESSIONS.put(4, 7); - VILLAGER_PROFESSIONS.put(5, 1); - VILLAGER_PROFESSIONS.put(6, 2); - VILLAGER_PROFESSIONS.put(7, 4); - VILLAGER_PROFESSIONS.put(8, 12); - VILLAGER_PROFESSIONS.put(9, 5); - VILLAGER_PROFESSIONS.put(10, 13); - VILLAGER_PROFESSIONS.put(11, 14); - VILLAGER_PROFESSIONS.put(12, 3); - VILLAGER_PROFESSIONS.put(13, 10); - VILLAGER_PROFESSIONS.put(14, 9); + VILLAGER_PROFESSIONS[0] = 0; + VILLAGER_PROFESSIONS[1] = 8; + VILLAGER_PROFESSIONS[2] = 11; + VILLAGER_PROFESSIONS[3] = 6; + VILLAGER_PROFESSIONS[4] = 7; + VILLAGER_PROFESSIONS[5] = 1; + VILLAGER_PROFESSIONS[6] = 2; + VILLAGER_PROFESSIONS[7] = 4; + VILLAGER_PROFESSIONS[8] = 12; + VILLAGER_PROFESSIONS[9] = 5; + VILLAGER_PROFESSIONS[10] = 13; + VILLAGER_PROFESSIONS[11] = 14; + VILLAGER_PROFESSIONS[12] = 3; + VILLAGER_PROFESSIONS[13] = 10; + VILLAGER_PROFESSIONS[14] = 9; - VILLAGER_REGIONS.put(0, 1); - VILLAGER_REGIONS.put(1, 2); - VILLAGER_REGIONS.put(2, 0); - VILLAGER_REGIONS.put(3, 3); - VILLAGER_REGIONS.put(4, 4); - VILLAGER_REGIONS.put(5, 5); - VILLAGER_REGIONS.put(6, 6); + VILLAGER_REGIONS[0] = 1; + VILLAGER_REGIONS[1] = 2; + VILLAGER_REGIONS[2] = 0; + VILLAGER_REGIONS[3] = 3; + VILLAGER_REGIONS[4] = 4; + VILLAGER_REGIONS[5] = 5; + VILLAGER_REGIONS[6] = 6; } private Vector3i bedPosition; @@ -88,25 +84,25 @@ public class VillagerEntity extends AbstractMerchantEntity { @Getter private boolean canTradeWith; - public VillagerEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public VillagerEntity(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); } public void setVillagerData(EntityMetadata entityMetadata) { VillagerData villagerData = entityMetadata.getValue(); // Profession - int profession = VILLAGER_PROFESSIONS.get(villagerData.getProfession()); + int profession = getBedrockProfession(villagerData.getProfession()); canTradeWith = profession != 14 && profession != 0; // Not a notwit and not professionless dirtyMetadata.put(EntityData.VARIANT, profession); //metadata.put(EntityData.SKIN_ID, villagerData.getType()); Looks like this is modified but for any reason? // Region - dirtyMetadata.put(EntityData.MARK_VARIANT, VILLAGER_REGIONS.get(villagerData.getType())); + dirtyMetadata.put(EntityData.MARK_VARIANT, getBedrockRegion(villagerData.getType())); // Trade tier - different indexing in Bedrock dirtyMetadata.put(EntityData.TRADE_TIER, villagerData.getLevel() - 1); } @Override - public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { + public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { return bedPosition = super.setBedPosition(entityMetadata); } @@ -158,4 +154,12 @@ public class VillagerEntity extends AbstractMerchantEntity { moveEntityPacket.setTeleported(false); session.sendUpstreamPacket(moveEntityPacket); } + + public static int getBedrockProfession(int javaProfession) { + return javaProfession >= 0 && javaProfession < VILLAGER_PROFESSIONS.length ? VILLAGER_PROFESSIONS[javaProfession] : 0; + } + + public static int getBedrockRegion(int javaRegion) { + return javaRegion >= 0 && javaRegion < VILLAGER_REGIONS.length ? VILLAGER_REGIONS[javaRegion] : 0; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java index ae13cfeae..baa48fcc1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/AbstractSkeletonEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class AbstractSkeletonEntity extends MonsterEntity { - public AbstractSkeletonEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AbstractSkeletonEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java index 2f315368f..e003dd080 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BasePiglinEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -30,14 +30,13 @@ import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.util.DimensionUtils; import java.util.UUID; public class BasePiglinEntity extends MonsterEntity { private boolean isImmuneToZombification; - public BasePiglinEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public BasePiglinEntity(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); } @@ -49,6 +48,6 @@ public class BasePiglinEntity extends MonsterEntity { @Override protected boolean isShaking() { - return (!isImmuneToZombification && !session.getDimension().equals(DimensionUtils.NETHER)) || super.isShaking(); + return (!isImmuneToZombification && !session.getDimensionType().piglinSafe()) || super.isShaking(); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java index 2303f8091..02539b26a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/BlazeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class BlazeEntity extends MonsterEntity { - public BlazeEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public BlazeEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java index f1e0b6a65..f73ab257a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/CreeperEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,11 +27,17 @@ package org.geysermc.geyser.entity.type.living.monster; 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 com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class CreeperEntity extends MonsterEntity { @@ -41,7 +47,7 @@ public class CreeperEntity extends MonsterEntity { */ private boolean ignitedByFlintAndSteel = false; - public CreeperEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public CreeperEntity(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); } @@ -55,4 +61,26 @@ public class CreeperEntity extends MonsterEntity { ignitedByFlintAndSteel = entityMetadata.getPrimitiveValue(); setFlag(EntityFlag.IGNITED, ignitedByFlintAndSteel); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) { + return InteractiveTag.IGNITE_CREEPER; + } else { + return super.testMobInteraction(hand, itemInHand); + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().flintAndSteel()) { + // Ignite creeper + session.playSoundEvent(SoundEvent.IGNITE, position); + return InteractionResult.SUCCESS; + } else { + return super.mobInteract(hand, itemInHand); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ElderGuardianEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ElderGuardianEntity.java index 9c237f117..1ac4e9527 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ElderGuardianEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ElderGuardianEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class ElderGuardianEntity extends GuardianEntity { - public ElderGuardianEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ElderGuardianEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java index f49b51e6c..6adcb4694 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,6 +39,7 @@ import org.geysermc.geyser.entity.type.living.MobEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.DimensionUtils; +import java.util.Optional; import java.util.Random; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -79,7 +80,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { private float wingPosition; private float lastWingPosition; - public EnderDragonEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public EnderDragonEntity(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); } @@ -130,7 +131,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { for (int i = 0; i < segmentHistory.length; i++) { segmentHistory[i] = new Segment(); - segmentHistory[i].yaw = headYaw; + segmentHistory[i].yaw = getHeadYaw(); segmentHistory[i].y = position.getY(); } } @@ -150,6 +151,11 @@ public class EnderDragonEntity extends MobEntity implements Tickable { return super.despawnEntity(); } + @Override + protected boolean isEnemy() { + return true; + } + @Override public void tick() { effectTick(); @@ -163,7 +169,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { * Updates the positions of the Ender Dragon's multiple bounding boxes */ private void updateBoundingBoxes() { - Vector3f facingDir = Vector3f.createDirectionDeg(0, headYaw); + Vector3f facingDir = Vector3f.createDirectionDeg(0, getHeadYaw()); Segment baseSegment = getSegment(5); // Used to angle the head, neck, and tail when the dragon flies up/down float pitch = (float) Math.toRadians(10 * (baseSegment.getY() - getSegment(10).getY())); @@ -182,7 +188,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { neck.setPosition(facingDir.up(pitchY).mul(pitchXZ, 1, -pitchXZ).mul(5.5f).up(headDuck)); body.setPosition(facingDir.mul(0.5f, 0f, -0.5f)); - Vector3f wingPos = Vector3f.createDirectionDeg(0, 90f - headYaw).mul(4.5f).up(2f); + Vector3f wingPos = Vector3f.createDirectionDeg(0, 90f - getHeadYaw()).mul(4.5f).up(2f); rightWing.setPosition(wingPos); leftWing.setPosition(wingPos.mul(-1, 1, -1)); // Mirror horizontally @@ -191,7 +197,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { float distance = (i + 1) * 2f; // Curls the tail when the dragon turns Segment targetSegment = getSegment(12 + 2 * i); - float angle = headYaw + targetSegment.yaw - baseSegment.yaw; + float angle = getHeadYaw() + targetSegment.yaw - baseSegment.yaw; float tailYOffset = targetSegment.y - baseSegment.y - (distance + 1.5f) * pitchY + 1.5f; tail[i].setPosition(Vector3f.createDirectionDeg(0, angle).mul(distance).add(tailBase).mul(-pitchXZ, 1, pitchXZ).up(tailYOffset)); @@ -207,7 +213,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { */ private void effectTick() { Random random = ThreadLocalRandom.current(); - if (!getFlag(EntityFlag.SILENT)) { + if (!silent) { if (Math.cos(wingPosition * 2f * Math.PI) <= -0.3f && Math.cos(lastWingPosition * 2f * Math.PI) >= -0.3f) { PlaySoundPacket playSoundPacket = new PlaySoundPacket(); playSoundPacket.setSound("mob.enderdragon.flap"); @@ -257,6 +263,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { spawnParticleEffectPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension())); spawnParticleEffectPacket.setPosition(head.getPosition().add(random.nextGaussian() / 2f, random.nextGaussian() / 2f, random.nextGaussian() / 2f)); spawnParticleEffectPacket.setIdentifier("minecraft:dragon_breath_fire"); + spawnParticleEffectPacket.setMolangVariablesJson(Optional.empty()); session.sendUpstreamPacket(spawnParticleEffectPacket); } } @@ -288,10 +295,6 @@ public class EnderDragonEntity extends MobEntity implements Tickable { session.sendUpstreamPacket(playSoundPacket); } - private boolean isAlive() { - return health > 0; - } - private boolean isHovering() { return phase == 10; } @@ -305,7 +308,7 @@ public class EnderDragonEntity extends MobEntity implements Tickable { */ private void pushSegment() { latestSegment = (latestSegment + 1) % segmentHistory.length; - segmentHistory[latestSegment].yaw = headYaw; + segmentHistory[latestSegment].yaw = getHeadYaw(); segmentHistory[latestSegment].y = position.getY(); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonPartEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonPartEntity.java index 7cd4bb6cf..a169081fc 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonPartEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EnderDragonPartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import org.geysermc.geyser.session.GeyserSession; public class EnderDragonPartEntity extends Entity { - public EnderDragonPartEntity(GeyserSession session, long entityId, long geyserId, float width, float height) { + public EnderDragonPartEntity(GeyserSession session, int entityId, long geyserId, float width, float height) { super(session, entityId, geyserId, null, EntityDefinitions.ENDER_DRAGON_PART, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0); dirtyMetadata.put(EntityData.BOUNDING_BOX_WIDTH, width); 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 469f48521..03492d518 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,7 +39,7 @@ import java.util.UUID; public class EndermanEntity extends MonsterEntity { - public EndermanEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public EndermanEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java index 845a281d9..511c56ff7 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GhastEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class GhastEntity extends FlyingEntity { - public GhastEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public GhastEntity(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); } @@ -44,4 +44,9 @@ public class GhastEntity extends FlyingEntity { // If the ghast is attacking dirtyMetadata.put(EntityData.CHARGE_AMOUNT, (byte) (entityMetadata.getPrimitiveValue() ? 1 : 0)); } + + @Override + protected boolean isEnemy() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java index 6dd27cc39..12e0966ea 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GiantEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class GiantEntity extends MonsterEntity { - public GiantEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public GiantEntity(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); dirtyMetadata.put(EntityData.SCALE, 6f); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java index 0190f3c60..fe1f3038b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/GuardianEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,19 +36,13 @@ import java.util.UUID; public class GuardianEntity extends MonsterEntity { - public GuardianEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public GuardianEntity(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); } public void setGuardianTarget(IntEntityMetadata entityMetadata) { int entityId = entityMetadata.getPrimitiveValue(); - Entity entity; - if (session.getPlayerEntity().getEntityId() == entityId) { - entity = session.getPlayerEntity(); - } else { - entity = session.getEntityCache().getEntityByJavaId(entityId); - } - + Entity entity = session.getEntityCache().getEntityByJavaId(entityId); if (entity != null) { dirtyMetadata.put(EntityData.TARGET_EID, entity.getGeyserId()); } else { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/MonsterEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/MonsterEntity.java index fad45f982..92fbeee67 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/MonsterEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/MonsterEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,12 @@ import java.util.UUID; public class MonsterEntity extends CreatureEntity { - public MonsterEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public MonsterEntity(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 boolean isEnemy() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java index 8d3ccc71f..dff79104b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PhantomEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import org.geysermc.geyser.session.GeyserSession; import java.util.UUID; public class PhantomEntity extends FlyingEntity { - public PhantomEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PhantomEntity(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); } @@ -48,4 +48,9 @@ public class PhantomEntity extends FlyingEntity { setBoundingBoxHeight(boundsScale * definition.height()); dirtyMetadata.put(EntityData.SCALE, modelScale); } + + @Override + protected boolean isEnemy() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java index b98d6eabc..4eb0baa6c 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/PiglinEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,17 +26,22 @@ package org.geysermc.geyser.entity.type.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class PiglinEntity extends BasePiglinEntity { - public PiglinEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PiglinEntity(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); } @@ -44,6 +49,8 @@ public class PiglinEntity extends BasePiglinEntity { boolean isBaby = entityMetadata.getPrimitiveValue(); dirtyMetadata.put(EntityData.SCALE, isBaby? .55f : 1f); setFlag(EntityFlag.BABY, isBaby); + + updateMountOffset(); } public void setChargingCrossbow(BooleanEntityMetadata entityMetadata) { @@ -62,4 +69,30 @@ public class PiglinEntity extends BasePiglinEntity { super.updateOffHand(session); } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + InteractiveTag tag = super.testMobInteraction(hand, itemInHand); + if (tag != InteractiveTag.NONE) { + return tag; + } else { + return canGiveGoldTo(itemInHand) ? InteractiveTag.BARTER : InteractiveTag.NONE; + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + InteractionResult superResult = super.mobInteract(hand, itemInHand); + if (superResult.consumesAction()) { + return superResult; + } else { + return canGiveGoldTo(itemInHand) ? InteractionResult.SUCCESS : InteractionResult.PASS; + } + } + + private boolean canGiveGoldTo(@Nonnull GeyserItemStack itemInHand) { + return !getFlag(EntityFlag.BABY) && itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldIngot() && !getFlag(EntityFlag.ADMIRING); + } } 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 e60f81d2f..ff1ba9ac3 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,7 +39,7 @@ import java.util.UUID; public class ShulkerEntity extends GolemEntity { - public ShulkerEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ShulkerEntity(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); // Indicate that invisibility should be fixed through the resource pack setFlag(EntityFlag.BRIBED, true); @@ -65,4 +65,9 @@ public class ShulkerEntity extends GolemEntity { dirtyMetadata.put(EntityData.VARIANT, Math.abs(color - 15)); } } + + @Override + protected boolean isEnemy() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java index b1f6939aa..b720f1d4e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SkeletonEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class SkeletonEntity extends AbstractSkeletonEntity { private boolean convertingToStray = false; - public SkeletonEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SkeletonEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java index 4f7b02d73..0d9a2b37a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/SpiderEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class SpiderEntity extends MonsterEntity { - public SpiderEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SpiderEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java index 938b18022..545c4bc73 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/VexEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class VexEntity extends MonsterEntity { - public VexEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public VexEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java new file mode 100644 index 000000000..1ca34037c --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WardenEntity.java @@ -0,0 +1,98 @@ +/* + * 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.entity.type.living.monster; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.IntEntityMetadata; +import com.nukkitx.math.GenericMath; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.Tickable; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.MathUtils; + +import java.util.UUID; +import java.util.concurrent.ThreadLocalRandom; + +public class WardenEntity extends MonsterEntity implements Tickable { + private int heartBeatDelay; + private int tickCount; + + private int sonicBoomTickDuration; + + public WardenEntity(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 + public void setPose(Pose pose) { + setFlag(EntityFlag.DIGGING, pose == Pose.DIGGING); + setFlag(EntityFlag.EMERGING, pose == Pose.EMERGING); + setFlag(EntityFlag.ROARING, pose == Pose.ROARING); + setFlag(EntityFlag.SNIFFING, pose == Pose.SNIFFING); + super.setPose(pose); + } + + public void setAngerLevel(IntEntityMetadata entityMetadata) { + float anger = (float) entityMetadata.getPrimitiveValue() / 80f; + heartBeatDelay = 40 - GenericMath.floor(MathUtils.clamp(anger, 0.0F, 1.0F) * 30F); + dirtyMetadata.put(EntityData.HEARTBEAT_INTERVAL_TICKS, heartBeatDelay); + } + + @Override + public void tick() { + if (++tickCount % heartBeatDelay == 0 && !silent) { + // We have to do these calculations because they're clientside on Java Edition but we mute entities + // to prevent hearing their step sounds + ThreadLocalRandom random = ThreadLocalRandom.current(); + + PlaySoundPacket packet = new PlaySoundPacket(); + packet.setSound("mob.warden.heartbeat"); + packet.setPosition(position); + packet.setPitch((random.nextFloat() - random.nextFloat()) * 0.2f + 1.0f); + packet.setVolume(1.0f); + session.sendUpstreamPacket(packet); + } + + if (sonicBoomTickDuration > 0) { + sonicBoomTickDuration--; + if (sonicBoomTickDuration == 0) { + setFlag(EntityFlag.SONIC_BOOM, false); + updateBedrockMetadata(); + } + } + } + + public void onSonicBoom() { + setFlag(EntityFlag.SONIC_BOOM, true); + updateBedrockMetadata(); + + sonicBoomTickDuration = 3 * 20; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java index 17da0a611..d6926996e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/WitherEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,7 +36,7 @@ import java.util.UUID; public class WitherEntity extends MonsterEntity { - public WitherEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public WitherEntity(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); } @@ -60,15 +60,11 @@ public class WitherEntity extends MonsterEntity { private void setTargetId(EntityData entityData, IntEntityMetadata entityMetadata) { int entityId = entityMetadata.getPrimitiveValue(); - Entity entity; - if (session.getPlayerEntity().getEntityId() == entityId) { - entity = session.getPlayerEntity(); - } else { - entity = session.getEntityCache().getEntityByJavaId(entityId); - } - + Entity entity = session.getEntityCache().getEntityByJavaId(entityId); if (entity != null) { dirtyMetadata.put(entityData, entity.getGeyserId()); + } else { + dirtyMetadata.put(entityData, (long) 0); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java index f0fe101da..dd5acbfb1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZoglinEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,13 +36,33 @@ import java.util.UUID; public class ZoglinEntity extends MonsterEntity { - public ZoglinEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ZoglinEntity(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); } public void setBaby(BooleanEntityMetadata entityMetadata) { boolean isBaby = entityMetadata.getPrimitiveValue(); - dirtyMetadata.put(EntityData.SCALE, isBaby? .55f : 1f); - setFlag(EntityFlag.BABY, isBaby); + if (isBaby != getFlag(EntityFlag.BABY)) { + dirtyMetadata.put(EntityData.SCALE, isBaby ? .55f : 1f); + setFlag(EntityFlag.BABY, isBaby); + + updatePassengerOffsets(); + } + } + + @Override + public float getBoundingBoxHeight() { + float scale = getFlag(EntityFlag.BABY) ? 0.55f : 1f; + return scale * definition.height(); + } + + @Override + protected boolean canBeLeashed() { + return isNotLeashed(); + } + + @Override + protected boolean isEnemy() { + return true; } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java index 9e3301b48..0dac50d07 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,7 +37,7 @@ import java.util.UUID; public class ZombieEntity extends MonsterEntity { private boolean convertingToDrowned = false; - public ZombieEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ZombieEntity(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); } @@ -45,6 +45,8 @@ public class ZombieEntity extends MonsterEntity { boolean isBaby = entityMetadata.getPrimitiveValue(); dirtyMetadata.put(EntityData.SCALE, isBaby ? .55f : 1.0f); setFlag(EntityFlag.BABY, isBaby); + + updateMountOffset(); } public void setConvertingToDrowned(BooleanEntityMetadata entityMetadata) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java index 54a5c4506..bf5180e36 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombieVillagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,38 +28,62 @@ 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.VillagerData; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.type.living.merchant.VillagerEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.util.InteractionResult; +import org.geysermc.geyser.util.InteractiveTag; +import javax.annotation.Nonnull; import java.util.UUID; public class ZombieVillagerEntity extends ZombieEntity { - private boolean isTransforming; - public ZombieVillagerEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ZombieVillagerEntity(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); } public void setTransforming(BooleanEntityMetadata entityMetadata) { - isTransforming = entityMetadata.getPrimitiveValue(); - setFlag(EntityFlag.IS_TRANSFORMING, isTransforming); + setFlag(EntityFlag.IS_TRANSFORMING, entityMetadata.getPrimitiveValue()); setFlag(EntityFlag.SHAKING, isShaking()); } public void setZombieVillagerData(EntityMetadata entityMetadata) { VillagerData villagerData = entityMetadata.getValue(); - dirtyMetadata.put(EntityData.VARIANT, VillagerEntity.VILLAGER_PROFESSIONS.get(villagerData.getProfession())); // Actually works properly with the OptionalPack - dirtyMetadata.put(EntityData.MARK_VARIANT, VillagerEntity.VILLAGER_REGIONS.get(villagerData.getType())); + dirtyMetadata.put(EntityData.VARIANT, VillagerEntity.getBedrockProfession(villagerData.getProfession())); // Actually works properly with the OptionalPack + dirtyMetadata.put(EntityData.MARK_VARIANT, VillagerEntity.getBedrockRegion(villagerData.getType())); // Used with the OptionalPack dirtyMetadata.put(EntityData.TRADE_TIER, villagerData.getLevel() - 1); } @Override protected boolean isShaking() { - return isTransforming || super.isShaking(); + return getFlag(EntityFlag.IS_TRANSFORMING) || super.isShaking(); + } + + @Nonnull + @Override + protected InteractiveTag testMobInteraction(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) { + return InteractiveTag.CURE; + } else { + return super.testMobInteraction(hand, itemInHand); + } + } + + @Nonnull + @Override + protected InteractionResult mobInteract(Hand hand, @Nonnull GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().goldenApple()) { + // The client doesn't know if the entity has weakness as that's not usually sent over the network + return InteractionResult.CONSUME; + } else { + return super.mobInteract(hand, itemInHand); + } } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombifiedPiglinEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombifiedPiglinEntity.java index 2604ce12e..a711718d3 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombifiedPiglinEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/ZombifiedPiglinEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class ZombifiedPiglinEntity extends ZombieEntity { - public ZombifiedPiglinEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public ZombifiedPiglinEntity(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); setFlag(EntityFlag.FIRE_IMMUNE, true); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/AbstractIllagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/AbstractIllagerEntity.java index 15ac1a0d9..21395a0ca 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/AbstractIllagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/AbstractIllagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,7 +33,7 @@ import java.util.UUID; public class AbstractIllagerEntity extends RaidParticipantEntity { - public AbstractIllagerEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public AbstractIllagerEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java index 477d9fef7..4359c4254 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/PillagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class PillagerEntity extends AbstractIllagerEntity { - public PillagerEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public PillagerEntity(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); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RaidParticipantEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RaidParticipantEntity.java index bd0f3ac5d..458eabf09 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RaidParticipantEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/RaidParticipantEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,7 +34,7 @@ import java.util.UUID; public class RaidParticipantEntity extends MonsterEntity { - public RaidParticipantEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public RaidParticipantEntity(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); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java index 7c2a05de1..38b8cd9a8 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/SpellcasterIllagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -40,7 +40,7 @@ public class SpellcasterIllagerEntity extends AbstractIllagerEntity { private static final int ATTACK_PARTICLE_COLOR = (102 << 16) | (77 << 8) | 89; private static final int WOLOLO_PARTICLE_COLOR = (179 << 16) | (128 << 8) | 51; - public SpellcasterIllagerEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public SpellcasterIllagerEntity(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); // OptionalPack usage setFlag(EntityFlag.BRIBED, this.definition == EntityDefinitions.ILLUSIONER); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java index a3b85dc73..199cffff9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/raid/VindicatorEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,7 +35,7 @@ import java.util.UUID; public class VindicatorEntity extends AbstractIllagerEntity { - public VindicatorEntity(GeyserSession session, long entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { + public VindicatorEntity(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); } 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 1d59b83db..6f2958ffd 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,10 +25,8 @@ package org.geysermc.geyser.entity.type.player; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.FloatEntityMetadata; @@ -38,6 +36,7 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.AttributeData; +import com.nukkitx.protocol.bedrock.data.GameType; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityData; @@ -61,13 +60,21 @@ import org.geysermc.geyser.translator.text.MessageTranslator; import javax.annotation.Nullable; import java.util.Collections; import java.util.Optional; +import java.util.UUID; import java.util.concurrent.TimeUnit; @Getter @Setter public class PlayerEntity extends LivingEntity { - private GameProfile profile; + public static final float SNEAKING_POSE_HEIGHT = 1.5f; + private String username; - private boolean playerList = true; // Player is in the player list + private boolean playerList = true; // Player is in the player list + + /** + * The textures property from the GameProfile. + */ + @Nullable + private String texturesProperty; private Vector3i bedPosition; @@ -80,11 +87,12 @@ public class PlayerEntity extends LivingEntity { */ private ParrotEntity rightParrot; - public PlayerEntity(GeyserSession session, long entityId, long geyserId, GameProfile gameProfile, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { - super(session, entityId, geyserId, gameProfile.getId(), EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw); + public PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, Vector3f position, + Vector3f motion, float yaw, float pitch, float headYaw, String username, @Nullable String texturesProperty) { + super(session, entityId, geyserId, uuid, EntityDefinitions.PLAYER, position, motion, yaw, pitch, headYaw); - profile = gameProfile; - username = gameProfile.getName(); + this.username = username; + this.texturesProperty = texturesProperty; } @Override @@ -118,19 +126,12 @@ public class PlayerEntity extends LivingEntity { addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER); addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); + addPlayerPacket.setGameType(GameType.SURVIVAL); //TODO addPlayerPacket.getMetadata().putFlags(flags); dirtyMetadata.apply(addPlayerPacket.getMetadata()); setFlagsDirty(false); - long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId); - if (linkedEntityId != -1) { - Entity linkedEntity = session.getEntityCache().getEntityByJavaId(linkedEntityId); - if (linkedEntity != null) { - addPlayerPacket.getEntityLinks().add(new EntityLinkData(linkedEntity.getGeyserId(), geyserId, EntityLinkData.Type.RIDER, false, false)); - } - } - valid = true; session.sendUpstreamPacket(addPlayerPacket); } @@ -167,6 +168,12 @@ public class PlayerEntity extends LivingEntity { } session.sendUpstreamPacket(movePlayerPacket); + + if (teleported) { + // As of 1.19.0, head yaw seems to be ignored during teleports. + updateHeadLookRotation(headYaw); + } + if (leftParrot != null) { leftParrot.moveAbsolute(position, yaw, pitch, headYaw, true, teleported); } @@ -209,45 +216,8 @@ public class PlayerEntity extends LivingEntity { } } - @Override - public void updateHeadLookRotation(float headYaw) { - moveRelative(0, 0, 0, yaw, pitch, headYaw, onGround); - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(geyserId); - movePlayerPacket.setPosition(position); - movePlayerPacket.setRotation(getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.HEAD_ROTATION); - session.sendUpstreamPacket(movePlayerPacket); - } - - @Override - public void updatePositionAndRotation(double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround); - if (leftParrot != null) { - leftParrot.moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround); - } - if (rightParrot != null) { - rightParrot.moveRelative(moveX, moveY, moveZ, yaw, pitch, isOnGround); - } - } - - @Override - public void updateRotation(float yaw, float pitch, boolean isOnGround) { - super.updateRotation(yaw, pitch, isOnGround); - // Both packets need to be sent or else player head rotation isn't correctly updated - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(geyserId); - movePlayerPacket.setPosition(position); - movePlayerPacket.setRotation(getBedrockRotation()); - movePlayerPacket.setOnGround(isOnGround); - movePlayerPacket.setMode(MovePlayerPacket.Mode.HEAD_ROTATION); - session.sendUpstreamPacket(movePlayerPacket); - if (leftParrot != null) { - leftParrot.updateRotation(yaw, pitch, isOnGround); - } - if (rightParrot != null) { - rightParrot.updateRotation(yaw, pitch, isOnGround); - } + public void updateRotation(float yaw, float pitch, float headYaw, boolean isOnGround) { + moveRelative(0, 0, 0, yaw, pitch, headYaw, isOnGround); } @Override @@ -256,7 +226,7 @@ public class PlayerEntity extends LivingEntity { } @Override - public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { + public Vector3i setBedPosition(EntityMetadata, ?> entityMetadata) { return bedPosition = super.setBedPosition(entityMetadata); } @@ -298,7 +268,7 @@ public class PlayerEntity extends LivingEntity { } // The parrot is a separate entity in Bedrock, but part of the player entity in Java //TODO is a UUID provided in NBT? ParrotEntity parrot = new ParrotEntity(session, 0, session.getEntityCache().getNextEntityId().incrementAndGet(), - null, EntityDefinitions.PARROT, position, motion, yaw, pitch, headYaw); + null, EntityDefinitions.PARROT, position, motion, getYaw(), getPitch(), getHeadYaw()); parrot.spawnEntity(); parrot.getDirtyMetadata().put(EntityData.VARIANT, tag.get("Variant").getValue()); // Different position whether the parrot is left or right @@ -388,15 +358,26 @@ public class PlayerEntity extends LivingEntity { @Override protected void setDimensions(Pose pose) { float height; + float width; switch (pose) { - case SNEAKING -> height = 1.5f; - case FALL_FLYING, SPIN_ATTACK, SWIMMING -> height = 0.6f; + case SNEAKING -> { + height = SNEAKING_POSE_HEIGHT; + width = definition.width(); + } + case FALL_FLYING, SPIN_ATTACK, SWIMMING -> { + height = 0.6f; + width = definition.width(); + } + case DYING -> { + height = 0.2f; + width = 0.2f; + } default -> { super.setDimensions(pose); return; } } - setBoundingBoxWidth(definition.width()); + setBoundingBoxWidth(width); setBoundingBoxHeight(height); } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java index dff9fbfa2..d4b703c40 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SessionPlayerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,10 +25,9 @@ package org.geysermc.geyser.entity.type.player; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute; import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeType; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.GlobalPos; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; import com.github.steveice10.mc.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import com.nukkitx.math.vector.Vector3f; @@ -39,13 +38,13 @@ import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import lombok.Getter; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.AttributeUtils; +import org.geysermc.geyser.util.DimensionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import javax.annotation.Nullable; +import java.util.*; /** * The entity class specifically for a {@link GeyserSession}'s player. @@ -70,13 +69,15 @@ public class SessionPlayerEntity extends PlayerEntity { */ private int fakeTradeXp; - private final GeyserSession session; - public SessionPlayerEntity(GeyserSession session) { - super(session, 1, 1, new GameProfile(UUID.randomUUID(), "unknown"), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0); + super(session, -1, 1, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, "unknown", null); valid = true; - this.session = session; + } + + @Override + protected void setClientSideSilent() { + // Do nothing, since we want the session player to hear their own footstep sounds for example. } @Override @@ -92,7 +93,7 @@ public class SessionPlayerEntity extends PlayerEntity { @Override public void setPosition(Vector3f position) { - if (session != null) { // null during entity initialization + if (valid) { // Don't update during session init session.getCollisionManager().updatePlayerBoundingBox(position); } super.setPosition(position); @@ -117,9 +118,20 @@ public class SessionPlayerEntity extends PlayerEntity { } @Override - public void setPose(EntityMetadata entityMetadata) { - super.setPose(entityMetadata); - session.setPose(entityMetadata.getValue()); + public boolean setBoundingBoxHeight(float height) { + if (super.setBoundingBoxHeight(height)) { + if (valid) { // Don't update during session init + session.getCollisionManager().updatePlayerBoundingBox(); + } + return true; + } + return false; + } + + @Override + public void setPose(Pose pose) { + super.setPose(pose); + session.setPose(pose); refreshSpeed = true; } @@ -127,6 +139,10 @@ public class SessionPlayerEntity extends PlayerEntity { return maxHealth; } + public float getHealth() { + return this.health; + } + public void setHealth(float health) { this.health = health; } @@ -160,6 +176,16 @@ public class SessionPlayerEntity extends PlayerEntity { return super.createHealthAttribute(); } + @Override + protected boolean hasShield(boolean offhand, ItemMapping shieldMapping) { + // Must be overridden to point to the player's inventory cache + if (offhand) { + return session.getPlayerInventory().getOffhand().getJavaId() == shieldMapping.getJavaId(); + } else { + return session.getPlayerInventory().getItemInHand().getJavaId() == shieldMapping.getJavaId(); + } + } + @Override public void updateBedrockMetadata() { super.updateBedrockMetadata(); @@ -201,4 +227,14 @@ public class SessionPlayerEntity extends PlayerEntity { this.attributes.put(type, attributeData); return attributeData; } + + public void setLastDeathPosition(@Nullable GlobalPos pos) { + if (pos != null) { + dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_POS, pos.getPosition()); + dirtyMetadata.put(EntityData.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension())); + dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 1); + } else { + dirtyMetadata.put(EntityData.PLAYER_HAS_DIED, (byte) 0); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java index 0afb3e8b5..6c15a4d3e 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/SkullPlayerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,32 +25,29 @@ package org.geysermc.geyser.entity.type.player; -import com.github.steveice10.mc.auth.data.GameProfile; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.data.GameType; import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket; -import lombok.Getter; +import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.cache.SkullCache; +import org.geysermc.geyser.skin.SkullSkinManager; + +import java.util.UUID; +import java.util.concurrent.TimeUnit; /** * A wrapper to handle skulls more effectively - skulls have to be treated as entities since there are no * custom player skulls in Bedrock. */ public class SkullPlayerEntity extends PlayerEntity { - /** - * Stores the block state that the skull is associated with. Used to determine if the block in the skull's position - * has changed - */ - @Getter - private final int blockState; - public SkullPlayerEntity(GeyserSession session, long geyserId, GameProfile gameProfile, Vector3f position, float rotation, int blockState) { - super(session, 0, geyserId, gameProfile, position, Vector3f.ZERO, rotation, 0, rotation); - this.blockState = blockState; + public SkullPlayerEntity(GeyserSession session, long geyserId) { + super(session, 0, geyserId, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, "", null); setPlayerList(false); } @@ -83,6 +80,7 @@ public class SkullPlayerEntity extends PlayerEntity { addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER); addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); + addPlayerPacket.setGameType(GameType.SURVIVAL); addPlayerPacket.getMetadata().putFlags(flags); dirtyMetadata.apply(addPlayerPacket.getMetadata()); @@ -92,8 +90,57 @@ public class SkullPlayerEntity extends PlayerEntity { session.sendUpstreamPacket(addPlayerPacket); } - public void despawnEntity(Vector3i position) { - this.despawnEntity(); - session.getSkullCache().remove(position, this); + /** + * Hide the player entity so that it can be reused for a different skull. + */ + public void free() { + setFlag(EntityFlag.INVISIBLE, true); + updateBedrockMetadata(); + + // Move skull entity out of the way + moveAbsolute(session.getPlayerEntity().getPosition().up(128), 0, 0, 0, false, true); + } + + public void updateSkull(SkullCache.Skull skull) { + if (!skull.getTexturesProperty().equals(getTexturesProperty())) { + // Make skull invisible as we change skins + setFlag(EntityFlag.INVISIBLE, true); + updateBedrockMetadata(); + + setTexturesProperty(skull.getTexturesProperty()); + + SkullSkinManager.requestAndHandleSkin(this, session, (skin -> session.scheduleInEventLoop(() -> { + // Delay to minimize split-second "player" pop-in + setFlag(EntityFlag.INVISIBLE, false); + updateBedrockMetadata(); + }, 250, TimeUnit.MILLISECONDS))); + } else { + // Just a rotation/position change + setFlag(EntityFlag.INVISIBLE, false); + updateBedrockMetadata(); + } + + float x = skull.getPosition().getX() + .5f; + float y = skull.getPosition().getY() - .01f; + float z = skull.getPosition().getZ() + .5f; + float rotation; + + int blockState = skull.getBlockState(); + byte floorRotation = BlockStateValues.getSkullRotation(blockState); + if (floorRotation == -1) { + // Wall skull + y += 0.25f; + rotation = BlockStateValues.getSkullWallDirections().get(blockState); + switch ((int) rotation) { + case 180 -> z += 0.24f; // North + case 0 -> z -= 0.24f; // South + case 90 -> x += 0.24f; // West + case 270 -> x -= 0.24f; // East + } + } else { + rotation = (180f + (floorRotation * 22.5f)) % 360; + } + + moveAbsolute(Vector3f.from(x, y, z), rotation, 0, rotation, true, true); } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java index 343cff4ef..688151a9e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/AnvilContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,8 +26,14 @@ package org.geysermc.geyser.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import lombok.Getter; import lombok.Setter; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.ItemUtils; + +import javax.annotation.Nullable; /** * Used to determine if rename packets should be sent and stores @@ -48,6 +54,7 @@ public class AnvilContainer extends Container { /** * The new name of the item as received from Bedrock */ + @Nullable private String newName = null; private GeyserItemStack lastInput = GeyserItemStack.EMPTY; @@ -59,6 +66,36 @@ public class AnvilContainer extends Container { super(title, id, size, containerType, playerInventory); } + /** + * @return the name to use instead for renaming. + */ + public String checkForRename(GeyserSession session, String rename) { + String correctRename; + newName = rename; + + String originalName = ItemUtils.getCustomName(getInput().getNbt()); + + String plainOriginalName = MessageTranslator.convertToPlainText(originalName, session.getLocale()); + String plainNewName = MessageTranslator.convertToPlainText(rename, session.getLocale()); + if (!plainOriginalName.equals(plainNewName)) { + // Strip out formatting since Java Edition does not allow it + correctRename = plainNewName; + // Java Edition sends a packet every time an item is renamed even slightly in GUI. Fortunately, this works out for us now + ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainNewName); + session.sendDownstreamPacket(renameItemPacket); + } else { + // Restore formatting for item since we're not renaming + correctRename = MessageTranslator.convertMessageLenient(originalName); + // Java Edition sends the original custom name when not renaming, + // if there isn't a custom name an empty string is sent + ServerboundRenameItemPacket renameItemPacket = new ServerboundRenameItemPacket(plainOriginalName); + session.sendDownstreamPacket(renameItemPacket); + } + + useJavaLevelCost = false; + return correctRename; + } + public GeyserItemStack getInput() { return getItem(0); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java index 5e9282d7f..7644ada73 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/BeaconContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/BedrockContainerSlot.java b/core/src/main/java/org/geysermc/geyser/inventory/BedrockContainerSlot.java index 0179bb277..87c0c92a3 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/BedrockContainerSlot.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/BedrockContainerSlot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,10 +26,6 @@ package org.geysermc.geyser.inventory; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; -import lombok.Value; -@Value -public class BedrockContainerSlot { - ContainerSlotType container; - int slot; +public record BedrockContainerSlot(ContainerSlotType container, int slot) { } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java index de7a861d5..72f1088c3 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/CartographyContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Container.java index 464d683fa..569802a5a 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Container.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,9 +27,11 @@ package org.geysermc.geyser.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import lombok.Getter; -import lombok.NonNull; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; +import org.jetbrains.annotations.Range; + +import javax.annotation.Nonnull; /** * Combination of {@link Inventory} and {@link PlayerInventory} @@ -60,7 +62,12 @@ public class Container extends Inventory { } @Override - public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { + public int getOffsetForHotbar(@Range(from = 0, to = 8) int slot) { + return playerInventory.getOffsetForHotbar(slot) - InventoryTranslator.PLAYER_INVENTORY_OFFSET + this.size; + } + + @Override + public void setItem(int slot, @Nonnull GeyserItemStack newItem, GeyserSession session) { if (slot < this.size) { super.setItem(slot, newItem, session); } else { diff --git a/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java index b16a3a07c..43aec6f08 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/EnchantingContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java index fc226f621..94012a830 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Generic3X3Container.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java index 8ecb3fe8d..94462268e 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserEnchantOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -46,7 +46,7 @@ public class GeyserEnchantOption { */ private static final List ENCHANT_NAMES = Arrays.asList("tougher armor", "lukeeey", "fall better", "explode less", "camo toy", "breathe better", "rtm five one six", "armor stab", "water walk", "you are elsa", - "tim two zero three", "fast walk nether", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned", + "tim two zero three", "fast walk nether", "davchoo", "oof ouch owie", "enemy on fire", "spider sad", "aj ferguson", "redned", "more items thx", "long sword reach", "fast tool", "give me block", "less breaky break", "cube craft", "strong arrow", "fist arrow", "spicy arrow", "many many arrows", "geyser", "come here fish", "i like this", "stabby stab", "supreme mortal", "avatar i guess", "more arrows", "fly finder seventeen", "in and out", diff --git a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java index a75631db0..e249f0167 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 6eaaf84a2..ca7e90a25 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/Inventory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,25 +31,35 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.math.vector.Vector3i; import lombok.Getter; -import lombok.NonNull; import lombok.Setter; +import lombok.ToString; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.jetbrains.annotations.Range; +import javax.annotation.Nonnull; import java.util.Arrays; -public class Inventory { - +@ToString +public abstract class Inventory { @Getter protected final int id; /** - * If this is out of sync with the server, the server will resync items. - * Since Java Edition 1.17.1. + * The Java inventory state ID from the server. As of Java Edition 1.18.1 this value has one instance per player. + * If this is out of sync with the server when a packet containing it is handled, the server will resync items. + * This field has existed since Java Edition 1.17.1. */ @Getter @Setter private int stateId; + /** + * See {@link org.geysermc.geyser.inventory.click.ClickPlan#execute(boolean)}; used as a hack + */ + @Getter + private int nextStateId = -1; @Getter protected final int size; @@ -61,8 +71,7 @@ public class Inventory { protected final ContainerType containerType; @Getter - @Setter - protected String title; + protected final String title; protected final GeyserItemStack[] items; @@ -102,7 +111,9 @@ public class Inventory { return items[slot]; } - public void setItem(int slot, @NonNull GeyserItemStack newItem, GeyserSession session) { + public abstract int getOffsetForHotbar(@Range(from = 0, to = 8) int slot); + + public void setItem(int slot, @Nonnull GeyserItemStack newItem, GeyserSession session) { if (slot > this.size) { session.getGeyser().getLogger().debug("Tried to set an item out of bounds! " + this); return; @@ -123,9 +134,11 @@ public class Inventory { } } - protected static void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) { + protected void updateItemNetId(GeyserItemStack oldItem, GeyserItemStack newItem, GeyserSession session) { if (!newItem.isEmpty()) { - if (newItem.getItemData(session).equals(oldItem.getItemData(session), false, false, false)) { + ItemMapping oldMapping = ItemTranslator.getBedrockItemMapping(session, oldItem); + ItemMapping newMapping = ItemTranslator.getBedrockItemMapping(session, newItem); + if (oldMapping.getBedrockId() == newMapping.getBedrockId()) { newItem.setNetId(oldItem.getNetId()); } else { newItem.setNetId(session.getNextItemNetId()); @@ -133,15 +146,15 @@ public class Inventory { } } - @Override - public String toString() { - return "Inventory{" + - "id=" + id + - ", size=" + size + - ", title='" + title + '\'' + - ", items=" + Arrays.toString(items) + - ", holderPosition=" + holderPosition + - ", holderId=" + holderId + - '}'; + /** + * See {@link org.geysermc.geyser.inventory.click.ClickPlan#execute(boolean)} for more details. + */ + public void incrementStateId(int count) { + // nextStateId == -1 means that it was not needed until now + nextStateId = (nextStateId == -1 ? stateId : nextStateId) + count & Short.MAX_VALUE; + } + + public void resetNextStateId() { + nextStateId = -1; } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java index 74d853ab6..5d8c9f110 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/LecternContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java index fecb79580..315e6cb18 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/MerchantContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,15 +31,27 @@ import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.Cli import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.session.GeyserSession; -@Getter -@Setter public class MerchantContainer extends Container { + @Getter @Setter private Entity villager; + @Setter private VillagerTrade[] villagerTrades; + @Getter @Setter private ClientboundMerchantOffersPacket pendingOffersPacket; public MerchantContainer(String title, int id, int size, ContainerType containerType, PlayerInventory playerInventory) { super(title, id, size, containerType, playerInventory); } + + public void onTradeSelected(GeyserSession session, int slot) { + if (villagerTrades != null && slot >= 0 && slot < villagerTrades.length) { + VillagerTrade trade = villagerTrades[slot]; + setItem(2, GeyserItemStack.from(trade.getOutput()), session); + // TODO this logic doesn't add up + session.getPlayerEntity().addFakeTradeExperience(trade.getXp()); + session.getPlayerEntity().updateBedrockMetadata(); + } + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java index 36114ccba..7b1064c8f 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/PlayerInventory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,14 +25,16 @@ package org.geysermc.geyser.inventory; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import lombok.Getter; -import lombok.NonNull; import lombok.Setter; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; +import org.jetbrains.annotations.Range; + +import javax.annotation.Nonnull; public class PlayerInventory extends Inventory { - /** * Stores the held item slot, starting at index 0. * Add 36 in order to get the network item slot. @@ -42,7 +44,7 @@ public class PlayerInventory extends Inventory { private int heldItemSlot; @Getter - @NonNull + @Nonnull private GeyserItemStack cursor = GeyserItemStack.EMPTY; public PlayerInventory() { @@ -50,11 +52,20 @@ public class PlayerInventory extends Inventory { heldItemSlot = 0; } - public void setCursor(@NonNull GeyserItemStack newCursor, GeyserSession session) { + @Override + public int getOffsetForHotbar(@Range(from = 0, to = 8) int slot) { + return slot + 36; + } + + public void setCursor(@Nonnull GeyserItemStack newCursor, GeyserSession session) { updateItemNetId(cursor, newCursor, session); cursor = newCursor; } + public GeyserItemStack getItemInHand(@Nonnull Hand hand) { + return hand == Hand.OFF_HAND ? getOffhand() : getItemInHand(); + } + public GeyserItemStack getItemInHand() { if (36 + heldItemSlot > this.size) { GeyserImpl.getInstance().getLogger().debug("Held item slot was larger than expected!"); @@ -63,7 +74,7 @@ public class PlayerInventory extends Inventory { return items[36 + heldItemSlot]; } - public void setItemInHand(@NonNull GeyserItemStack item) { + public void setItemInHand(@Nonnull GeyserItemStack item) { if (36 + heldItemSlot > this.size) { GeyserImpl.getInstance().getLogger().debug("Held item slot was larger than expected!"); return; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/SlotType.java b/core/src/main/java/org/geysermc/geyser/inventory/SlotType.java index 17863ba66..a4e20ce75 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/SlotType.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/SlotType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java index 3dc35f5df..6e04e6741 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/StonecutterContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java index 187a98842..027c7a7ce 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/Click.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,7 +38,16 @@ public enum Click { DROP_ONE(ContainerActionType.DROP_ITEM, DropItemAction.DROP_FROM_SELECTED), DROP_ALL(ContainerActionType.DROP_ITEM, DropItemAction.DROP_SELECTED_STACK), LEFT_OUTSIDE(ContainerActionType.CLICK_ITEM, ClickItemAction.LEFT_CLICK), - RIGHT_OUTSIDE(ContainerActionType.CLICK_ITEM, ClickItemAction.RIGHT_CLICK); + RIGHT_OUTSIDE(ContainerActionType.CLICK_ITEM, ClickItemAction.RIGHT_CLICK), + SWAP_TO_HOTBAR_1(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_1), + SWAP_TO_HOTBAR_2(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_2), + SWAP_TO_HOTBAR_3(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_3), + SWAP_TO_HOTBAR_4(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_4), + SWAP_TO_HOTBAR_5(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_5), + SWAP_TO_HOTBAR_6(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_6), + SWAP_TO_HOTBAR_7(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_7), + SWAP_TO_HOTBAR_8(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_8), + SWAP_TO_HOTBAR_9(ContainerActionType.MOVE_TO_HOTBAR_SLOT, MoveToHotbarAction.SLOT_9); public static final int OUTSIDE_SLOT = -999; diff --git a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java index c239cc778..ec36645da 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/click/ClickPlan.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,30 +27,35 @@ package org.geysermc.geyser.inventory.click; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerActionType; +import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.data.game.inventory.MoveToHotbarAction; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import lombok.Value; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.CraftingInventoryTranslator; -import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator; +import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.util.InventoryUtils; +import org.jetbrains.annotations.Contract; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; -public class ClickPlan { +public final class ClickPlan { private final List plan = new ArrayList<>(); private final Int2ObjectMap simulatedItems; + /** + * Used for 1.17.1+ proper packet translation - any non-cursor item that is changed in a single transaction gets sent here. + */ + private Int2ObjectMap changedItems; private GeyserItemStack simulatedCursor; - private boolean simulating; + private boolean finished; private final GeyserSession session; private final InventoryTranslator translator; @@ -63,16 +68,11 @@ public class ClickPlan { this.inventory = inventory; this.simulatedItems = new Int2ObjectOpenHashMap<>(inventory.getSize()); + this.changedItems = null; this.simulatedCursor = session.getPlayerInventory().getCursor().copy(); - this.simulating = true; + this.finished = false; - if (translator instanceof PlayerInventoryTranslator) { - gridSize = 4; - } else if (translator instanceof CraftingInventoryTranslator) { - gridSize = 9; - } else { - gridSize = -1; - } + gridSize = translator.getGridSize(); } private void resetSimulation() { @@ -85,7 +85,7 @@ public class ClickPlan { } public void add(Click click, int slot, boolean force) { - if (!simulating) + if (finished) throw new UnsupportedOperationException("ClickPlan already executed"); if (click == Click.LEFT_OUTSIDE || click == Click.RIGHT_OUTSIDE) { @@ -94,6 +94,8 @@ public class ClickPlan { ClickAction action = new ClickAction(click, slot, force); plan.add(action); + // RUNNING THE SIMULATION HERE IS IMPORTANT. The contents of the simulation are used in complex, multi-stage tasks + // such as autocrafting. simulateAction(action); } @@ -105,35 +107,52 @@ public class ClickPlan { ClickAction action = planIter.next(); if (action.slot != Click.OUTSIDE_SLOT && translator.getSlotType(action.slot) != SlotType.NORMAL) { + // Needed with Paper 1.16.5 refresh = true; } + changedItems = new Int2ObjectOpenHashMap<>(); + + boolean emulatePost1_16Logic = session.isEmulatePost1_16Logic(); + + int stateId; + if (emulatePost1_16Logic) { + stateId = stateIdHack(action); + simulateAction(action); + } else { + stateId = inventory.getStateId(); + } + ItemStack clickedItemStack; if (!planIter.hasNext() && refresh) { clickedItemStack = InventoryUtils.REFRESH_ITEM; - } else if (action.click.actionType == ContainerActionType.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) { - clickedItemStack = null; } else { - clickedItemStack = getItem(action.slot).getItemStack(); + if (emulatePost1_16Logic) { + // The action must be simulated first as Java expects the new contents of the cursor (as of 1.18.1) + clickedItemStack = simulatedCursor.getItemStack(); + } else { + if (action.click.actionType == ContainerActionType.DROP_ITEM || action.slot == Click.OUTSIDE_SLOT) { + clickedItemStack = null; + } else { + clickedItemStack = getItem(action.slot).getItemStack(); + } + } } - Int2ObjectMap affectedSlots = new Int2ObjectOpenHashMap<>(); - for (Int2ObjectMap.Entry simulatedSlot : simulatedItems.int2ObjectEntrySet()) { - affectedSlots.put(simulatedSlot.getIntKey(), simulatedSlot.getValue().getItemStack()); + if (!emulatePost1_16Logic) { + simulateAction(action); } ServerboundContainerClickPacket clickPacket = new ServerboundContainerClickPacket( inventory.getId(), - inventory.getStateId(), + stateId, action.slot, action.click.actionType, action.click.action, clickedItemStack, - affectedSlots + changedItems ); - simulateAction(action); - session.sendDownstreamPacket(clickPacket); } @@ -141,19 +160,11 @@ public class ClickPlan { for (Int2ObjectMap.Entry simulatedSlot : simulatedItems.int2ObjectEntrySet()) { inventory.setItem(simulatedSlot.getIntKey(), simulatedSlot.getValue(), session); } - simulating = false; + finished = true; } public GeyserItemStack getItem(int slot) { - return getItem(slot, true); - } - - public GeyserItemStack getItem(int slot, boolean generate) { - if (generate) { - return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); - } else { - return simulatedItems.getOrDefault(slot, inventory.getItem(slot)); - } + return simulatedItems.computeIfAbsent(slot, k -> inventory.getItem(slot).copy()); } public GeyserItemStack getCursor() { @@ -161,23 +172,40 @@ public class ClickPlan { } private void setItem(int slot, GeyserItemStack item) { - if (simulating) { - simulatedItems.put(slot, item); - } else { - inventory.setItem(slot, item, session); - } + simulatedItems.put(slot, item); + onSlotItemChange(slot, item); } private void setCursor(GeyserItemStack item) { - if (simulating) { - simulatedCursor = item; - } else { - session.getPlayerInventory().setCursor(item, session); + simulatedCursor = item; + } + + private void add(int slot, GeyserItemStack itemStack, int amount) { + itemStack.add(amount); + onSlotItemChange(slot, itemStack); + } + + private void sub(int slot, GeyserItemStack itemStack, int amount) { + itemStack.sub(amount); + onSlotItemChange(slot, itemStack); + } + + private void setAmount(int slot, GeyserItemStack itemStack, int amount) { + itemStack.setAmount(amount); + onSlotItemChange(slot, itemStack); + } + + /** + * Does not need to be called for the cursor + */ + private void onSlotItemChange(int slot, GeyserItemStack itemStack) { + if (changedItems != null) { + changedItems.put(slot, itemStack.getItemStack()); } } private void simulateAction(ClickAction action) { - GeyserItemStack cursor = simulating ? getCursor() : session.getPlayerInventory().getCursor(); + GeyserItemStack cursor = getCursor(); switch (action.click) { case LEFT_OUTSIDE -> { setCursor(GeyserItemStack.EMPTY); @@ -191,7 +219,7 @@ public class ClickPlan { } } - GeyserItemStack clicked = simulating ? getItem(action.slot) : inventory.getItem(action.slot); + GeyserItemStack clicked = getItem(action.slot); if (translator.getSlotType(action.slot) == SlotType.OUTPUT) { switch (action.click) { case LEFT, RIGHT -> { @@ -201,6 +229,7 @@ public class ClickPlan { cursor.add(clicked.getAmount()); } reduceCraftingGrid(false); + setItem(action.slot, GeyserItemStack.EMPTY); // Matches Java Edition 1.18.1 } case LEFT_SHIFT -> reduceCraftingGrid(true); } @@ -212,28 +241,55 @@ public class ClickPlan { setItem(action.slot, cursor); } else { setCursor(GeyserItemStack.EMPTY); - clicked.add(cursor.getAmount()); + add(action.slot, clicked, cursor.getAmount()); } break; case RIGHT: if (cursor.isEmpty() && !clicked.isEmpty()) { int half = clicked.getAmount() / 2; //smaller half setCursor(clicked.copy(clicked.getAmount() - half)); //larger half - clicked.setAmount(half); + setAmount(action.slot, clicked, half); } else if (!cursor.isEmpty() && clicked.isEmpty()) { cursor.sub(1); setItem(action.slot, cursor.copy(1)); } else if (InventoryUtils.canStack(cursor, clicked)) { cursor.sub(1); - clicked.add(1); + add(action.slot, clicked, 1); } break; + case SWAP_TO_HOTBAR_1: + swap(action.slot, inventory.getOffsetForHotbar(0), clicked); + break; + case SWAP_TO_HOTBAR_2: + swap(action.slot, inventory.getOffsetForHotbar(1), clicked); + break; + case SWAP_TO_HOTBAR_3: + swap(action.slot, inventory.getOffsetForHotbar(2), clicked); + break; + case SWAP_TO_HOTBAR_4: + swap(action.slot, inventory.getOffsetForHotbar(3), clicked); + break; + case SWAP_TO_HOTBAR_5: + swap(action.slot, inventory.getOffsetForHotbar(4), clicked); + break; + case SWAP_TO_HOTBAR_6: + swap(action.slot, inventory.getOffsetForHotbar(5), clicked); + break; + case SWAP_TO_HOTBAR_7: + swap(action.slot, inventory.getOffsetForHotbar(6), clicked); + break; + case SWAP_TO_HOTBAR_8: + swap(action.slot, inventory.getOffsetForHotbar(7), clicked); + break; + case SWAP_TO_HOTBAR_9: + swap(action.slot, inventory.getOffsetForHotbar(8), clicked); + break; case LEFT_SHIFT: //TODO break; case DROP_ONE: if (!clicked.isEmpty()) { - clicked.sub(1); + sub(action.slot, clicked, 1); } break; case DROP_ALL: @@ -243,7 +299,61 @@ public class ClickPlan { } } - //TODO + /** + * Swap between two inventory slots without a cursor. This should only be used with {@link ContainerActionType#MOVE_TO_HOTBAR_SLOT} + */ + private void swap(int sourceSlot, int destSlot, GeyserItemStack sourceItem) { + GeyserItemStack destinationItem = getItem(destSlot); + setItem(sourceSlot, destinationItem); + setItem(destSlot, sourceItem); + } + + private int stateIdHack(ClickAction action) { + int stateId; + if (inventory.getNextStateId() != -1) { + stateId = inventory.getNextStateId(); + } else { + stateId = inventory.getStateId(); + } + + // Java will never ever send more than one container click packet per set of actions*. + // *(exception being Java's "quick craft"/painting feature) + // Bedrock might, and this would generally fall into one of two categories: + // - Bedrock is sending an item directly from one slot to another, without picking it up, that cannot + // be expressed with a shift click + // - Bedrock wants to pick up or place an arbitrary amount of items that cannot be expressed from + // one left/right click action. + // Java typically doesn't increment the state ID if you send a vanilla-accurate container click packet, + // but it will increment the state ID with a vanilla client in at least the crafting table + if (inventory.getContainerType() == ContainerType.CRAFTING && CraftingInventoryTranslator.isCraftingGrid(action.slot)) { + // 1.18.1 sends a second set slot update for any action in the crafting grid + // And an additional packet if something is removed (Mojmap: CraftingContainer#removeItem) + int stateIdIncrements; + GeyserItemStack clicked = getItem(action.slot); + if (action.click == Click.LEFT) { + if (!clicked.isEmpty() && !InventoryUtils.canStack(simulatedCursor, clicked)) { + // An item is removed from the crafting table; yes deletion + stateIdIncrements = 2; + } else { + // We can stack and we add all the items to the crafting slot; no deletion + stateIdIncrements = 1; + } + } else if (action.click == Click.RIGHT) { + stateIdIncrements = 1; + } else if (action.click.actionType == ContainerActionType.MOVE_TO_HOTBAR_SLOT) { + stateIdIncrements = 1; + } else { + if (session.getGeyser().getConfig().isDebugMode()) { + session.getGeyser().getLogger().debug("Not sure how to handle state ID hack in crafting table: " + plan); + } + stateIdIncrements = 1; + } + inventory.incrementStateId(stateIdIncrements); + } + + return stateId; + } + private void reduceCraftingGrid(boolean makeAll) { if (gridSize == -1) return; @@ -265,32 +375,33 @@ public class ClickPlan { } for (int i = 0; i < gridSize; i++) { - GeyserItemStack item = getItem(i + 1); - if (!item.isEmpty()) - item.sub(crafted); + final int slot = i + 1; + GeyserItemStack item = getItem(slot); + if (!item.isEmpty()) { + // These changes should be broadcasted to the server + sub(slot, item, crafted); + } } } /** - * @return a new set of all affected slots. This isn't a constant variable; it's newly generated each time it is run. + * @return a new set of all affected slots. */ + @Contract("-> new") public IntSet getAffectedSlots() { IntSet affectedSlots = new IntOpenHashSet(); for (ClickAction action : plan) { - if (translator.getSlotType(action.slot) == SlotType.NORMAL && action.slot != Click.OUTSIDE_SLOT) { + if (translator.getSlotType(action.slot) != SlotType.OUTPUT && action.slot != Click.OUTSIDE_SLOT) { affectedSlots.add(action.slot); + if (action.click.actionType == ContainerActionType.MOVE_TO_HOTBAR_SLOT) { + //TODO won't work if offhand is added + affectedSlots.add(inventory.getOffsetForHotbar(((MoveToHotbarAction) action.click.action).ordinal())); + } } } return affectedSlots; } - @Value - private static class ClickAction { - Click click; - /** - * Java slot - */ - int slot; - boolean force; + private record ClickAction(Click click, int slot, boolean force) { } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java index 8dba5a69d..fd26cc170 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/BlockInventoryHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.inventory.holder; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.google.common.collect.ImmutableSet; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; @@ -36,9 +35,9 @@ import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.InventoryTranslator; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.util.BlockUtils; import java.util.Collections; @@ -154,8 +153,7 @@ public class BlockInventoryHolder extends InventoryHolder { } Vector3i holderPos = inventory.getHolderPosition(); - Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); + int realBlock = session.getGeyser().getWorldManager().getBlockAt(session, holderPos.getX(), holderPos.getY(), holderPos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); diff --git a/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java b/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java index 845e645e3..fe54e1dc0 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/holder/InventoryHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java b/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java index 4abc7525e..bcbfe3e17 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/Enchantment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -67,7 +67,8 @@ public enum Enchantment { MULTISHOT, PIERCING, QUICK_CHARGE, - SOUL_SPEED; + SOUL_SPEED, + SWIFT_SNEAK; private static final Enchantment[] VALUES = values(); @@ -109,6 +110,7 @@ public enum Enchantment { FROST_WALKER, BINDING_CURSE, SOUL_SPEED, + SWIFT_SNEAK, SHARPNESS, SMITE, BANE_OF_ARTHROPODS, diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java index 1efb77ab0..8d2b52aa2 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/Potion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java index 940436106..56b6ee7ac 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/StoredItemMappings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -41,16 +41,27 @@ public class StoredItemMappings { private final ItemMapping bamboo; private final ItemMapping banner; private final ItemMapping barrier; + private final int bowl; + private final int chest; private final ItemMapping compass; private final ItemMapping crossbow; private final ItemMapping enchantedBook; private final ItemMapping fishingRod; - private final ItemMapping lodestoneCompass; + private final int flintAndSteel; + private final int goldenApple; + private final int goldIngot; + private final int ironIngot; + private final int lead; private final ItemMapping milkBucket; + private final int nameTag; private final ItemMapping powderSnowBucket; private final ItemMapping playerHead; private final ItemMapping egg; + private final int saddle; + private final int shears; private final ItemMapping shield; + private final int slimeBall; + private final int waterBucket; private final ItemMapping wheat; private final ItemMapping writableBook; @@ -58,16 +69,27 @@ public class StoredItemMappings { this.bamboo = load(itemMappings, "bamboo"); this.banner = load(itemMappings, "white_banner"); // As of 1.17.10, all banners have the same Bedrock ID this.barrier = load(itemMappings, "barrier"); + this.bowl = load(itemMappings, "bowl").getJavaId(); + this.chest = load(itemMappings, "chest").getJavaId(); this.compass = load(itemMappings, "compass"); this.crossbow = load(itemMappings, "crossbow"); this.enchantedBook = load(itemMappings, "enchanted_book"); this.fishingRod = load(itemMappings, "fishing_rod"); - this.lodestoneCompass = load(itemMappings, "lodestone_compass"); + this.flintAndSteel = load(itemMappings, "flint_and_steel").getJavaId(); + this.goldenApple = load(itemMappings, "golden_apple").getJavaId(); + this.goldIngot = load(itemMappings, "gold_ingot").getJavaId(); + this.ironIngot = load(itemMappings, "iron_ingot").getJavaId(); + this.lead = load(itemMappings, "lead").getJavaId(); this.milkBucket = load(itemMappings, "milk_bucket"); + this.nameTag = load(itemMappings, "name_tag").getJavaId(); this.powderSnowBucket = load(itemMappings, "powder_snow_bucket"); this.playerHead = load(itemMappings, "player_head"); this.egg = load(itemMappings, "egg"); + this.saddle = load(itemMappings, "saddle").getJavaId(); + this.shears = load(itemMappings, "shears").getJavaId(); this.shield = load(itemMappings, "shield"); + this.slimeBall = load(itemMappings, "slime_ball").getJavaId(); + this.waterBucket = load(itemMappings, "water_bucket").getJavaId(); this.wheat = load(itemMappings, "wheat"); this.writableBook = load(itemMappings, "writable_book"); } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java index 91d0f526f..ddc44fbc4 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/item/TippedArrowPotion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/entity/factory/PaintingEntityFactory.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java similarity index 67% rename from core/src/main/java/org/geysermc/geyser/entity/factory/PaintingEntityFactory.java rename to core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java index 2990b0ac5..641d5ad94 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/factory/PaintingEntityFactory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserRecipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,16 +23,14 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity.factory; +package org.geysermc.geyser.inventory.recipe; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.PaintingEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.level.PaintingType; - -import java.util.UUID; - -public interface PaintingEntityFactory extends EntityFactory { - - PaintingEntity create(GeyserSession session, long entityId, long geyserId, UUID uuid, Vector3f position, PaintingType paintingName, int direction); +/** + * A more compact version of {@link com.github.steveice10.mc.protocol.data.game.recipe.Recipe}. + */ +public interface GeyserRecipe { + /** + * Whether the recipe is flexible or not in which items can be placed where. + */ + boolean isShaped(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/NoteblockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java similarity index 54% rename from core/src/main/java/org/geysermc/geyser/translator/level/block/entity/NoteblockBlockEntityTranslator.java rename to core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java index 1d61d0e30..a011fef6d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/NoteblockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapedRecipe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,26 +23,21 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.level.block.entity; +package org.geysermc.geyser.inventory.recipe; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.protocol.bedrock.packet.BlockEventPacket; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.level.block.BlockStateValues; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; +import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; -/** - * Does not implement BlockEntityTranslator because it's only a block entity in Bedrock - */ -public class NoteblockBlockEntityTranslator { +public record GeyserShapedRecipe(int width, int height, Ingredient[] ingredients, ItemStack result) implements GeyserRecipe { - public static void translate(GeyserSession session, Position position) { - int blockState = session.getGeyser().getWorldManager().getBlockAt(session, position); - BlockEventPacket blockEventPacket = new BlockEventPacket(); - blockEventPacket.setBlockPosition(Vector3i.from(position.getX(), position.getY(), position.getZ())); - blockEventPacket.setEventType(0); - blockEventPacket.setEventData(BlockStateValues.getNoteblockPitch(blockState)); - session.sendUpstreamPacket(blockEventPacket); + public GeyserShapedRecipe(ShapedRecipeData data) { + this(data.getWidth(), data.getHeight(), data.getIngredients(), data.getResult()); } + @Override + public boolean isShaped() { + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java new file mode 100644 index 000000000..6c7665bbb --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserShapelessRecipe.java @@ -0,0 +1,42 @@ +/* + * 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.inventory.recipe; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; +import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; + +public record GeyserShapelessRecipe(Ingredient[] ingredients, ItemStack result) implements GeyserRecipe { + + public GeyserShapelessRecipe(ShapelessRecipeData data) { + this(data.getIngredients(), data.getResult()); + } + + @Override + public boolean isShaped() { + return false; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/factory/ExperienceOrbEntityFactory.java b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java similarity index 71% rename from core/src/main/java/org/geysermc/geyser/entity/factory/ExperienceOrbEntityFactory.java rename to core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java index 40a93c08b..04a772c31 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/factory/ExperienceOrbEntityFactory.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/recipe/GeyserStonecutterData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,14 +23,13 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity.factory; +package org.geysermc.geyser.inventory.recipe; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.ExpOrbEntity; -import org.geysermc.geyser.session.GeyserSession; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -@FunctionalInterface -public interface ExperienceOrbEntityFactory extends EntityFactory { - - ExpOrbEntity create(GeyserSession session, int amount, long entityId, long geyserId, Vector3f position); +/** + * @param buttonId the button that needs to be pressed for Java Edition to accept this item. + * @param output the expected output of this item when cut. + */ +public record GeyserStonecutterData(int buttonId, ItemStack output) { } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java index f95633768..655d0f215 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/AnvilInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -384,19 +384,19 @@ public class AnvilInventoryUpdater extends InventoryUpdater { if (enchantTag.get("id") instanceof StringTag javaEnchId) { JavaEnchantment enchantment = JavaEnchantment.getByJavaIdentifier(javaEnchId.getValue()); if (enchantment == null) { - GeyserImpl.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment in anvil: " + javaEnchId.getValue()); continue; } Tag javaEnchLvl = enchantTag.get("lvl"); - if (!(javaEnchLvl instanceof ShortTag || javaEnchLvl instanceof IntTag)) + if (javaEnchLvl == null || !(javaEnchLvl.getValue() instanceof Number number)) continue; // Handle duplicate enchantments if (bedrock) { - enchantments.putIfAbsent(enchantment, ((Number) javaEnchLvl.getValue()).intValue()); + enchantments.putIfAbsent(enchantment, number.intValue()); } else { - enchantments.mergeInt(enchantment, ((Number) javaEnchLvl.getValue()).intValue(), Math::max); + enchantments.mergeInt(enchantment, number.intValue(), Math::max); } } } diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java index 65147abb6..1e5c6946d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ChestInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java index dd1e810ca..705a8b242 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/ContainerInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java index 10a556c81..fa680c201 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/HorseInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java index 6910aa447..421a8101d 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/InventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java index 79b6bffc0..e86e62d10 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/updater/UIInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java b/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java new file mode 100644 index 000000000..78c6b2c6a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/BedrockDimension.java @@ -0,0 +1,41 @@ +/* + * 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; + +/** + * A data structure to represent what Bedrock believes are the height requirements for a specific dimension. + * As of 1.18.30, biome count is representative of the height of the world, and out-of-bounds chunks can crash + * the client. + * + * @param minY The minimum height Bedrock Edition will accept. + * @param height The maximum chunk height Bedrock Edition will accept, from the lowest point to the highest. + * @param doUpperHeightWarn whether to warn in the console if the Java dimension height exceeds Bedrock's. + */ +public record BedrockDimension(int minY, int height, boolean doUpperHeightWarn) { + public static BedrockDimension OVERWORLD = new BedrockDimension(-64, 384, true); + public static BedrockDimension THE_NETHER = new BedrockDimension(0, 128, false); + public static BedrockDimension THE_END = new BedrockDimension(0, 256, true); +} diff --git a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java index 002753407..9f1212875 100644 --- a/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java +++ b/core/src/main/java/org/geysermc/geyser/level/BedrockMapIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/FireworkColor.java b/core/src/main/java/org/geysermc/geyser/level/FireworkColor.java index cb8c57517..e005ab2d8 100644 --- a/core/src/main/java/org/geysermc/geyser/level/FireworkColor.java +++ b/core/src/main/java/org/geysermc/geyser/level/FireworkColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/GameRule.java b/core/src/main/java/org/geysermc/geyser/level/GameRule.java index d11288c6f..be647cff6 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GameRule.java +++ b/core/src/main/java/org/geysermc/geyser/level/GameRule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java index 24bebf10a..fc3c86dd4 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserAdvancement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,6 +28,7 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; import lombok.NonNull; import org.geysermc.geyser.session.cache.AdvancementsCache; +import org.geysermc.geyser.text.ChatColor; import java.util.List; @@ -69,6 +70,14 @@ public class GeyserAdvancement { return this.advancement.getDisplayData(); } + /** + * @return Purple for challenges and green for normal advancements + */ + public String getDisplayColor() { + Advancement.DisplayData displayData = getDisplayData(); + return displayData != null && displayData.getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ? ChatColor.LIGHT_PURPLE : ChatColor.GREEN; + } + public String getRootId(AdvancementsCache advancementsCache) { if (rootId == null) { if (this.advancement.getParentId() == null) { 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 ac7084980..100917793 100644 --- a/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/GeyserWorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,15 +27,14 @@ package org.geysermc.geyser.level; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.ChunkCache; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; -import org.geysermc.geyser.level.block.BlockStateValues; import java.util.Locale; @@ -83,7 +82,7 @@ public class GeyserWorldManager extends WorldManager { @Override public void setGameRule(GeyserSession session, String name, Object value) { - session.sendDownstreamPacket(new ServerboundChatPacket("/gamerule " + name + " " + value)); + session.sendCommand("gamerule " + name + " " + value); gameruleCache.put(name, String.valueOf(value)); } @@ -109,12 +108,12 @@ public class GeyserWorldManager extends WorldManager { @Override public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { - session.sendDownstreamPacket(new ServerboundChatPacket("/gamemode " + gameMode.name().toLowerCase(Locale.ROOT))); + session.sendCommand("gamemode " + gameMode.name().toLowerCase(Locale.ROOT)); } @Override public void setDifficulty(GeyserSession session, Difficulty difficulty) { - session.sendDownstreamPacket(new ServerboundChatPacket("/difficulty " + difficulty.name().toLowerCase(Locale.ROOT))); + session.sendCommand("difficulty " + difficulty.name().toLowerCase(Locale.ROOT)); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java new file mode 100644 index 000000000..5f3c96b86 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/level/JavaDimension.java @@ -0,0 +1,56 @@ +/* + * 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; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import org.geysermc.geyser.util.JavaCodecEntry; + +import java.util.Map; + +/** + * Represents the information we store from the current Java dimension + * @param piglinSafe Whether piglins and hoglins are safe from conversion in this dimension. + * This controls if they have the shaking effect applied in the dimension. + */ +public record JavaDimension(int minY, int maxY, boolean piglinSafe, double worldCoordinateScale) { + + public static void load(CompoundTag tag, Map map) { + for (CompoundTag dimension : JavaCodecEntry.iterateAsTag(tag.get("minecraft:dimension_type"))) { + CompoundTag elements = dimension.get("element"); + int minY = ((IntTag) elements.get("min_y")).getValue(); + int maxY = ((IntTag) elements.get("height")).getValue(); + // Logical height can be ignored probably - seems to be for artificial limits like the Nether. + + // Set if piglins/hoglins should shake + boolean piglinSafe = ((Number) elements.get("piglin_safe").getValue()).byteValue() != (byte) 0; + // Load world coordinate scale for the world border + double coordinateScale = ((Number) elements.get("coordinate_scale").getValue()).doubleValue(); + + map.put((String) dimension.get("name").getValue(), new JavaDimension(minY, maxY, piglinSafe, coordinateScale)); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/level/MapColor.java b/core/src/main/java/org/geysermc/geyser/level/MapColor.java index 1b2de18d1..d84788db2 100644 --- a/core/src/main/java/org/geysermc/geyser/level/MapColor.java +++ b/core/src/main/java/org/geysermc/geyser/level/MapColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java index 952828b17..5c0cbf643 100644 --- a/core/src/main/java/org/geysermc/geyser/level/PaintingType.java +++ b/core/src/main/java/org/geysermc/geyser/level/PaintingType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -56,17 +56,17 @@ public enum PaintingType { SKELETON("Skeleton", 4, 3), DONKEY_KONG("DonkeyKong", 4, 3), POINTER("Pointer", 4, 4), - PIG_SCENE("Pigscene", 4, 4), - BURNING_SKULL("BurningSkull", 4, 4); + PIGSCENE("Pigscene", 4, 4), + BURNING_SKULL("BurningSkull", 4, 4), + EARTH("Earth", 2, 2), + WIND("Wind", 2, 2), + WATER("Water", 2, 2), + FIRE("Fire", 2, 2); private static final PaintingType[] VALUES = values(); - private String bedrockName; - private int width; - private int height; - - public com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType toJavaType() { - return com.github.steveice10.mc.protocol.data.game.entity.type.PaintingType.valueOf(name()); - } + private final String bedrockName; + private final int width; + private final int height; public static PaintingType getByName(String javaName) { for (PaintingType paintingName : VALUES) { 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 9aaf323c0..69f5d5beb 100644 --- a/core/src/main/java/org/geysermc/geyser/level/WorldManager.java +++ b/core/src/main/java/org/geysermc/geyser/level/WorldManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import com.nukkitx.math.vector.Vector3i; @@ -41,17 +40,6 @@ import org.geysermc.geyser.session.GeyserSession; */ public abstract class WorldManager { - /** - * Gets the Java block state at the specified location - * - * @param session the session - * @param position the position - * @return the block state at the specified location - */ - public int getBlockAt(GeyserSession session, Position position) { - return this.getBlockAt(session, position.getX(), position.getY(), position.getZ()); - } - /** * Gets the Java block state at the specified location * @@ -59,7 +47,7 @@ public abstract class WorldManager { * @param vector the position * @return the block state at the specified location */ - public int getBlockAt(GeyserSession session, Vector3i vector) { + public final int getBlockAt(GeyserSession session, Vector3i vector) { return this.getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); } 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 index 0c7235f6c..d22150ccf 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/BlockPositionIterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,8 +26,6 @@ package org.geysermc.geyser.level.block; import com.nukkitx.network.util.Preconditions; -import lombok.Getter; - public class BlockPositionIterator { private final int minX; 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 432ea1081..a9b3ffedc 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,6 +38,8 @@ import org.geysermc.geyser.util.collection.FixedInt2ByteMap; import org.geysermc.geyser.util.collection.FixedInt2IntMap; import org.geysermc.geyser.util.collection.LecternHasBookMap; +import java.util.Locale; + /** * Used for block entities if the Java block state contains Bedrock block information. */ @@ -47,7 +49,9 @@ public final class BlockStateValues { private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap(); private static final Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); + private static final IntSet HORIZONTAL_FACING_JIGSAWS = new IntOpenHashSet(); private static final LecternHasBookMap LECTERN_BOOK_STATES = new LecternHasBookMap(); + private static final IntSet NON_WATER_CAULDRONS = new IntOpenHashSet(); private static final Int2IntMap NOTEBLOCK_PITCHES = new FixedInt2IntMap(); private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap(); private static final IntSet STICKY_PISTONS = new IntOpenHashSet(); @@ -170,12 +174,27 @@ public final class BlockStateValues { JsonNode shulkerDirection = blockData.get("shulker_direction"); if (shulkerDirection != null) { BlockStateValues.SHULKERBOX_DIRECTIONS.put(javaBlockState, (byte) shulkerDirection.intValue()); + return; } - if (javaId.startsWith("minecraft:water")) { + if (javaId.startsWith("minecraft:water") && !javaId.contains("cauldron")) { String strLevel = javaId.substring(javaId.lastIndexOf("level=") + 6, javaId.length() - 1); int level = Integer.parseInt(strLevel); WATER_LEVEL.put(javaBlockState, level); + return; + } + + if (javaId.startsWith("minecraft:jigsaw[orientation=")) { + String blockStateData = javaId.substring(javaId.indexOf("orientation=") + "orientation=".length(), javaId.lastIndexOf('_')); + Direction direction = Direction.valueOf(blockStateData.toUpperCase(Locale.ROOT)); + if (direction.isHorizontal()) { + HORIZONTAL_FACING_JIGSAWS.add(javaBlockState); + } + return; + } + + if (javaId.contains("_cauldron") && !javaId.contains("water_")) { + NON_WATER_CAULDRONS.add(javaBlockState); } } @@ -201,6 +220,15 @@ public final class BlockStateValues { return BED_COLORS.getOrDefault(state, (byte) -1); } + /** + * Non-water cauldrons (since Bedrock 1.18.30) must have a block entity packet sent on chunk load to fix rendering issues. + * + * @return if this Java block state is a non-empty non-water cauldron + */ + public static boolean isCauldron(int state) { + return NON_WATER_CAULDRONS.contains(state); + } + /** * The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags * in Bedrock need the conditional information. @@ -230,6 +258,13 @@ public final class BlockStateValues { return FLOWER_POT_VALUES; } + /** + * @return a set of all forward-facing jigsaws, to use as a fallback if NBT is missing. + */ + public static IntSet getHorizontalFacingJigsaws() { + return HORIZONTAL_FACING_JIGSAWS; + } + /** * @return the lectern book state map pointing to book present state */ diff --git a/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java b/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java index bd4128abc..8024af650 100644 --- a/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java +++ b/core/src/main/java/org/geysermc/geyser/level/block/DoubleChestValue.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/BlockStorage.java b/core/src/main/java/org/geysermc/geyser/level/chunk/BlockStorage.java index 62d7df413..fbcdfc3dc 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/BlockStorage.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/BlockStorage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java index 365d196a3..ca8c4db1d 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunk.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java index 6daf13996..748bc8579 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/GeyserChunkSection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/NibbleArray.java b/core/src/main/java/org/geysermc/geyser/level/chunk/NibbleArray.java deleted file mode 100644 index 43dbd9fdc..000000000 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/NibbleArray.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.chunk; - -import com.nukkitx.network.util.Preconditions; - -public class NibbleArray implements Cloneable { - - private final byte[] data; - - public NibbleArray(int length) { - data = new byte[length / 2]; - } - - public NibbleArray(byte[] array) { - data = array; - } - - public byte get(int index) { - Preconditions.checkElementIndex(index, data.length * 2); - byte val = data[index / 2]; - if ((index & 1) == 0) { - return (byte) (val & 0x0f); - } else { - return (byte) ((val & 0xf0) >>> 4); - } - } - - public void set(int index, byte value) { - Preconditions.checkArgument(value >= 0 && value < 16, "Nibbles must have a value between 0 and 15."); - Preconditions.checkElementIndex(index, data.length * 2); - value &= 0xf; - int half = index / 2; - byte previous = data[half]; - if ((index & 1) == 0) { - data[half] = (byte) (previous & 0xf0 | value); - } else { - data[half] = (byte) (previous & 0x0f | value << 4); - } - } - - public void fill(byte value) { - Preconditions.checkArgument(value >= 0 && value < 16, "Nibbles must have a value between 0 and 15."); - value &= 0xf; - for (int i = 0; i < data.length; i++) { - data[i] = (byte) ((value << 4) | value); - } - } - - public void copyFrom(byte[] bytes) { - Preconditions.checkNotNull(bytes, "bytes"); - Preconditions.checkArgument(bytes.length == data.length, "length of provided byte array is %s but expected %s", bytes.length, - data.length); - System.arraycopy(bytes, 0, data, 0, data.length); - } - - public void copyFrom(NibbleArray array) { - Preconditions.checkNotNull(array, "array"); - copyFrom(array.data); - } - - public byte[] getData() { - return data; - } - - public NibbleArray copy() { - return new NibbleArray(getData().clone()); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArray.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArray.java index cf69e697f..e5eb44bee 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArray.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java index cd54ed73f..d2f3e7c9e 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/BitArrayVersion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/PaddedBitArray.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/PaddedBitArray.java index 3686ed4e0..64c453bb3 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/PaddedBitArray.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/PaddedBitArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/Pow2BitArray.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/Pow2BitArray.java index be5567e15..0a925a184 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/Pow2BitArray.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/Pow2BitArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java index 0c64ad76b..6e37749df 100644 --- a/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java +++ b/core/src/main/java/org/geysermc/geyser/level/chunk/bitarray/SingletonBitArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/Axis.java b/core/src/main/java/org/geysermc/geyser/level/physics/Axis.java index d9334368f..8d2820a54 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/Axis.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/Axis.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java b/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java index 6600c5abc..108982a32 100644 --- a/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java +++ b/core/src/main/java/org/geysermc/geyser/level/physics/BoundingBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 5bd72182f..2617b2750 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -362,7 +362,22 @@ public class CollisionManager { * @return true if the block located at the player's floor position plus 1 would intersect with the player, * were they not sneaking */ - public boolean isUnderSlab() { + public boolean mustPlayerSneakHere() { + return checkPose(EntityDefinitions.PLAYER.height()); + } + + /** + * @return true if the block located at the player's floor position plus 1 would intersect with the player, + * were they not crawling + */ + public boolean mustPlayerCrawlHere() { + return checkPose(PlayerEntity.SNEAKING_POSE_HEIGHT); + } + + /** + * @param height check and see if this height is invalid in the current player position + */ + private boolean checkPose(float height) { Vector3i position = session.getPlayerEntity().getPosition().toInt(); BlockCollision collision = BlockUtils.getCollisionAt(session, position); if (collision != null) { @@ -370,7 +385,7 @@ public class CollisionManager { // at the current location. double originalY = playerBoundingBox.getMiddleY(); double originalHeight = playerBoundingBox.getSizeY(); - double standingY = originalY - (originalHeight / 2.0) + (EntityDefinitions.PLAYER.height() / 2.0); + double standingY = originalY - (originalHeight / 2.0) + (height / 2.0); playerBoundingBox.setSizeY(EntityDefinitions.PLAYER.height()); playerBoundingBox.setMiddleY(standingY); 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 fa3234460..48c50bc69 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 2a818d2d8..bf943134b 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/CIDRMatcher.java b/core/src/main/java/org/geysermc/geyser/network/CIDRMatcher.java index b29b12873..4328b987e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/CIDRMatcher.java +++ b/core/src/main/java/org/geysermc/geyser/network/CIDRMatcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java index 97ed35785..d41871cdb 100644 --- a/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/ConnectorServerEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -47,6 +47,8 @@ import java.nio.charset.StandardCharsets; import java.util.List; public class ConnectorServerEventHandler implements BedrockServerEventHandler { + private static final boolean PRINT_DEBUG_PINGS = Boolean.parseBoolean(System.getProperty("Geyser.PrintPingsInDebugMode", "true")); + /* The following constants are all used to ensure the ping does not reach a length where it is unparsable by the Bedrock client */ @@ -88,7 +90,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { @Override public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { - if (geyser.getConfig().isDebugMode()) { + if (geyser.getConfig().isDebugMode() && PRINT_DEBUG_PINGS) { geyser.getLogger().debug(GeyserLocale.getLocaleStringLog("geyser.network.pinged", inetSocketAddress)); } diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 0dceed7e9..b0b707ee0 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java index 868f87a5d..fff0d38fe 100644 --- a/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/MinecraftProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,12 +28,10 @@ package org.geysermc.geyser.network; import com.github.steveice10.mc.protocol.codec.MinecraftCodec; import com.github.steveice10.mc.protocol.codec.PacketCodec; import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import com.nukkitx.protocol.bedrock.v465.Bedrock_v465; -import com.nukkitx.protocol.bedrock.v471.Bedrock_v471; -import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; +import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.StringJoiner; @@ -45,7 +43,7 @@ public final class MinecraftProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v475.V475_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = BedrockBeta.BETA_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ @@ -58,9 +56,9 @@ public final class MinecraftProtocol { private static final PacketCodec DEFAULT_JAVA_CODEC = MinecraftCodec.CODEC; static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v465.V465_CODEC); - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v471.V471_CODEC); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); + SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() + .minecraftVersion("1.19.0") + .build()); } /** @@ -92,7 +90,7 @@ public final class MinecraftProtocol { * @return the supported Minecraft: Java Edition version names */ public static List getJavaVersions() { - return Arrays.asList("1.18", "1.18.1"); + return Collections.singletonList(DEFAULT_JAVA_CODEC.getMinecraftVersion()); } /** diff --git a/core/src/main/java/org/geysermc/geyser/network/QueryPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/QueryPacketHandler.java index c8d1959ef..8b08098f2 100644 --- a/core/src/main/java/org/geysermc/geyser/network/QueryPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/QueryPacketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 781f58ef5..5ae6fbca9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -30,17 +30,18 @@ import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.data.ExperimentData; import com.nukkitx.protocol.bedrock.data.ResourcePackType; import com.nukkitx.protocol.bedrock.packet.*; -import com.nukkitx.protocol.bedrock.v471.Bedrock_v471; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.configuration.GeyserConfiguration; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.pack.ResourcePack; import org.geysermc.geyser.pack.ResourcePackManifest; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.PendingMicrosoftAuthentication; +import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.util.*; +import org.geysermc.geyser.util.LoginEncryptionUtils; +import org.geysermc.geyser.util.MathUtils; import java.io.FileInputStream; import java.io.InputStream; @@ -73,11 +74,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { String supportedVersions = MinecraftProtocol.getAllSupportedBedrockVersions(); if (loginPacket.getProtocolVersion() > MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { // Too early to determine session locale - session.getGeyser().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions)); session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.server", supportedVersions)); return true; } else if (loginPacket.getProtocolVersion() < MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { - session.getGeyser().getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); session.disconnect(GeyserLocale.getLocaleStringLog("geyser.network.outdated.client", supportedVersions)); return true; } @@ -166,11 +165,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { stackPacket.getExperiments().add(new ExperimentData("data_driven_items", true)); } - if (session.getUpstream().getProtocolVersion() <= Bedrock_v471.V471_CODEC.getProtocolVersion()) { - // Allow extended world height in the overworld to work for pre-1.18 clients - stackPacket.getExperiments().add(new ExperimentData("caves_and_cliffs", true)); - } - session.sendUpstreamPacket(stackPacket); break; @@ -189,6 +183,14 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { } private boolean couldLoginUserByName(String bedrockUsername) { + if (geyser.getConfig().getSavedUserLogins().contains(bedrockUsername)) { + String refreshToken = geyser.refreshTokenFor(bedrockUsername); + if (refreshToken != null) { + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().name())); + session.authenticateWithRefreshToken(refreshToken); + return true; + } + } if (geyser.getConfig().getUserAuths() != null) { GeyserConfiguration.IUserAuthenticationInfo info = geyser.getConfig().getUserAuths().get(bedrockUsername); @@ -199,6 +201,12 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { return true; } } + PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(session.getAuthData().xuid()); + if (task != null) { + if (task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task)) { + return true; + } + } return false; } diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/ChannelWrapper.java b/core/src/main/java/org/geysermc/geyser/network/netty/ChannelWrapper.java index ec23c4149..26015a96f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/ChannelWrapper.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/ChannelWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/DefaultChannelPipelinePublic.java b/core/src/main/java/org/geysermc/geyser/network/netty/DefaultChannelPipelinePublic.java index 67bbf6427..67362c35e 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/DefaultChannelPipelinePublic.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/DefaultChannelPipelinePublic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserInjector.java b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserInjector.java index b87c41ba6..f2ae7c685 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/GeyserInjector.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/GeyserInjector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java index 96dcca77b..ac2b6898a 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWithRemoteAddress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWrapper.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWrapper.java index f80e85d70..258fa69eb 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWrapper.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalChannelWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java index 7bb11e01b..bb8ca754f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalServerChannelWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java index 7fa28ebf2..0781a04b2 100644 --- a/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java +++ b/core/src/main/java/org/geysermc/geyser/network/netty/LocalSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,6 +26,7 @@ package org.geysermc.geyser.network.netty; import com.github.steveice10.packetlib.BuiltinFlags; +import com.github.steveice10.packetlib.codec.PacketCodecHelper; import com.github.steveice10.packetlib.packet.PacketProtocol; import com.github.steveice10.packetlib.tcp.*; import io.netty.bootstrap.Bootstrap; @@ -47,15 +48,17 @@ public final class LocalSession extends TcpSession { private final SocketAddress targetAddress; private final String clientIp; + private final PacketCodecHelper codecHelper; - public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol) { + public LocalSession(String host, int port, SocketAddress targetAddress, String clientIp, PacketProtocol protocol, PacketCodecHelper codecHelper) { super(host, port, protocol); this.targetAddress = targetAddress; this.clientIp = clientIp; + this.codecHelper = codecHelper; } @Override - public void connect() { + public void connect(boolean wait) { if (this.disconnected) { throw new IllegalStateException("Connection has already been disconnected."); } @@ -102,6 +105,11 @@ public final class LocalSession extends TcpSession { } } + @Override + public PacketCodecHelper getCodecHelper() { + return this.codecHelper; + } + // TODO duplicate code private void addHAProxySupport(ChannelPipeline pipeline) { InetSocketAddress clientAddress = getFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS); 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 1f69fbdbc..d9f1e36f5 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java +++ b/core/src/main/java/org/geysermc/geyser/pack/ResourcePack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/pack/ResourcePackManifest.java b/core/src/main/java/org/geysermc/geyser/pack/ResourcePackManifest.java index 1e79b330b..2b14eade3 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/ResourcePackManifest.java +++ b/core/src/main/java/org/geysermc/geyser/pack/ResourcePackManifest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 9d36b0274..d438110d0 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserLegacyPingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/ping/GeyserPingInfo.java b/core/src/main/java/org/geysermc/geyser/ping/GeyserPingInfo.java index ac3c61980..d444e554c 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/GeyserPingInfo.java +++ b/core/src/main/java/org/geysermc/geyser/ping/GeyserPingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java b/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java index d2ebbe4ac..d414b7fa8 100644 --- a/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java +++ b/core/src/main/java/org/geysermc/geyser/ping/IGeyserPingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,6 +25,7 @@ package org.geysermc.geyser.ping; +import javax.annotation.Nullable; import java.net.Inet4Address; import java.net.InetSocketAddress; @@ -38,6 +39,7 @@ public interface IGeyserPingPassthrough { * * @return string of the MOTD */ + @Nullable default GeyserPingInfo getPingInformation() { return this.getPingInformation(new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69)); } @@ -48,6 +50,7 @@ public interface IGeyserPingPassthrough { * @param inetSocketAddress the ip address of the client pinging the server * @return string of the MOTD */ + @Nullable GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress); } 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 ce64ee265..fc4e3d022 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/ArrayRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ArrayRegistry.java index 5ef0aeba0..124aea713 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ArrayRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ArrayRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 98d3aa341..609647b2d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java new file mode 100644 index 000000000..892f4a6df --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/IntMappedRegistry.java @@ -0,0 +1,122 @@ +/* + * 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.registry; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.geysermc.geyser.registry.loader.RegistryLoader; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +/** + * A mapped registry with an integer as the key. This class is designed to minimize the need for boxing/unboxing keys. + * + * @param the value + */ +public class IntMappedRegistry extends AbstractMappedRegistry> { + protected IntMappedRegistry(I input, RegistryLoader> registryLoader) { + super(input, registryLoader); + } + + /** + * Returns the value registered by the given integer. + * + * @param i the integer + * @return the value registered by the given integer. + */ + public V get(int i) { + return this.mappings.get(i); + } + + @Nullable + @Override + @Deprecated + public V get(Integer key) { + return super.get(key); + } + + /** + * Returns the value registered by the given key or the default value + * specified if null. + * + * @param i the key + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public V getOrDefault(int i, V defaultValue) { + return this.mappings.getOrDefault(i, defaultValue); + } + + @Override + @Deprecated + public V getOrDefault(Integer key, V defaultValue) { + return super.getOrDefault(key, defaultValue); + } + + /** + * Registers a new value into this registry with the given key. + * + * @param i the key + * @param value the value + * @return a new value into this registry with the given key. + */ + public V register(int i, V value) { + return this.mappings.put(i, value); + } + + @Override + @Deprecated + public V register(Integer key, V value) { + return super.register(key, value); + } + + /** + * Creates a new integer mapped registry with the given {@link RegistryLoader}. The + * input type is not specified here, meaning the loader return type is either + * predefined, or the registry is populated at a later point. + * + * @param registryLoader the registry loader + * @param the input + * @param the map value + * @return a new registry with the given RegistryLoader + */ + public static IntMappedRegistry create(RegistryLoader> registryLoader) { + return new IntMappedRegistry<>(null, registryLoader); + } + + /** + * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. + * + * @param registryLoader the registry loader + * @param the input + * @param the map value + * @return a new registry with the given RegistryLoader supplier + */ + public static IntMappedRegistry create(I input, Supplier>> registryLoader) { + return new IntMappedRegistry<>(input, registryLoader.get()); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/MappedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/MappedRegistry.java index 9860eda78..98e8e1da2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/MappedRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/MappedRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java index e74d15001..3f7d88031 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/PacketTranslatorRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 ce63c2c5b..8f2a9775a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,11 +27,9 @@ package org.geysermc.geyser.registry; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; -import com.github.steveice10.mc.protocol.data.game.level.event.SoundEvent; +import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent; import com.github.steveice10.mc.protocol.data.game.level.particle.ParticleType; -import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; -import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; import com.github.steveice10.packetlib.packet.Packet; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; @@ -43,26 +41,26 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; -import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.inventory.item.Enchantment.JavaEnchantment; -import org.geysermc.geyser.translator.sound.SoundTranslator; -import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; -import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; -import org.geysermc.geyser.translator.level.event.LevelEventTranslator; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.registry.loader.*; import org.geysermc.geyser.registry.populator.ItemRegistryPopulator; +import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; import org.geysermc.geyser.registry.populator.RecipeRegistryPopulator; import org.geysermc.geyser.registry.type.EnchantmentData; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.translator.collision.BlockCollision; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.geyser.translator.level.event.LevelEventTranslator; +import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; +import org.geysermc.geyser.translator.sound.SoundTranslator; import java.util.EnumMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.IntFunction; /** * Holds all the common registries in Geyser. @@ -96,7 +94,7 @@ public final class Registries { /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ - public static final SimpleMappedRegistry COLLISIONS = SimpleMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new); + public static final IntMappedRegistry COLLISIONS = IntMappedRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collision.json"), CollisionRegistryLoader::new); /** * A versioned registry which holds a {@link RecipeType} to a corresponding list of {@link CraftingData}. @@ -141,15 +139,15 @@ public final class Registries { public static final SimpleRegistry> POTION_MIXES; /** - * A versioned registry holding all the recipes, with the net ID being the key, and {@link Recipe} as the value. + * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. */ - public static final VersionedRegistry> RECIPES = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + public static final VersionedRegistry> RECIPES = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); /** * A mapped registry holding the available records, with the ID of the record being the key, and the {@link com.nukkitx.protocol.bedrock.data.SoundEvent} * as the value. */ - public static final SimpleMappedRegistry RECORDS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + public static final IntMappedRegistry RECORDS = IntMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); /** * A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}. @@ -157,9 +155,9 @@ public final class Registries { public static final SimpleMappedRegistry SOUNDS = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); /** - * A mapped registry holding {@link SoundEvent}s to their corresponding {@link LevelEventTranslator}. + * A mapped registry holding {@link LevelEvent}s to their corresponding {@link LevelEventTranslator}. */ - public static final SimpleMappedRegistry SOUND_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); + public static final SimpleMappedRegistry SOUND_LEVEL_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); /** * A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}. diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registry.java b/core/src/main/java/org/geysermc/geyser/registry/Registry.java index 15a18e3b1..f5412fd6d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedRegistry.java index 9eddab92f..f108bf703 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/SimpleRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/SimpleRegistry.java index b39aae450..59855c1ab 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/SimpleRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/SimpleRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/VersionedRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/VersionedRegistry.java index 93387a770..cfed73d24 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/VersionedRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/VersionedRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/AnnotatedRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/AnnotatedRegistryLoader.java index d8314965f..ba9ba1d76 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/AnnotatedRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/AnnotatedRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java index e685c8760..f7fb708fb 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/BiomeIdentifierRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java index b18d6959d..f47273827 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/BlockEntityRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java index 949c3ee96..b74573a4e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/CollisionRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -50,10 +50,10 @@ import java.util.regex.Pattern; /** * Loads collision data from the given resource path. */ -public class CollisionRegistryLoader extends MultiResourceRegistryLoader> { +public class CollisionRegistryLoader extends MultiResourceRegistryLoader> { @Override - public Map load(Pair input) { + public Int2ObjectMap load(Pair input) { Int2ObjectMap collisions = new Int2ObjectOpenHashMap<>(); Map, CollisionInfo> annotationMap = new IdentityHashMap<>(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/EffectRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/EffectRegistryLoader.java index 8d46d2639..9e1bbc6aa 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/EffectRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/EffectRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java index 59fb5029b..e566ff37c 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/EnchantmentRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/MultiResourceRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/MultiResourceRegistryLoader.java index fd2fb317a..e6e6e0978 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/MultiResourceRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/MultiResourceRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/NbtRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/NbtRegistryLoader.java index e4006c0f2..fcbacbfbc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/NbtRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/NbtRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java index 0ea76c9bb..fc757ca05 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ParticleTypesRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 1280ce297..b0a9c72b2 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoader.java index bb43ba9ba..5d916f74d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaders.java b/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaders.java index 35bf384c7..132b7cff5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaders.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java index 1b0f93c6a..64d974bc3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundEventsRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,7 +26,7 @@ package org.geysermc.geyser.registry.loader; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.level.event.SoundEvent; +import com.github.steveice10.mc.protocol.data.game.level.event.LevelEvent; import com.nukkitx.protocol.bedrock.data.LevelEventType; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.geyser.GeyserImpl; @@ -41,37 +41,37 @@ import java.util.Map; /** * Loads sound effects from the given resource path. */ -public class SoundEventsRegistryLoader extends EffectRegistryLoader> { +public class SoundEventsRegistryLoader extends EffectRegistryLoader> { @Override - public Map load(String input) { + public Map load(String input) { this.loadFile(input); Iterator> effectsIterator = this.get(input).fields(); - Map soundEffects = new Object2ObjectOpenHashMap<>(); + Map soundEffects = new Object2ObjectOpenHashMap<>(); while (effectsIterator.hasNext()) { Map.Entry entry = effectsIterator.next(); JsonNode node = entry.getValue(); try { String type = node.get("type").asText(); - SoundEvent javaEffect = null; + LevelEvent javaEffect = null; LevelEventTranslator transformer = null; switch (type) { case "soundLevel" -> { - javaEffect = SoundEvent.valueOf(entry.getKey()); + javaEffect = LevelEvent.valueOf(entry.getKey()); LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText()); int data = node.has("data") ? node.get("data").intValue() : 0; transformer = new SoundLevelEventTranslator(levelEventType, data); } case "soundEvent" -> { - javaEffect = SoundEvent.valueOf(entry.getKey()); + javaEffect = LevelEvent.valueOf(entry.getKey()); com.nukkitx.protocol.bedrock.data.SoundEvent soundEvent = com.nukkitx.protocol.bedrock.data.SoundEvent.valueOf(node.get("name").asText()); String identifier = node.has("identifier") ? node.get("identifier").asText() : ""; int extraData = node.has("extraData") ? node.get("extraData").intValue() : -1; transformer = new SoundEventEventTranslator(soundEvent, identifier, extraData); } case "playSound" -> { - javaEffect = SoundEvent.valueOf(entry.getKey()); + javaEffect = LevelEvent.valueOf(entry.getKey()); String name = node.get("name").asText(); float volume = node.has("volume") ? node.get("volume").floatValue() : 1.0f; boolean pitchSub = node.has("pitch_sub") && node.get("pitch_sub").booleanValue(); @@ -85,7 +85,7 @@ public class SoundEventsRegistryLoader extends EffectRegistryLoader next = soundsIterator.next(); JsonNode brMap = next.getValue(); - soundMappings.put(next.getKey(), new SoundMapping( - next.getKey(), + String javaSound = next.getKey(); + soundMappings.put(javaSound, new SoundMapping( + javaSound, brMap.has("bedrock_mapping") && brMap.get("bedrock_mapping").isTextual() ? brMap.get("bedrock_mapping").asText() : null, brMap.has("playsound_mapping") && brMap.get("playsound_mapping").isTextual() ? brMap.get("playsound_mapping").asText() : null, brMap.has("extra_data") && brMap.get("extra_data").isInt() ? brMap.get("extra_data").asInt() : -1, diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundTranslatorRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundTranslatorRegistryLoader.java index 457a32f56..359cd112e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/SoundTranslatorRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/SoundTranslatorRegistryLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 fef5b32aa..58a1bdb0f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,8 +28,7 @@ package org.geysermc.geyser.registry.populator; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableMap; import com.nukkitx.nbt.*; -import com.nukkitx.protocol.bedrock.v465.Bedrock_v465; -import com.nukkitx.protocol.bedrock.v471.Bedrock_v471; +import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -46,7 +45,10 @@ import org.geysermc.geyser.util.BlockUtils; import java.io.DataInputStream; import java.io.InputStream; -import java.util.*; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.Iterator; +import java.util.Map; import java.util.function.BiFunction; import java.util.zip.GZIPInputStream; @@ -59,8 +61,7 @@ public class BlockRegistryPopulator { static { ImmutableMap.Builder, BiFunction> stateMapperBuilder = ImmutableMap., BiFunction>builder() - .put(ObjectIntPair.of("1_17_30", Bedrock_v465.V465_CODEC.getProtocolVersion()), EMPTY_MAPPER) - .put(ObjectIntPair.of("1_17_40", Bedrock_v471.V471_CODEC.getProtocolVersion()), EMPTY_MAPPER); + .put(ObjectIntPair.of("1_19_0", BedrockBeta.BETA_CODEC.getProtocolVersion()), EMPTY_MAPPER); BLOCK_MAPPERS = stateMapperBuilder.build(); } @@ -87,7 +88,6 @@ public class BlockRegistryPopulator { } catch (Exception e) { throw new AssertionError("Unable to get blocks from runtime block states", e); } - Map javaIdentifierToBedrockTag = new Object2ObjectOpenHashMap<>(blocksTag.size()); // New since 1.16.100 - find the block runtime ID by the order given to us in the block palette, // as we no longer send a block palette Object2IntMap blockStateOrderedMap = new Object2IntOpenHashMap<>(blocksTag.size()); @@ -157,10 +157,6 @@ public class BlockRegistryPopulator { flowerPotBlocks.put(cleanJavaIdentifier.intern(), blocksTag.get(bedrockRuntimeId)); } - if (!cleanJavaIdentifier.equals(entry.getValue().get("bedrock_identifier").asText())) { - javaIdentifierToBedrockTag.put(cleanJavaIdentifier.intern(), blocksTag.get(bedrockRuntimeId)); - } - javaToBedrockBlocks[javaRuntimeId] = bedrockRuntimeId; } @@ -195,7 +191,6 @@ public class BlockRegistryPopulator { BlockRegistries.BLOCKS.register(palette.getKey().valueInt(), builder.blockStateVersion(stateVersion) .javaToBedrockBlocks(javaToBedrockBlocks) - .javaIdentifierToBedrockTag(javaIdentifierToBedrockTag) .itemFrames(itemFrames) .flowerPotBlocks(flowerPotBlocks) .jigsawStateIds(jigsawStateIds) @@ -255,7 +250,7 @@ public class BlockRegistryPopulator { builder.pickItem(pickItemNode.textValue().intern()); } - if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor")) { + if (javaId.equals("minecraft:obsidian") || javaId.equals("minecraft:crying_obsidian") || javaId.startsWith("minecraft:respawn_anchor") || javaId.startsWith("minecraft:reinforced_deepslate")) { builder.pistonBehavior(PistonBehavior.BLOCK); } else { JsonNode pistonBehaviorNode = entry.getValue().get("piston_behavior"); 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 71036b792..2868652bd 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,15 +31,12 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.protocol.bedrock.beta.BedrockBeta; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import com.nukkitx.protocol.bedrock.v465.Bedrock_v465; -import com.nukkitx.protocol.bedrock.v471.Bedrock_v471; -import com.nukkitx.protocol.bedrock.v475.Bedrock_v475; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.objects.*; @@ -49,6 +46,8 @@ import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.*; +import org.geysermc.geyser.util.ItemUtils; +import org.geysermc.geyser.util.collection.FixedInt2IntMap; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -59,19 +58,14 @@ import java.util.*; * Populates the item registries. */ public class ItemRegistryPopulator { - private static final Map PALETTE_VERSIONS; - - static { - PALETTE_VERSIONS = new Object2ObjectOpenHashMap<>(); - PALETTE_VERSIONS.put("1_17_30", new PaletteVersion(Bedrock_v465.V465_CODEC.getProtocolVersion(), Collections.emptyMap())); - PALETTE_VERSIONS.put("1_17_40", new PaletteVersion(Bedrock_v471.V471_CODEC.getProtocolVersion(), Collections.emptyMap())); - PALETTE_VERSIONS.put("1_18_0", new PaletteVersion(Bedrock_v475.V475_CODEC.getProtocolVersion(), Collections.emptyMap())); - } private record PaletteVersion(int protocolVersion, Map additionalTranslatedItems) { } public static void populate() { + Map paletteVersions = new Object2ObjectOpenHashMap<>(); + paletteVersions.put("1_19_0", new PaletteVersion(BedrockBeta.BETA_CODEC.getProtocolVersion(), Collections.emptyMap())); + GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); TypeReference> mappingItemsType = new TypeReference<>() { }; @@ -84,8 +78,12 @@ public class ItemRegistryPopulator { throw new AssertionError("Unable to load Java runtime item IDs", e); } + // We can reduce some operations as Java information is the same across all palette versions + boolean firstMappingsPass = true; + Int2IntMap dyeColors = new FixedInt2IntMap(); + /* Load item palette */ - for (Map.Entry palette : PALETTE_VERSIONS.entrySet()) { + for (Map.Entry palette : paletteVersions.entrySet()) { TypeReference> paletteEntriesType = new TypeReference<>() {}; // Used to get the Bedrock namespaced ID (in instances where there are small differences) @@ -125,7 +123,7 @@ public class ItemRegistryPopulator { IntList spawnEggs = new IntArrayList(); List carpets = new ObjectArrayList<>(); - Int2ObjectMap mappings = new Int2ObjectOpenHashMap<>(); + List mappings = new ObjectArrayList<>(); // Temporary mapping to create stored items Map identifierToMapping = new Object2ObjectOpenHashMap<>(); @@ -163,6 +161,9 @@ public class ItemRegistryPopulator { if (identifier.equals("minecraft:debug_stick")) { // Just shows an empty texture; either way it doesn't exist in the creative menu on Java continue; + } else if (identifier.equals("minecraft:empty_map") && damage == 2) { + // Bedrock-only as its own item + continue; } StartGamePacket.ItemEntry entry = entries.get(identifier); int id = -1; @@ -224,16 +225,16 @@ public class ItemRegistryPopulator { // This items has a mapping specifically for this version of the game mappingItem = entry.getValue(); } - if (javaIdentifier.equals("minecraft:music_disc_otherside") && palette.getValue().protocolVersion() <= Bedrock_v471.V471_CODEC.getProtocolVersion()) { - mappingItem.setBedrockIdentifier("minecraft:music_disc_pigstep"); - } if (usingFurnaceMinecart && javaIdentifier.equals("minecraft:furnace_minecart")) { javaFurnaceMinecartId = itemIndex; itemIndex++; + // Will be added later + mappings.add(null); continue; } - String bedrockIdentifier = mappingItem.getBedrockIdentifier().intern(); + + String bedrockIdentifier = mappingItem.getBedrockIdentifier(); int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); if (bedrockId == Short.MIN_VALUE) { throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); @@ -358,12 +359,13 @@ public class ItemRegistryPopulator { ItemMapping.ItemMappingBuilder mappingBuilder = ItemMapping.builder() .javaIdentifier(javaIdentifier) .javaId(itemIndex) - .bedrockIdentifier(bedrockIdentifier) + .bedrockIdentifier(bedrockIdentifier.intern()) .bedrockId(bedrockId) .bedrockData(mappingItem.getBedrockData()) .bedrockBlockId(bedrockBlockId) .stackSize(stackSize) - .maxDamage(mappingItem.getMaxDamage()); + .maxDamage(mappingItem.getMaxDamage()) + .hasSuspiciousStewEffect(mappingItem.isHasSuspiciousStewEffect()); if (mappingItem.getRepairMaterials() != null) { mappingBuilder = mappingBuilder.repairMaterials(new ObjectOpenHashSet<>(mappingItem.getRepairMaterials())); @@ -406,11 +408,15 @@ public class ItemRegistryPopulator { spawnEggs.add(mapping.getBedrockId()); } - mappings.put(itemIndex, mapping); + mappings.add(mapping); identifierToMapping.put(javaIdentifier, mapping); itemNames.add(javaIdentifier); + if (firstMappingsPass && mappingItem.getDyeColor() != -1) { + dyeColors.put(itemIndex, mappingItem.getDyeColor()); + } + itemIndex++; } @@ -423,16 +429,14 @@ public class ItemRegistryPopulator { // Add the lodestone compass since it doesn't exist on java but we need it for item conversion ItemMapping lodestoneEntry = ItemMapping.builder() - .javaIdentifier("minecraft:lodestone_compass") + .javaIdentifier("") .bedrockIdentifier("minecraft:lodestone_compass") - .javaId(itemIndex) + .javaId(-1) .bedrockId(lodestoneCompassId) .bedrockData(0) .bedrockBlockId(-1) .stackSize(1) .build(); - mappings.put(itemIndex, lodestoneEntry); - identifierToMapping.put(lodestoneEntry.getJavaIdentifier(), lodestoneEntry); ComponentItemData furnaceMinecartData = null; if (usingFurnaceMinecart) { @@ -441,7 +445,7 @@ public class ItemRegistryPopulator { entries.put("geysermc:furnace_minecart", new StartGamePacket.ItemEntry("geysermc:furnace_minecart", (short) furnaceMinecartId, true)); - mappings.put(javaFurnaceMinecartId, ItemMapping.builder() + mappings.set(javaFurnaceMinecartId, ItemMapping.builder() .javaIdentifier("minecraft:furnace_minecart") .bedrockIdentifier("geysermc:furnace_minecart") .javaId(javaFurnaceMinecartId) @@ -492,9 +496,9 @@ public class ItemRegistryPopulator { } ItemMappings itemMappings = ItemMappings.builder() - .items(mappings) + .items(mappings.toArray(new ItemMapping[0])) .creativeItems(creativeItems.toArray(new ItemData[0])) - .itemEntries(new ArrayList<>(entries.values())) + .itemEntries(List.copyOf(entries.values())) .itemNames(itemNames.toArray(new String[0])) .storedItems(new StoredItemMappings(identifierToMapping)) .javaOnlyItems(javaOnlyItems) @@ -503,9 +507,14 @@ public class ItemRegistryPopulator { .spawnEggIds(spawnEggs) .carpets(carpets) .furnaceMinecartData(furnaceMinecartData) + .lodestoneCompass(lodestoneEntry) .build(); Registries.ITEMS.register(palette.getValue().protocolVersion(), itemMappings); + + firstMappingsPass = false; } + + ItemUtils.setDyeColors(dyeColors); } } 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 5024d26e7..5aeb3a757 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java index 7af45f74d..f0a215f2a 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/RecipeRegistryPopulator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,10 +28,7 @@ package org.geysermc.geyser.registry.populator; import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; @@ -40,6 +37,9 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; @@ -71,7 +71,7 @@ public class RecipeRegistryPopulator { // Make a bit of an assumption here that the last recipe net ID will be equivalent between all versions LAST_RECIPE_NET_ID = currentRecipeId; Map> craftingData = new EnumMap<>(RecipeType.class); - Int2ObjectMap recipes = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap recipes = new Int2ObjectOpenHashMap<>(); craftingData.put(RecipeType.CRAFTING_SPECIAL_BOOKCLONING, Collections.singletonList(CraftingData.fromMulti(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), ++LAST_RECIPE_NET_ID))); @@ -124,7 +124,7 @@ public class RecipeRegistryPopulator { * @param recipes a list of all the recipes * @return the {@link CraftingData} to send to the Bedrock client. */ - private static CraftingData getCraftingDataFromJsonNode(JsonNode node, Int2ObjectMap recipes, ItemMappings mappings) { + private static CraftingData getCraftingDataFromJsonNode(JsonNode node, Int2ObjectMap recipes, ItemMappings mappings) { int netId = ++LAST_RECIPE_NET_ID; int type = node.get("bedrockRecipeType").asInt(); JsonNode outputNode = node.get("output"); @@ -165,9 +165,8 @@ public class RecipeRegistryPopulator { for (ItemData input : inputs) { ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)})); } - ShapedRecipeData data = new ShapedRecipeData(shape.get(0).length(), shape.size(), "crafting_table", + GeyserRecipe recipe = new GeyserShapedRecipe(shape.get(0).length(), shape.size(), ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); - Recipe recipe = new Recipe(RecipeType.CRAFTING_SHAPED, "", data); recipes.put(netId, recipe); /* Convert end */ @@ -185,9 +184,7 @@ public class RecipeRegistryPopulator { for (ItemData input : inputs) { ingredients.add(new Ingredient(new ItemStack[]{ItemTranslator.translateToJava(input, mappings)})); } - ShapelessRecipeData data = new ShapelessRecipeData("crafting_table", - ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); - Recipe recipe = new Recipe(RecipeType.CRAFTING_SHAPELESS, "", data); + GeyserRecipe recipe = new GeyserShapelessRecipe(ingredients.toArray(new Ingredient[0]), ItemTranslator.translateToJava(output, mappings)); recipes.put(netId, recipe); /* Convert end */ diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java index e65ebcfff..3fadcf5e5 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java index 0d85b80e0..41318ee64 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/BlockMappings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -47,12 +47,6 @@ public class BlockMappings { NbtList bedrockBlockStates; - /** - * Contains a map of Java blocks to their respective Bedrock block tag, if the Java identifier is different from Bedrock. - * Required to fix villager trades with these blocks. - */ - Map javaIdentifierToBedrockTag; - int commandBlockRuntimeId; Object2IntMap itemFrames; @@ -74,13 +68,4 @@ public class BlockMappings { public boolean isItemFrame(int bedrockBlockRuntimeId) { return this.itemFrames.values().contains(bedrockBlockRuntimeId); } - - /** - * @param cleanJavaIdentifier the clean Java identifier of the block to look up - * - * @return the block tag of the block name mapped from Java to Bedrock. - */ - public NbtMap getBedrockBlockNbt(String cleanJavaIdentifier) { - return this.javaIdentifierToBedrockTag.get(cleanJavaIdentifier); - } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java b/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java index ce8b6abc5..970e128a4 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/EnchantmentData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java index 56d7825cc..9d06fd3a9 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/GeyserMappingItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -44,4 +44,6 @@ public class GeyserMappingItem { @JsonProperty("tool_tier") String toolTier; @JsonProperty("max_damage") int maxDamage = 0; @JsonProperty("repair_materials") List repairMaterials; + @JsonProperty("has_suspicious_stew_effect") boolean hasSuspiciousStewEffect = false; + @JsonProperty("dye_color") int dyeColor = -1; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java index 178ebd607..28d41ba46 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -39,7 +39,7 @@ import java.util.Set; public class ItemMapping { public static final ItemMapping AIR = new ItemMapping("minecraft:air", "minecraft:air", 0, 0, 0, BlockRegistries.BLOCKS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()).getBedrockAirId(), - 64, null, null, null, 0, null); + 64, null, null, null, 0, null, false); String javaIdentifier; String bedrockIdentifier; @@ -63,6 +63,8 @@ public class ItemMapping { Set repairMaterials; + boolean hasSuspiciousStewEffect; + /** * Gets if this item is a block. * diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java index a246cdcf3..3072568f3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/ItemMappings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,13 +29,13 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.nukkitx.protocol.bedrock.data.inventory.ComponentItemData; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.IntList; import lombok.Builder; import lombok.Value; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.inventory.item.StoredItemMappings; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.List; import java.util.Map; @@ -48,7 +48,12 @@ public class ItemMappings { Map cachedJavaMappings = new WeakHashMap<>(); - Int2ObjectMap items; + ItemMapping[] items; + + /** + * A unique exception as this is an item in Bedrock, but not in Java. + */ + ItemMapping lodestoneCompass; ItemData[] creativeItems; List itemEntries; @@ -70,6 +75,7 @@ public class ItemMappings { * @param itemStack the itemstack * @return an item entry from the given java edition identifier */ + @Nonnull public ItemMapping getMapping(ItemStack itemStack) { return this.getMapping(itemStack.getId()); } @@ -81,8 +87,9 @@ public class ItemMappings { * @param javaId the id * @return an item entry from the given java edition identifier */ + @Nonnull public ItemMapping getMapping(int javaId) { - return this.items.get(javaId); + return javaId >= 0 && javaId < this.items.length ? this.items[javaId] : ItemMapping.AIR; } /** @@ -94,7 +101,7 @@ public class ItemMappings { */ public ItemMapping getMapping(String javaIdentifier) { return this.cachedJavaMappings.computeIfAbsent(javaIdentifier, key -> { - for (ItemMapping mapping : this.items.values()) { + for (ItemMapping mapping : this.items) { if (mapping.getJavaIdentifier().equals(key)) { return mapping; } @@ -110,11 +117,18 @@ public class ItemMappings { * @return an item entry from the given item data */ public ItemMapping getMapping(ItemData data) { + int id = data.getId(); + if (id == 0) { + return ItemMapping.AIR; + } else if (id == lodestoneCompass.getBedrockId()) { + return lodestoneCompass; + } + boolean isBlock = data.getBlockRuntimeId() != 0; boolean hasDamage = data.getDamage() != 0; - for (ItemMapping mapping : this.items.values()) { - if (mapping.getBedrockId() == data.getId()) { + for (ItemMapping mapping : this.items) { + if (mapping.getBedrockId() == id) { if (isBlock && !hasDamage) { // Pre-1.16.220 will not use block runtime IDs at all, so we shouldn't check either if (data.getBlockRuntimeId() != mapping.getBedrockBlockId()) { continue; @@ -135,7 +149,7 @@ public class ItemMappings { } // This will hide the message when the player clicks with an empty hand - if (data.getId() != 0 && data.getDamage() != 0) { + if (id != 0 && data.getDamage() != 0) { GeyserImpl.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); } return ItemMapping.AIR; diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java b/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java index c7815c055..bf202ddb3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/PaletteItem.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 cd5ad17ce..71feee3de 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java b/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java index d6aaf9bd0..27b5e631d 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java +++ b/core/src/main/java/org/geysermc/geyser/registry/type/SoundMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,10 +38,10 @@ public class SoundMapping { public SoundMapping(String java, String bedrock, String playsound, int extraData, String identifier, boolean levelEvent) { this.java = java; - this.bedrock = bedrock == null || bedrock.equalsIgnoreCase("") ? null : bedrock; - this.playsound = playsound == null || playsound.equalsIgnoreCase("") ? null : playsound; + this.bedrock = bedrock == null || bedrock.isEmpty() ? null : bedrock; + this.playsound = playsound == null || playsound.isEmpty() ? null : playsound; this.extraData = extraData; - this.identifier = identifier == null || identifier.equalsIgnoreCase("") ? ":" : identifier; + this.identifier = identifier == null || identifier.isEmpty() ? ":" : identifier; this.levelEvent = levelEvent; } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java index 31407b77d..688666c73 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Objective.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java index fe8674d1a..53537137f 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Score.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 2d7f2373f..a6e80a375 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Scoreboard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java index 80a4491ba..45ae7eff2 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/ScoreboardUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 b2fb44d34..d7840627f 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/UpdateType.java b/core/src/main/java/org/geysermc/geyser/scoreboard/UpdateType.java index 3366b08f8..9120412d8 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/UpdateType.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/UpdateType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 2e3368356..c18562c88 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,8 +25,8 @@ package org.geysermc.geyser.session; +import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.auth.data.GameProfile; -import com.github.steveice10.mc.auth.exception.request.AuthPendingException; import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.auth.service.AuthenticationService; @@ -34,18 +34,28 @@ import com.github.steveice10.mc.auth.service.MojangAuthenticationService; import com.github.steveice10.mc.auth.service.MsaAuthenticationService; import com.github.steveice10.mc.protocol.MinecraftConstants; import com.github.steveice10.mc.protocol.MinecraftProtocol; +import com.github.steveice10.mc.protocol.codec.MinecraftCodecHelper; import com.github.steveice10.mc.protocol.data.ProtocolState; import com.github.steveice10.mc.protocol.data.UnexpectedEncryptionException; +import com.github.steveice10.mc.protocol.data.game.MessageType; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Pose; +import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; +import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; +import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; +import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic; import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryPacket; import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Session; @@ -55,28 +65,33 @@ import com.github.steveice10.packetlib.tcp.TcpClientSession; import com.github.steveice10.packetlib.tcp.TcpSession; import com.nukkitx.math.GenericMath; import com.nukkitx.math.vector.*; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.BedrockServerSession; import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.data.command.CommandPermission; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.packet.*; -import com.nukkitx.protocol.bedrock.v471.Bedrock_v471; import io.netty.channel.Channel; import io.netty.channel.EventLoop; -import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.bytes.ByteArrays; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIterator; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.AccessLevel; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.common.value.qual.IntRange; import org.geysermc.common.PlatformType; -import org.geysermc.cumulus.Form; -import org.geysermc.cumulus.util.FormBuilder; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.util.FormBuilder; import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.geyser.Constants; @@ -84,20 +99,22 @@ import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.connection.GeyserConnection; import org.geysermc.geyser.command.CommandSender; import org.geysermc.geyser.configuration.EmoteOffhandWorkaroundOption; -import org.geysermc.geyser.entity.InteractiveTagManager; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; 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.entity.type.player.SkullPlayerEntity; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; +import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.WorldManager; import org.geysermc.geyser.level.physics.CollisionManager; import org.geysermc.geyser.network.netty.LocalSession; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMappings; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.AuthType; @@ -106,20 +123,19 @@ import org.geysermc.geyser.session.cache.*; import org.geysermc.geyser.skin.FloodgateSkinUploader; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.text.TextDecoration; import org.geysermc.geyser.translator.inventory.InventoryTranslator; 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.geysermc.geyser.util.MathUtils; +import org.geysermc.geyser.util.*; +import javax.annotation.Nonnull; import java.net.ConnectException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -127,18 +143,23 @@ import java.util.concurrent.atomic.AtomicInteger; @Getter public class GeyserSession implements GeyserConnection, CommandSender { - private final GeyserImpl geyser; - private final UpstreamSession upstream; + private final @Nonnull GeyserImpl geyser; + private final @Nonnull UpstreamSession upstream; /** * The loop where all packets and ticking is processed to prevent concurrency issues. * If this is manually called, ensure that any exceptions are properly handled. */ - private final EventLoop eventLoop; + private final @Nonnull EventLoop eventLoop; private TcpSession downstream; @Setter private AuthData authData; @Setter private BedrockClientData clientData; + /** + * Used for Floodgate skin uploading + */ + @Setter + private JsonNode certChainData; /* Setter for GeyserConnect */ @Setter @@ -164,10 +185,12 @@ public class GeyserSession implements GeyserConnection, CommandSender { private final LodestoneCache lodestoneCache; private final PistonCache pistonCache; private final PreferencesCache preferencesCache; + private final SkullCache skullCache; private final TagCache tagCache; private final WorldCache worldCache; - private final Int2ObjectMap teleportMap = new Int2ObjectOpenHashMap<>(); + @Setter + private TeleportCache unconfirmedTeleport; private final WorldBorder worldBorder; /** @@ -210,7 +233,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private ItemMappings itemMappings; - private final Map skullCache = new Object2ObjectOpenHashMap<>(); private final Long2ObjectMap storedMaps = new Long2ObjectOpenHashMap<>(); /** @@ -247,7 +269,9 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private Vector2i lastChunkPosition = null; - private int renderDistance; + @Setter + private int clientRenderDistance = -1; + private int serverRenderDistance; // Exposed for GeyserConnect usage protected boolean sentSpawnPacket; @@ -304,6 +328,15 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ @Setter private String dimension = DimensionUtils.OVERWORLD; + @MonotonicNonNull + @Setter + private JavaDimension dimensionType = null; + /** + * All dimensions that the client could possibly connect to. + */ + private final Map dimensions = new Object2ObjectOpenHashMap<>(3); + + private final Map chatTypes = new EnumMap<>(MessageType.class); @Setter private int breakingBlock; @@ -333,9 +366,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private Vector3f lastInteractionPlayerPosition = Vector3f.ZERO; - @Setter - private Entity ridingVehicleEntity; - /** * The entity that the client is currently looking at. */ @@ -343,8 +373,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { private Entity mouseoverEntity; @Setter - private Int2ObjectMap craftingRecipes; - private final Set unlockedRecipes; + private Int2ObjectMap craftingRecipes; private final AtomicInteger lastRecipeNetId; /** @@ -352,7 +381,21 @@ public class GeyserSession implements GeyserConnection, CommandSender { * The key is the Java ID of the item; the values are all the possible outputs' Java IDs sorted by their string identifier */ @Setter - private Int2ObjectMap stonecutterRecipes; + private Int2ObjectMap stonecutterRecipes; + + /** + * Whether to work around 1.13's different behavior in villager trading menus. + */ + @Setter + private boolean emulatePost1_14Logic = true; + /** + * Starting in 1.17, Java servers expect the carriedItem parameter of the serverbound click container + * packet to be the current contents of the mouse after the transaction has been done. 1.16 expects the clicked slot + * contents before any transaction is done. With the current ViaVersion structure, if we do not send what 1.16 expects + * and send multiple click container packets, then successive transactions will be rejected. + */ + @Setter + private boolean emulatePost1_16Logic = true; /** * The current attack speed of the player. Used for sending proper cooldown timings. @@ -404,6 +447,13 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private long lastVehicleMoveTimestamp = System.currentTimeMillis(); + /** + * Counts how many ticks have occurred since an arm animation started. + * -1 means there is no active arm swing. + */ + @Getter(AccessLevel.NONE) + private int armAnimationTicks = -1; + /** * Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless. */ @@ -428,6 +478,9 @@ public class GeyserSession implements GeyserConnection, CommandSender { */ private boolean flying = false; + @Setter + private boolean instabuild = false; + /** * Caches current rain status. */ @@ -440,15 +493,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Setter private boolean thunder = false; - /** - * Stores the last text inputted into a sign. - *

- * Bedrock sends packets every time you update the sign, Java only wants the final packet. - * Until we determine that the user has finished editing, we save the sign's current status. - */ - @Setter - private String lastSignMessage; - /** * Stores a map of all statistics sent from the server. * The server only sends new statistics back to us, so in order to show all statistics we need to cache existing ones. @@ -492,6 +536,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.lodestoneCache = new LodestoneCache(); this.pistonCache = new PistonCache(this); this.preferencesCache = new PreferencesCache(this); + this.skullCache = new SkullCache(this); this.tagCache = new TagCache(); this.worldCache = new WorldCache(this); @@ -505,7 +550,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.playerInventory = new PlayerInventory(); this.openInventory = null; this.craftingRecipes = new Int2ObjectOpenHashMap<>(); - this.unlockedRecipes = new ObjectOpenHashSet<>(); this.lastRecipeNetId = new AtomicInteger(1); this.spawned = false; @@ -526,11 +570,14 @@ public class GeyserSession implements GeyserConnection, CommandSender { } bedrockServerSession.addDisconnectHandler(disconnectReason -> { - InetAddress address = bedrockServerSession.getRealAddress().getAddress(); - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.disconnect", address, disconnectReason)); + String message = switch (disconnectReason) { + // A generic message that just means the player quit normally. + case CLOSED_BY_REMOTE_PEER -> GeyserLocale.getLocaleStringLog("geyser.network.disconnect.closed_by_remote_peer"); + case TIMED_OUT -> GeyserLocale.getLocaleStringLog("geyser.network.disconnect.timed_out"); + default -> disconnectReason.name(); + }; - disconnect(disconnectReason.name()); - geyser.getSessionManager().removeSession(this); + disconnect(message); }); this.remoteAddress = geyser.getConfig().getRemote().getAddress(); @@ -592,17 +639,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { upstream.sendPacket(gamerulePacket); } - public void login() { - if (this.remoteAuthType != AuthType.ONLINE) { - if (this.remoteAuthType == AuthType.OFFLINE) { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.offline")); - } else { - geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.floodgate")); - } - authenticate(authData.name()); - } - } - public void authenticate(String username) { authenticate(username, ""); } @@ -616,7 +652,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { loggingIn = true; // Use a future to prevent timeouts as all the authentication is handled sync - // This will be changed with the new protocol library. CompletableFuture.supplyAsync(() -> { try { if (password != null && !password.isEmpty()) { @@ -673,10 +708,58 @@ public class GeyserSession implements GeyserConnection, CommandSender { }); } + public void authenticateWithRefreshToken(String refreshToken) { + if (loggedIn) { + geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", getAuthData().name())); + return; + } + + loggingIn = true; + + CompletableFuture.supplyAsync(() -> { + MsaAuthenticationService service = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID); + service.setRefreshToken(refreshToken); + try { + service.login(); + } catch (RequestException e) { + geyser.getLogger().error("Error while attempting to use refresh token for " + name() + "!", e); + return Boolean.FALSE; + } + + GameProfile profile = service.getSelectedProfile(); + if (profile == null) { + // Java account is offline + disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); + return null; + } + + protocol = new MinecraftProtocol(profile, service.getAccessToken()); + geyser.saveRefreshToken(name(), service.getRefreshToken()); + return Boolean.TRUE; + }).whenComplete((successful, ex) -> { + if (this.closed) { + return; + } + if (successful == Boolean.FALSE) { + // The player is waiting for a spawn packet, so let's spawn them in now to show them forms + connect(); + // Will be cached for after login + LoginEncryptionUtils.buildAndShowTokenExpiredWindow(this); + return; + } + + connectDownstream(); + }); + } + + public void authenticateWithMicrosoftCode() { + authenticateWithMicrosoftCode(false); + } + /** * Present a form window to the user asking to log in with another web browser */ - public void authenticateWithMicrosoftCode() { + public void authenticateWithMicrosoftCode(boolean offlineAccess) { if (loggedIn) { geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", getAuthData().name())); return; @@ -689,65 +772,64 @@ public class GeyserSession implements GeyserConnection, CommandSender { packet.setTime(16000); sendUpstreamPacket(packet); - // new thread so clients don't timeout - MsaAuthenticationService msaAuthenticationService = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID); + final PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getOrCreateTask( + getAuthData().xuid() + ); + task.setOnline(true); + task.resetTimer(); - // Use a future to prevent timeouts as all the authentication is handled sync - // This will be changed with the new protocol library. - CompletableFuture.supplyAsync(() -> { - try { - return msaAuthenticationService.getAuthCode(); - } catch (RequestException e) { - throw new CompletionException(e); - } - }).whenComplete((response, ex) -> { - if (ex != null) { - ex.printStackTrace(); - disconnect(ex.toString()); - return; - } - LoginEncryptionUtils.buildAndShowMicrosoftCodeWindow(this, response); - attemptCodeAuthentication(msaAuthenticationService); - }); + if (task.getAuthentication().isDone()) { + onMicrosoftLoginComplete(task); + } else { + task.getCode(offlineAccess).whenComplete((response, ex) -> { + boolean connected = !closed; + if (ex != null) { + if (connected) { + geyser.getLogger().error("Failed to get Microsoft auth code", ex); + disconnect(ex.toString()); + } + task.cleanup(); // error getting auth code -> clean up immediately + } else if (connected) { + LoginEncryptionUtils.buildAndShowMicrosoftCodeWindow(this, response); + task.getAuthentication().whenComplete((r, $) -> onMicrosoftLoginComplete(task)); + } + }); + } } /** - * Poll every second to see if the user has successfully signed in + * If successful, also begins connecting to the Java server. */ - private void attemptCodeAuthentication(MsaAuthenticationService msaAuthenticationService) { - if (loggedIn || closed) { - return; + public boolean onMicrosoftLoginComplete(PendingMicrosoftAuthentication.AuthenticationTask task) { + if (closed) { + return false; } - CompletableFuture.supplyAsync(() -> { - try { - msaAuthenticationService.login(); - GameProfile profile = msaAuthenticationService.getSelectedProfile(); - if (profile == null) { - // Java account is offline - disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); - return null; - } - - return new MinecraftProtocol(profile, msaAuthenticationService.getAccessToken()); - } catch (RequestException e) { - throw new CompletionException(e); - } - }).whenComplete((response, ex) -> { - if (ex != null) { - if (!(ex instanceof CompletionException completionException) || !(completionException.getCause() instanceof AuthPendingException)) { - geyser.getLogger().error("Failed to log in with Microsoft code!", ex); - disconnect(ex.toString()); - } else { - // Wait one second before trying again - geyser.getScheduledThread().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS); - } - return; - } - if (!closed) { - this.protocol = response; + task.cleanup(); // player is online -> remove pending authentication immediately + Throwable ex = task.getLoginException(); + if (ex != null) { + geyser.getLogger().error("Failed to log in with Microsoft code!", ex); + disconnect(ex.toString()); + } else { + MsaAuthenticationService service = task.getMsaAuthenticationService(); + GameProfile selectedProfile = service.getSelectedProfile(); + if (selectedProfile == null) { + disconnect(GeyserLocale.getPlayerLocaleString( + "geyser.network.remote.invalid_account", + clientData.getLanguageCode() + )); + } else { + this.protocol = new MinecraftProtocol( + selectedProfile, + service.getAccessToken() + ); connectDownstream(); + + // Save our refresh token for later use + geyser.saveRefreshToken(name(), service.getRefreshToken()); + return true; } - }); + } + return false; } /** @@ -762,7 +844,8 @@ public class GeyserSession implements GeyserConnection, CommandSender { if (geyser.getBootstrap().getSocketAddress() != null) { // We're going to connect through the JVM and not through TCP downstream = new LocalSession(this.remoteAddress, this.remotePort, - geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), this.protocol); + geyser.getBootstrap().getSocketAddress(), upstream.getAddress().getAddress().getHostAddress(), + this.protocol, this.protocol.createHelper()); } else { downstream = new TcpClientSession(this.remoteAddress, this.remotePort, this.protocol); disableSrvResolving(); @@ -789,6 +872,13 @@ public class GeyserSession implements GeyserConnection, CommandSender { FloodgateSkinUploader skinUploader = geyser.getSkinUploader(); FloodgateCipher cipher = geyser.getCipher(); + String bedrockAddress = upstream.getAddress().getAddress().getHostAddress(); + // both BungeeCord and Velocity remove the IPv6 scope (if there is one) for Spigot + int ipv6ScopeIndex = bedrockAddress.indexOf('%'); + if (ipv6ScopeIndex != -1) { + bedrockAddress = bedrockAddress.substring(0, ipv6ScopeIndex); + } + encryptedData = cipher.encryptFromString(BedrockData.of( clientData.getGameVersion(), authData.name(), @@ -797,7 +887,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { clientData.getLanguageCode(), clientData.getUiProfile().ordinal(), clientData.getCurrentInputMode().ordinal(), - upstream.getAddress().getAddress().getHostAddress(), + bedrockAddress, skinUploader.getId(), skinUploader.getVerifyCode() ).toString()); @@ -927,7 +1017,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { setDaylightCycle(true); } - downstream.connect(); + downstream.connect(false); } public void disconnect(String reason) { @@ -935,11 +1025,22 @@ public class GeyserSession implements GeyserConnection, CommandSender { loggedIn = false; if (downstream != null) { downstream.disconnect(reason); + } else { + // Downstream's disconnect will fire an event that prints a log message + // Otherwise, we print a message here + InetAddress address = upstream.getAddress().getAddress(); + geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.network.disconnect", address, reason)); } - if (upstream != null && !upstream.isClosed()) { - geyser.getSessionManager().removeSession(this); + if (!upstream.isClosed()) { upstream.disconnect(reason); } + geyser.getSessionManager().removeSession(this); + if (authData != null) { + PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(authData.xuid()); + if (task != null) { + task.setOnline(false); + } + } } if (tickThread != null) { @@ -949,10 +1050,6 @@ public class GeyserSession implements GeyserConnection, CommandSender { closed = true; } - public void close() { - disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.close", getClientData().getLanguageCode())); - } - /** * Executes a task and prints a stack trace if an error occurs. */ @@ -1002,15 +1099,17 @@ public class GeyserSession implements GeyserConnection, CommandSender { worldBorder.resize(); } - if (!worldBorder.isWithinWarningBoundaries()) { + boolean shouldShowFog = !worldBorder.isWithinWarningBoundaries(); + if (shouldShowFog || worldBorder.isCloseToBorderBoundaries()) { // Show particles representing where the world border is worldBorder.drawWall(); // Set the mood - if (!isInWorldBorderWarningArea) { + if (shouldShowFog && !isInWorldBorderWarningArea) { isInWorldBorderWarningArea = true; sendFog("minecraft:fog_crimson_forest"); } - } else if (isInWorldBorderWarningArea) { + } + if (!shouldShowFog && isInWorldBorderWarningArea) { // Clear fog as we are outside the world border now removeFog("minecraft:fog_crimson_forest"); isInWorldBorderWarningArea = false; @@ -1020,6 +1119,34 @@ public class GeyserSession implements GeyserConnection, CommandSender { for (Tickable entity : entityCache.getTickableEntities()) { entity.tick(); } + + if (armAnimationTicks != -1) { + // As of 1.18.2 Java Edition, it appears that the swing time is dynamically updated depending on the + // player's effect status, but the animation can cut short if the duration suddenly decreases + // (from suddenly no longer having mining fatigue, for example) + // This math is referenced from Java Edition 1.18.2 + int swingTotalDuration; + int hasteLevel = Math.max(effectCache.getHaste(), effectCache.getConduitPower()); + if (hasteLevel > 0) { + swingTotalDuration = 6 - hasteLevel; + } else { + int miningFatigueLevel = effectCache.getMiningFatigue(); + if (miningFatigueLevel > 0) { + swingTotalDuration = 6 + miningFatigueLevel * 2; + } else { + swingTotalDuration = 6; + } + } + if (++armAnimationTicks >= swingTotalDuration) { + if (sneaking) { + // Attempt to re-activate blocking as our swing animation is up + if (attemptToBlock()) { + playerEntity.updateBedrockMetadata(); + } + } + armAnimationTicks = -1; + } + } } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -1029,7 +1156,23 @@ public class GeyserSession implements GeyserConnection, CommandSender { this.authData = authData; } - public void setSneaking(boolean sneaking) { + public void startSneaking() { + // Toggle the shield, if there is no ongoing arm animation + // This matches Bedrock Edition behavior as of 1.18.12 + if (armAnimationTicks == -1) { + attemptToBlock(); + } + + setSneaking(true); + } + + public void stopSneaking() { + disableBlocking(); + + setSneaking(false); + } + + private void setSneaking(boolean sneaking) { this.sneaking = sneaking; // Update pose and bounding box on our end @@ -1053,21 +1196,29 @@ public class GeyserSession implements GeyserConnection, CommandSender { if (mouseoverEntity != null) { // Horses, etc can change their property depending on if you're sneaking - InteractiveTagManager.updateTag(this, mouseoverEntity); + mouseoverEntity.updateInteractiveTag(); } } private void setSneakingPose(boolean sneaking) { - this.pose = sneaking ? Pose.SNEAKING : Pose.STANDING; - playerEntity.setBoundingBoxHeight(sneaking ? 1.5f : playerEntity.getDefinition().height()); + if (this.pose == Pose.SNEAKING && !sneaking) { + this.pose = Pose.STANDING; + playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height()); + } else if (sneaking) { + this.pose = Pose.SNEAKING; + playerEntity.setBoundingBoxHeight(1.5f); + } playerEntity.setFlag(EntityFlag.SNEAKING, sneaking); - - collisionManager.updatePlayerBoundingBox(); } public void setSwimming(boolean swimming) { - this.pose = swimming ? Pose.SWIMMING : Pose.STANDING; - playerEntity.setBoundingBoxHeight(swimming ? 0.6f : playerEntity.getDefinition().height()); + if (swimming) { + this.pose = Pose.SWIMMING; + playerEntity.setBoundingBoxHeight(0.6f); + } else { + this.pose = Pose.STANDING; + playerEntity.setBoundingBoxHeight(playerEntity.getDefinition().height()); + } playerEntity.setFlag(EntityFlag.SWIMMING, swimming); playerEntity.updateBedrockMetadata(); } @@ -1090,7 +1241,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { public AttributeData adjustSpeed() { AttributeData currentPlayerSpeed = playerEntity.getAttributes().get(GeyserAttributeType.MOVEMENT_SPEED); if (currentPlayerSpeed != null) { - if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.isUnderSlab()) || + if ((pose.equals(Pose.SNEAKING) && !sneaking && collisionManager.mustPlayerSneakHere()) || (!swimmingInWater && playerEntity.getFlag(EntityFlag.SWIMMING) && !collisionManager.isPlayerInWater())) { // Either of those conditions means that Bedrock goes zoom when they shouldn't be AttributeData speedAttribute = GeyserAttributeType.MOVEMENT_SPEED.getAttribute(originalSpeedAttribute / 3.32f); @@ -1106,6 +1257,54 @@ public class GeyserSession implements GeyserConnection, CommandSender { return null; } + /** + * Checks to see if a shield is in either hand to activate blocking. If so, it sets the Bedrock client to display + * blocking and sends a packet to the Java server. + */ + private boolean attemptToBlock() { + ItemMapping shield = itemMappings.getStoredItems().shield(); + + ServerboundUseItemPacket useItemPacket; + if (playerInventory.getItemInHand().getJavaId() == shield.getJavaId()) { + useItemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, getNextSequence()); + } else if (playerInventory.getOffhand().getJavaId() == shield.getJavaId()) { + useItemPacket = new ServerboundUseItemPacket(Hand.OFF_HAND, getNextSequence()); + } else { + // No blocking + return false; + } + + sendDownstreamPacket(useItemPacket); + playerEntity.setFlag(EntityFlag.BLOCKING, true); + // Metadata should be updated later + return true; + } + + /** + * Starts ticking the amount of time that the Bedrock client has been swinging their arm, and disables blocking if + * blocking. + */ + public void activateArmAnimationTicking() { + armAnimationTicks = 0; + if (disableBlocking()) { + playerEntity.updateBedrockMetadata(); + } + } + + /** + * Indicates to the client to stop blocking and tells the Java server the same. + */ + private boolean disableBlocking() { + if (playerEntity.getFlag(EntityFlag.BLOCKING)) { + ServerboundPlayerActionPacket releaseItemPacket = new ServerboundPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, + Vector3i.ZERO, Direction.DOWN, getNextSequence()); + sendDownstreamPacket(releaseItemPacket); + playerEntity.setFlag(EntityFlag.BLOCKING, false); + return true; + } + return false; + } + /** * Will be overwritten for GeyserConnect. */ @@ -1128,6 +1327,21 @@ public class GeyserSession implements GeyserConnection, CommandSender { return authData.xuid(); } + @SuppressWarnings("ConstantConditions") // Need to enforce the parameter annotations + @Override + public boolean transfer(@NonNull String address, @IntRange(from = 0, to = 65535) int port) { + if (address == null || address.isBlank()) { + throw new IllegalArgumentException("Server address cannot be null or blank"); + } else if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Server port must be between 0 and 65535, was " + port); + } + TransferPacket transferPacket = new TransferPacket(); + transferPacket.setAddress(address); + transferPacket.setPort(port); + sendUpstreamPacket(transferPacket); + return true; + } + @Override public void sendMessage(String message) { TextPacket textPacket = new TextPacket(); @@ -1149,11 +1363,25 @@ public class GeyserSession implements GeyserConnection, CommandSender { @Override public String getLocale() { return clientData.getLanguageCode(); - } + } - public void setRenderDistance(int renderDistance) { + /** + * Sends a chat message to the Java server. + */ + public void sendChat(String message) { + sendDownstreamPacket(new ServerboundChatPacket(message, Instant.now().toEpochMilli(), 0L, ByteArrays.EMPTY_ARRAY, false)); + } + + /** + * Sends a command to the Java server. + */ + public void sendCommand(String command) { + sendDownstreamPacket(new ServerboundChatCommandPacket(command, Instant.now().toEpochMilli(), 0L, Collections.emptyMap(), false)); + } + + public void setServerRenderDistance(int renderDistance) { renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle - this.renderDistance = renderDistance; + this.serverRenderDistance = renderDistance; ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); chunkRadiusUpdatedPacket.setRadius(renderDistance); @@ -1168,10 +1396,26 @@ public class GeyserSession implements GeyserConnection, CommandSender { formCache.showForm(form); } - public void sendForm(FormBuilder formBuilder) { + public void sendForm(FormBuilder formBuilder) { formCache.showForm(formBuilder.build()); } + /** + * @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead. + */ + @Deprecated + public void sendForm(org.geysermc.cumulus.Form form) { + sendForm(form.newForm()); + } + + /** + * @deprecated since Cumulus version 1.1, and will be removed when Cumulus 2.0 releases. Please use the new forms instead. + */ + @Deprecated + public void sendForm(org.geysermc.cumulus.util.FormBuilder formBuilder) { + sendForm(formBuilder.build()); + } + private void startGame() { StartGamePacket startGamePacket = new StartGamePacket(); startGamePacket.setUniqueEntityId(playerEntity.getGeyserId()); @@ -1184,7 +1428,7 @@ public class GeyserSession implements GeyserConnection, CommandSender { startGamePacket.setPlayerPosition(Vector3f.from(0, 69, 0)); startGamePacket.setRotation(Vector2f.from(1, 1)); - startGamePacket.setSeed(-1); + startGamePacket.setSeed(-1L); startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension)); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGameType(GameType.SURVIVAL); @@ -1227,16 +1471,15 @@ public class GeyserSession implements GeyserConnection, CommandSender { startGamePacket.setInventoriesServerAuthoritative(true); startGamePacket.setServerEngine(""); // Do we want to fill this in? + startGamePacket.setPlayerPropertyData(NbtMap.EMPTY); + startGamePacket.setWorldTemplateId(UUID.randomUUID()); + SyncedPlayerMovementSettings settings = new SyncedPlayerMovementSettings(); settings.setMovementMode(AuthoritativeMovementMode.CLIENT); settings.setRewindHistorySize(0); settings.setServerAuthoritativeBlockBreaking(false); startGamePacket.setPlayerMovementSettings(settings); - if (upstream.getProtocolVersion() <= Bedrock_v471.V471_CODEC.getProtocolVersion()) { - startGamePacket.getExperiments().add(new ExperimentData("caves_and_cliffs", true)); - } - upstream.sendPacket(startGamePacket); } @@ -1247,73 +1490,23 @@ public class GeyserSession implements GeyserConnection, CommandSender { return itemNetId.getAndIncrement(); } - public void addTeleport(TeleportCache teleportCache) { - teleportMap.put(teleportCache.getTeleportConfirmId(), teleportCache); - - ObjectIterator> it = teleportMap.int2ObjectEntrySet().iterator(); - - // Remove any teleports with a higher number - maybe this is a world change that reset the ID to 0? - while (it.hasNext()) { - Int2ObjectMap.Entry entry = it.next(); - int nextID = entry.getValue().getTeleportConfirmId(); - if (nextID > teleportCache.getTeleportConfirmId()) { - it.remove(); - } - } - } - public void confirmTeleport(Vector3d position) { - if (teleportMap.size() == 0) { + if (unconfirmedTeleport == null) { return; } - int teleportID = -1; - for (Int2ObjectMap.Entry entry : teleportMap.int2ObjectEntrySet()) { - if (entry.getValue().canConfirm(position)) { - if (entry.getValue().getTeleportConfirmId() > teleportID) { - teleportID = entry.getValue().getTeleportConfirmId(); - } - } + if (unconfirmedTeleport.canConfirm(position)) { + unconfirmedTeleport = null; + return; } - if (teleportID != -1) { - ObjectIterator> it = teleportMap.int2ObjectEntrySet().iterator(); - - // Confirm the current teleport and any earlier ones - while (it.hasNext()) { - TeleportCache entry = it.next().getValue(); - int nextID = entry.getTeleportConfirmId(); - if (nextID <= teleportID) { - ServerboundAcceptTeleportationPacket teleportConfirmPacket = new ServerboundAcceptTeleportationPacket(nextID); - sendDownstreamPacket(teleportConfirmPacket); - // Servers (especially ones like Hypixel) expect exact coordinates given back to them. - ServerboundMovePlayerPosRotPacket positionPacket = new ServerboundMovePlayerPosRotPacket(playerEntity.isOnGround(), - entry.getX(), entry.getY(), entry.getZ(), entry.getYaw(), entry.getPitch()); - sendDownstreamPacket(positionPacket); - it.remove(); - geyser.getLogger().debug("Confirmed teleport " + nextID); - } - } - } - - if (teleportMap.size() > 0) { - int resendID = -1; - for (Int2ObjectMap.Entry entry : teleportMap.int2ObjectEntrySet()) { - TeleportCache teleport = entry.getValue(); - teleport.incrementUnconfirmedFor(); - if (teleport.shouldResend()) { - if (teleport.getTeleportConfirmId() >= resendID) { - resendID = teleport.getTeleportConfirmId(); - } - } - } - - if (resendID != -1) { - geyser.getLogger().debug("Resending teleport " + resendID); - TeleportCache teleport = teleportMap.get(resendID); - getPlayerEntity().moveAbsolute(Vector3f.from(teleport.getX(), teleport.getY(), teleport.getZ()), - teleport.getYaw(), teleport.getPitch(), playerEntity.isOnGround(), true); - } + // Resend the teleport every few packets until Bedrock responds + unconfirmedTeleport.incrementUnconfirmedFor(); + if (unconfirmedTeleport.shouldResend()) { + unconfirmedTeleport.resetUnconfirmedFor(); + geyser.getLogger().debug("Resending teleport " + unconfirmedTeleport.getTeleportConfirmId()); + getPlayerEntity().moveAbsolute(Vector3f.from(unconfirmedTeleport.getX(), unconfirmedTeleport.getY(), unconfirmedTeleport.getZ()), + unconfirmedTeleport.getYaw(), unconfirmedTeleport.getPitch(), playerEntity.isOnGround(), true); } } @@ -1461,6 +1654,31 @@ public class GeyserSession implements GeyserConnection, CommandSender { sendUpstreamPacket(adventureSettingsPacket); } + private int getRenderDistance() { + if (clientRenderDistance != -1) { + // The client has sent a render distance + return clientRenderDistance; + } + return serverRenderDistance; + } + + // We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc + private static final List SKIN_PARTS = Arrays.asList(SkinPart.values()); + + /** + * Send a packet to the server to indicate client render distance, locale, skin parts, and hand preference. + */ + public void sendJavaClientSettings() { + ServerboundClientInformationPacket clientSettingsPacket = new ServerboundClientInformationPacket(getLocale(), + getRenderDistance(), ChatVisibility.FULL, true, SKIN_PARTS, + HandPreference.RIGHT_HAND, false, true); + sendDownstreamPacket(clientSettingsPacket); + } + + public int getNextSequence() { + return 0; + } + /** * Used for updating statistic values since we only get changes from the server * @@ -1524,4 +1742,21 @@ public class GeyserSession implements GeyserConnection, CommandSender { packet.getFogStack().addAll(this.fogNameSpaces); sendUpstreamPacket(packet); } + + public boolean canUseCommandBlocks() { + return instabuild && opPermissionLevel >= 2; + } + + public void playSoundEvent(SoundEvent sound, Vector3f position) { + LevelSoundEvent2Packet packet = new LevelSoundEvent2Packet(); + packet.setPosition(position); + packet.setSound(sound); + packet.setIdentifier(":"); + packet.setExtraData(-1); + sendUpstreamPacket(packet); + } + + public MinecraftCodecHelper getCodecHelper() { + return (MinecraftCodecHelper) this.downstream.getCodecHelper(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java b/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java new file mode 100644 index 000000000..93200dcb6 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/PendingMicrosoftAuthentication.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2019-2021 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.session; + +import com.github.steveice10.mc.auth.exception.request.AuthPendingException; +import com.github.steveice10.mc.auth.exception.request.RequestException; +import com.github.steveice10.mc.auth.service.MsaAuthenticationService; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; +import lombok.SneakyThrows; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.GeyserLogger; + +import javax.annotation.Nonnull; +import java.util.concurrent.*; + +/** + * Pending Microsoft authentication task cache. + * It permits user to exit the server while they authorize Geyser to access their Microsoft account. + */ +public class PendingMicrosoftAuthentication { + /** + * For GeyserConnect usage. + */ + private boolean storeServerInformation = false; + private final LoadingCache authentications; + + public PendingMicrosoftAuthentication(int timeoutSeconds) { + this.authentications = CacheBuilder.newBuilder() + .build(new CacheLoader<>() { + @Override + public AuthenticationTask load(@NonNull String userKey) { + return storeServerInformation ? new ProxyAuthenticationTask(userKey, timeoutSeconds * 1000L) + : new AuthenticationTask(userKey, timeoutSeconds * 1000L); + } + }); + } + + public AuthenticationTask getTask(@Nonnull String userKey) { + return authentications.getIfPresent(userKey); + } + + @SneakyThrows(ExecutionException.class) + public AuthenticationTask getOrCreateTask(@Nonnull String userKey) { + return authentications.get(userKey); + } + + @SuppressWarnings("unused") // GeyserConnect + public void setStoreServerInformation() { + storeServerInformation = true; + } + + public class AuthenticationTask { + private static final Executor DELAYED_BY_ONE_SECOND = CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS); + + @Getter + private final MsaAuthenticationService msaAuthenticationService = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID); + private final String userKey; + private final long timeoutMs; + + private long remainingTimeMs; + + @Setter + private boolean online = true; + + @Getter + private final CompletableFuture authentication; + + @Getter + private volatile Throwable loginException; + + private AuthenticationTask(String userKey, long timeoutMs) { + this.userKey = userKey; + this.timeoutMs = timeoutMs; + this.remainingTimeMs = timeoutMs; + + this.authentication = new CompletableFuture<>(); + this.authentication.whenComplete((r, ex) -> { + this.loginException = ex; + // avoid memory leak, in case player doesn't connect again + CompletableFuture.delayedExecutor(timeoutMs, TimeUnit.MILLISECONDS).execute(this::cleanup); + }); + } + + public void resetTimer() { + this.remainingTimeMs = this.timeoutMs; + } + + public void cleanup() { + GeyserLogger logger = GeyserImpl.getInstance().getLogger(); + if (logger.isDebug()) { + logger.debug("Cleaning up authentication task for " + userKey); + } + authentications.invalidate(userKey); + } + + public CompletableFuture getCode(boolean offlineAccess) { + // Request the code + CompletableFuture code = CompletableFuture.supplyAsync(() -> tryGetCode(offlineAccess)); + // Once the code is received, continuously try to request the access token, profile, etc + code.thenRun(() -> performLoginAttempt(System.currentTimeMillis())); + return code; + } + + /** + * @param offlineAccess whether we want a refresh token for later use. + */ + private MsaAuthenticationService.MsCodeResponse tryGetCode(boolean offlineAccess) throws CompletionException { + try { + return msaAuthenticationService.getAuthCode(offlineAccess); + } catch (RequestException e) { + throw new CompletionException(e); + } + } + + private void performLoginAttempt(long lastAttempt) { + CompletableFuture.runAsync(() -> { + try { + msaAuthenticationService.login(); + } catch (AuthPendingException e) { + long currentAttempt = System.currentTimeMillis(); + if (!online) { + // decrement timer only when player's offline + remainingTimeMs -= currentAttempt - lastAttempt; + if (remainingTimeMs <= 0L) { + // time's up + authentication.completeExceptionally(new TaskTimeoutException()); + cleanup(); + return; + } + } + // try again in 1 second + performLoginAttempt(currentAttempt); + return; + } catch (Exception e) { + authentication.completeExceptionally(e); + return; + } + // login successful + authentication.complete(msaAuthenticationService); + }, DELAYED_BY_ONE_SECOND); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{userKey='" + userKey + "'}"; + } + } + + @Getter + @Setter + public final class ProxyAuthenticationTask extends AuthenticationTask { + private String server; + private int port; + + private ProxyAuthenticationTask(String userKey, long timeoutMs) { + super(userKey, timeoutMs); + } + } + + /** + * @see PendingMicrosoftAuthentication + */ + public static class TaskTimeoutException extends Exception { + TaskTimeoutException() { + super("It took too long to authorize Geyser to access your Microsoft account. " + + "Please request new code and try again."); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java index 5aecdf175..8cfc73d7e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/SessionManager.java +++ b/core/src/main/java/org/geysermc/geyser/session/SessionManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java index 88dc360bf..060dcc7fb 100644 --- a/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/UpstreamSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/auth/AuthData.java b/core/src/main/java/org/geysermc/geyser/session/auth/AuthData.java index d48cf3889..99b7ae3af 100644 --- a/core/src/main/java/org/geysermc/geyser/session/auth/AuthData.java +++ b/core/src/main/java/org/geysermc/geyser/session/auth/AuthData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,18 +25,7 @@ package org.geysermc.geyser.session.auth; -import com.fasterxml.jackson.databind.JsonNode; -import org.geysermc.geyser.GeyserImpl; - import java.util.UUID; -public record AuthData(String name, UUID uuid, String xuid, - JsonNode certChainData, String clientData) { - - public void upload(GeyserImpl geyser) { - // we can't upload the skin in LoginEncryptionUtil since the global server would return - // the skin too fast, that's why we upload it after we know for sure that the target server - // is ready to handle the result of the global server - geyser.getSkinUploader().uploadSkin(certChainData, clientData); - } +public record AuthData(String name, UUID uuid, String xuid) { } diff --git a/core/src/main/java/org/geysermc/geyser/session/auth/AuthType.java b/core/src/main/java/org/geysermc/geyser/session/auth/AuthType.java index 00427e7e4..1edbd0f29 100644 --- a/core/src/main/java/org/geysermc/geyser/session/auth/AuthType.java +++ b/core/src/main/java/org/geysermc/geyser/session/auth/AuthType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java b/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java index b0c0b16b0..07dd38491 100644 --- a/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java +++ b/core/src/main/java/org/geysermc/geyser/session/auth/BedrockClientData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,9 +25,11 @@ package org.geysermc.geyser.session.auth; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; +import lombok.Setter; import org.geysermc.floodgate.util.DeviceOs; import org.geysermc.floodgate.util.InputMode; import org.geysermc.floodgate.util.UiProfile; @@ -107,6 +109,10 @@ public final class BedrockClientData { @JsonProperty(value = "PlayFabId") private String playFabId; + @JsonIgnore + @Setter + private String originalString = null; + public DeviceOs getDeviceOs() { return deviceOs != null ? deviceOs : DeviceOs.UNKNOWN; } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java index b6dde975c..f5801ed2b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/AdvancementsCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,14 +29,15 @@ import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSeenAdvancementsPacket; import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.geyser.level.GeyserAdvancement; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; -import org.geysermc.cumulus.SimpleForm; -import org.geysermc.cumulus.response.SimpleFormResponse; +import org.geysermc.geyser.translator.text.MessageTranslator; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -75,38 +76,20 @@ public class AdvancementsCache { .translator(MinecraftLocale::getLocaleString, session.getLocale()) .title("gui.advancements"); - boolean hasAdvancements = false; + List rootAdvancementIds = new ArrayList<>(); for (Map.Entry advancement : storedAdvancements.entrySet()) { if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement - hasAdvancements = true; builder.button(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), session.getLocale())); + rootAdvancementIds.add(advancement.getKey()); } } - if (!hasAdvancements) { + if (rootAdvancementIds.isEmpty()) { builder.content("advancements.empty"); } - builder.responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - return; - } - - String id = ""; - - int advancementIndex = 0; - for (Map.Entry advancement : storedAdvancements.entrySet()) { - if (advancement.getValue().getParentId() == null) { // Root advancement - if (advancementIndex == response.getClickedButtonId()) { - id = advancement.getKey(); - break; - } else { - advancementIndex++; - } - } - } - + builder.validResultHandler((response) -> { + String id = rootAdvancementIds.get(response.clickedButtonId()); if (!id.equals("")) { if (id.equals(currentAdvancementCategoryId)) { // The server thinks we are already on this tab @@ -135,12 +118,16 @@ public class AdvancementsCache { .title(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language)) .content(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language)); + List visibleAdvancements = new ArrayList<>(); if (currentAdvancementCategoryId != null) { for (GeyserAdvancement advancement : storedAdvancements.values()) { - if (advancement != null) { + boolean earned = isEarned(advancement); + if (earned || !advancement.getDisplayData().isHidden()) { if (advancement.getParentId() != null && currentAdvancementCategoryId.equals(advancement.getRootId(this))) { - boolean color = isEarned(advancement) || !advancement.getDisplayData().isShowToast(); - builder.button((color ? "§6" : "") + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n'); + String color = earned ? advancement.getDisplayColor() : ""; + builder.button(color + MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()) + '\n'); + + visibleAdvancements.add(advancement); } } } @@ -148,30 +135,13 @@ public class AdvancementsCache { builder.button(GeyserLocale.getPlayerLocaleString("gui.back", language)); - builder.responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - // Indicate that we have closed the current advancement tab - session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); - return; - } + builder.closedResultHandler(() -> { + // Indicate that we have closed the current advancement tab + session.sendDownstreamPacket(new ServerboundSeenAdvancementsPacket()); - GeyserAdvancement advancement = null; - int advancementIndex = 0; - // Loop around to find the advancement that the client pressed - for (GeyserAdvancement advancementEntry : storedAdvancements.values()) { - if (advancementEntry.getParentId() != null && - currentAdvancementCategoryId.equals(advancementEntry.getRootId(this))) { - if (advancementIndex == response.getClickedButtonId()) { - advancement = advancementEntry; - break; - } else { - advancementIndex++; - } - } - } - - if (advancement != null) { + }).validResultHandler((response) -> { + if (response.getClickedButtonId() < visibleAdvancements.size()) { + GeyserAdvancement advancement = visibleAdvancements.get(response.clickedButtonId()); buildAndShowInfoForm(advancement); } else { buildAndShowMenuForm(); @@ -219,12 +189,7 @@ public class AdvancementsCache { .title(MessageTranslator.convertMessage(advancement.getDisplayData().getTitle())) .content(content) .button(GeyserLocale.getPlayerLocaleString("gui.back", language)) - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (response.isCorrect()) { - buildAndShowListForm(); - } - }) + .validResultHandler((response) -> buildAndShowListForm()) ); } @@ -266,10 +231,9 @@ public class AdvancementsCache { } public String getColorFromAdvancementFrameType(GeyserAdvancement advancement) { - String base = "\u00a7"; if (advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE) { - return base + "5"; + return ChatColor.DARK_PURPLE; } - return base + "a"; // Used for types TASK and GOAL + return ChatColor.GREEN; // Used for types TASK and GOAL } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java index faaeafdb9..e3ffa301e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BookEditCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java b/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java index 3d1e11db9..7cfeaa165 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/BossBar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java index 522c00d2a..91d6b33d6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/ChunkCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,6 +33,7 @@ import lombok.Setter; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.level.chunk.GeyserChunk; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.util.MathUtils; public class ChunkCache { @@ -45,11 +46,11 @@ public class ChunkCache { private int heightY; /** - * Whether the Bedrock client believes they are in a world with a minimum of -64 and maximum of 320 + * Which dimension Bedrock understands themselves to be in. */ @Getter @Setter - private boolean isExtendedHeight = false; + private BedrockDimension bedrockDimension = BedrockDimension.OVERWORLD; public ChunkCache(GeyserSession session) { this.cache = !session.getGeyser().getWorldManager().hasOwnChunkCache(); // To prevent Spigot from initializing diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java index 5d99ba0e3..012606615 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,8 +25,8 @@ package org.geysermc.geyser.session.cache; -import it.unimi.dsi.fastutil.longs.Long2LongMap; -import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2LongMap; +import it.unimi.dsi.fastutil.ints.Int2LongOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; @@ -53,18 +53,15 @@ public class EntityCache { * A list of all entities that must be ticked. */ private final List tickableEntities = new ObjectArrayList<>(); - private final Long2LongMap entityIdTranslations = new Long2LongOpenHashMap(); + private final Int2LongMap entityIdTranslations = new Int2LongOpenHashMap(); private final Map playerEntities = new Object2ObjectOpenHashMap<>(); private final Map bossBars = new Object2ObjectOpenHashMap<>(); - private final Long2LongMap cachedPlayerEntityLinks = new Long2LongOpenHashMap(); @Getter private final AtomicLong nextEntityId = new AtomicLong(2L); public EntityCache(GeyserSession session) { this.session = session; - - cachedPlayerEntityLinks.defaultReturnValue(-1L); } public void spawnEntity(Entity entity) { @@ -112,15 +109,16 @@ public class EntityCache { } session.getPlayerWithCustomHeads().clear(); - // As a precaution - cachedPlayerEntityLinks.clear(); } public Entity getEntityByGeyserId(long geyserId) { return entities.get(geyserId); } - public Entity getEntityByJavaId(long javaId) { + public Entity getEntityByJavaId(int javaId) { + if (javaId == session.getPlayerEntity().getEntityId()) { + return session.getPlayerEntity(); + } return entities.get(entityIdTranslations.get(javaId)); } @@ -160,14 +158,6 @@ public class EntityCache { bossBars.values().forEach(BossBar::updateBossBar); } - public long getCachedPlayerEntityLink(long playerId) { - return cachedPlayerEntityLinks.remove(playerId); - } - - public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) { - cachedPlayerEntityLinks.put(playerId, linkedEntityId); - } - public List getTickableEntities() { return tickableEntities; } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java index 95c059475..a7693e516 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityEffectCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java index 6f7d180de..24acebce0 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/FormCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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 @@ -31,33 +31,42 @@ import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import lombok.RequiredArgsConstructor; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.form.impl.FormDefinitions; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.cumulus.Form; -import org.geysermc.cumulus.SimpleForm; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; @RequiredArgsConstructor public class FormCache { - private final AtomicInteger formId = new AtomicInteger(0); + private final FormDefinitions formDefinitions = FormDefinitions.instance(); + private final AtomicInteger formIdCounter = new AtomicInteger(0); private final Int2ObjectMap

forms = new Int2ObjectOpenHashMap<>(); private final GeyserSession session; public int addForm(Form form) { - int windowId = formId.getAndIncrement(); - forms.put(windowId, form); - return windowId; + int formId = formIdCounter.getAndIncrement(); + forms.put(formId, form); + return formId; } - public int showForm(Form form) { - int windowId = addForm(form); + public void showForm(Form form) { + int formId = addForm(form); + + if (session.getUpstream().isInitialized()) { + sendForm(formId, form); + } + } + + private void sendForm(int formId, Form form) { + String jsonData = formDefinitions.codecFor(form).jsonData(form); ModalFormRequestPacket formRequestPacket = new ModalFormRequestPacket(); - formRequestPacket.setFormId(windowId); - formRequestPacket.setFormData(form.getJsonData()); + formRequestPacket.setFormId(formId); + formRequestPacket.setFormData(jsonData); session.sendUpstreamPacket(formRequestPacket); // Hack to fix the (url) image loading bug @@ -65,11 +74,17 @@ public class FormCache { NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket(); latencyPacket.setFromServer(true); latencyPacket.setTimestamp(-System.currentTimeMillis()); - session.scheduleInEventLoop(() -> session.sendUpstreamPacket(latencyPacket), - 500, TimeUnit.MILLISECONDS); + session.scheduleInEventLoop( + () -> session.sendUpstreamPacket(latencyPacket), + 500, TimeUnit.MILLISECONDS + ); } + } - return windowId; + public void resendAllForms() { + for (Int2ObjectMap.Entry entry : forms.int2ObjectEntrySet()) { + sendForm(entry.getIntKey(), entry.getValue()); + } } public void handleResponse(ModalFormResponsePacket response) { @@ -78,17 +93,11 @@ public class FormCache { return; } - Consumer responseConsumer = form.getResponseHandler(); - if (responseConsumer != null) { - try { - responseConsumer.accept(response.getFormData()); - } catch (Exception e) { - GeyserImpl.getInstance().getLogger().error("Error while processing form response!", e); - } + try { + formDefinitions.definitionFor(form) + .handleFormResponse(form, response.getFormData()); + } catch (Exception e) { + GeyserImpl.getInstance().getLogger().error("Error while processing form response!", e); } } - - public boolean removeWindow(int id) { - return forms.remove(id) != null; - } } 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 bd3c73574..05c2628df 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -30,9 +30,6 @@ import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; import org.geysermc.geyser.inventory.GeyserItemStack; import javax.annotation.Nullable; @@ -43,7 +40,7 @@ import java.util.WeakHashMap; * A temporary cache for lodestone information. * Bedrock requests the lodestone position information separately from the item. */ -public class LodestoneCache { +public final class LodestoneCache { /** * A list of any GeyserItemStacks that are lodestones. Used mainly to minimize Bedrock's "pop-in" effect * when a new item has been created; instead we can re-use already existing IDs @@ -121,8 +118,16 @@ public class LodestoneCache { } public @Nullable LodestonePos getPos(int id) { - // We should not need to check the activeLodestones map as Bedrock should already be aware of this ID - return this.lodestones.remove(id); + LodestonePos pos = this.lodestones.remove(id); + if (pos != null) { + return pos; + } + for (LodestonePos activePos : this.activeLodestones.values()) { + if (activePos.id == id) { + return activePos; + } + } + return null; } public void clear() { @@ -131,16 +136,7 @@ public class LodestoneCache { this.lodestones.clear(); } - @Getter - @AllArgsConstructor - @EqualsAndHashCode - public static class LodestonePos { - private final int id; - private final int x; - private final int y; - private final int z; - private final String dimension; - + public record LodestonePos(int id, int x, int y, int z, String dimension) { boolean equals(int x, int y, int z, String dimension) { return this.x == x && this.y == y && this.z == z && this.dimension.equals(dimension); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java index 05e59a5bb..03785de16 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/PistonCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/PreferencesCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/PreferencesCache.java index 534045f81..9e8597b0f 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/PreferencesCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/PreferencesCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java new file mode 100644 index 000000000..f26e1cce3 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/session/cache/SkullCache.java @@ -0,0 +1,211 @@ +/* + * 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.session.cache; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; +import org.geysermc.geyser.session.GeyserSession; + +import java.util.*; + +public class SkullCache { + private final int maxVisibleSkulls; + private final boolean cullingEnabled; + + private final int skullRenderDistanceSquared; + + /** + * The time in milliseconds before unused skull entities are despawned + */ + private static final long CLEANUP_PERIOD = 10000; + + @Getter + private final Map skulls = new Object2ObjectOpenHashMap<>(); + + private final List inRangeSkulls = new ArrayList<>(); + + private final Deque unusedSkullEntities = new ArrayDeque<>(); + private int totalSkullEntities = 0; + + private final GeyserSession session; + + private Vector3f lastPlayerPosition; + + private long lastCleanup = System.currentTimeMillis(); + + public SkullCache(GeyserSession session) { + this.session = session; + this.maxVisibleSkulls = session.getGeyser().getConfig().getMaxVisibleCustomSkulls(); + this.cullingEnabled = this.maxVisibleSkulls != -1; + + // Normal skulls are not rendered beyond 64 blocks + int distance = Math.min(session.getGeyser().getConfig().getCustomSkullRenderDistance(), 64); + this.skullRenderDistanceSquared = distance * distance; + } + + public void putSkull(Vector3i position, String texturesProperty, int blockState) { + Skull skull = skulls.computeIfAbsent(position, Skull::new); + skull.texturesProperty = texturesProperty; + skull.blockState = blockState; + + if (skull.entity != null) { + skull.entity.updateSkull(skull); + } else { + if (!cullingEnabled) { + assignSkullEntity(skull); + return; + } + if (lastPlayerPosition == null) { + return; + } + skull.distanceSquared = position.distanceSquared(lastPlayerPosition.getX(), lastPlayerPosition.getY(), lastPlayerPosition.getZ()); + if (skull.distanceSquared < skullRenderDistanceSquared) { + // Keep list in order + int i = Collections.binarySearch(inRangeSkulls, skull, Comparator.comparingInt(Skull::getDistanceSquared)); + if (i < 0) { // skull.distanceSquared is a new distance value + i = -i - 1; + } + inRangeSkulls.add(i, skull); + + if (i < maxVisibleSkulls) { + // Reassign entity from the farthest skull to this one + if (inRangeSkulls.size() > maxVisibleSkulls) { + freeSkullEntity(inRangeSkulls.get(maxVisibleSkulls)); + } + assignSkullEntity(skull); + } + } + } + } + + public void removeSkull(Vector3i position) { + Skull skull = skulls.remove(position); + if (skull != null) { + boolean hadEntity = skull.entity != null; + freeSkullEntity(skull); + + if (cullingEnabled) { + inRangeSkulls.remove(skull); + if (hadEntity && inRangeSkulls.size() >= maxVisibleSkulls) { + // Reassign entity to the closest skull without an entity + assignSkullEntity(inRangeSkulls.get(maxVisibleSkulls - 1)); + } + } + } + } + + public void updateVisibleSkulls() { + if (cullingEnabled) { + // No need to recheck skull visibility for small movements + if (lastPlayerPosition != null && session.getPlayerEntity().getPosition().distanceSquared(lastPlayerPosition) < 4) { + return; + } + lastPlayerPosition = session.getPlayerEntity().getPosition(); + + inRangeSkulls.clear(); + for (Skull skull : skulls.values()) { + skull.distanceSquared = skull.position.distanceSquared(lastPlayerPosition.getX(), lastPlayerPosition.getY(), lastPlayerPosition.getZ()); + if (skull.distanceSquared > skullRenderDistanceSquared) { + freeSkullEntity(skull); + } else { + inRangeSkulls.add(skull); + } + } + inRangeSkulls.sort(Comparator.comparingInt(Skull::getDistanceSquared)); + + for (int i = inRangeSkulls.size() - 1; i >= 0; i--) { + if (i < maxVisibleSkulls) { + assignSkullEntity(inRangeSkulls.get(i)); + } else { + freeSkullEntity(inRangeSkulls.get(i)); + } + } + } + + // Occasionally clean up unused entities as we want to keep skull + // entities around for later use, to reduce "player" pop-in + if ((System.currentTimeMillis() - lastCleanup) > CLEANUP_PERIOD) { + lastCleanup = System.currentTimeMillis(); + for (SkullPlayerEntity entity : unusedSkullEntities) { + entity.despawnEntity(); + totalSkullEntities--; + } + unusedSkullEntities.clear(); + } + } + + private void assignSkullEntity(Skull skull) { + if (skull.entity != null) { + return; + } + if (unusedSkullEntities.isEmpty()) { + if (!cullingEnabled || totalSkullEntities < maxVisibleSkulls) { + // Create a new entity + long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); + skull.entity = new SkullPlayerEntity(session, geyserId); + skull.entity.spawnEntity(); + skull.entity.updateSkull(skull); + totalSkullEntities++; + } + } else { + // Reuse an entity + skull.entity = unusedSkullEntities.removeFirst(); + skull.entity.updateSkull(skull); + } + } + + private void freeSkullEntity(Skull skull) { + if (skull.entity != null) { + skull.entity.free(); + unusedSkullEntities.addFirst(skull.entity); + skull.entity = null; + } + } + + public void clear() { + skulls.clear(); + inRangeSkulls.clear(); + unusedSkullEntities.clear(); + totalSkullEntities = 0; + lastPlayerPosition = null; + } + + @RequiredArgsConstructor + @Data + public static class Skull { + private String texturesProperty; + private int blockState; + private SkullPlayerEntity entity; + + private final Vector3i position; + private int distanceSquared; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java index 32827cfec..d46a39616 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TagCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,15 +28,19 @@ package org.geysermc.geyser.session.cache; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateTagsPacket; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import javax.annotation.ParametersAreNonnullByDefault; import java.util.Map; /** * Manages information sent from the {@link ClientboundUpdateTagsPacket}. If that packet is not sent, all lists here * will remain empty, matching Java Edition behavior. */ +@ParametersAreNonnullByDefault public class TagCache { /* Blocks */ private IntList leaves; @@ -52,16 +56,19 @@ public class TagCache { private IntList requiresDiamondTool; /* Items */ + private IntList axolotlTemptItems; + private IntList fishes; private IntList flowers; private IntList foxFood; private IntList piglinLoved; + private IntList smallFlowers; public TagCache() { // Ensure all lists are non-null clear(); } - public void loadPacket(ClientboundUpdateTagsPacket packet) { + public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) { Map blockTags = packet.getTags().get("minecraft:block"); this.leaves = IntList.of(blockTags.get("minecraft:leaves")); this.wool = IntList.of(blockTags.get("minecraft:wool")); @@ -76,9 +83,19 @@ public class TagCache { this.requiresDiamondTool = IntList.of(blockTags.get("minecraft:needs_diamond_tool")); Map itemTags = packet.getTags().get("minecraft:item"); + this.axolotlTemptItems = IntList.of(itemTags.get("minecraft:axolotl_tempt_items")); + this.fishes = IntList.of(itemTags.get("minecraft:fishes")); this.flowers = IntList.of(itemTags.get("minecraft:flowers")); this.foxFood = IntList.of(itemTags.get("minecraft:fox_food")); this.piglinLoved = IntList.of(itemTags.get("minecraft:piglin_loved")); + this.smallFlowers = IntList.of(itemTags.get("minecraft:small_flowers")); + + // Hack btw + boolean emulatePost1_14Logic = itemTags.get("minecraft:signs").length > 1; + session.setEmulatePost1_14Logic(emulatePost1_14Logic); + if (session.getGeyser().getLogger().isDebug()) { + session.getGeyser().getLogger().debug("Emulating post 1.14 villager logic for " + session.name() + "? " + emulatePost1_14Logic); + } } public void clear() { @@ -94,9 +111,20 @@ public class TagCache { this.requiresIronTool = IntLists.emptyList(); this.requiresDiamondTool = IntLists.emptyList(); + this.axolotlTemptItems = IntLists.emptyList(); + this.fishes = IntLists.emptyList(); this.flowers = IntLists.emptyList(); this.foxFood = IntLists.emptyList(); this.piglinLoved = IntLists.emptyList(); + this.smallFlowers = IntLists.emptyList(); + } + + public boolean isAxolotlTemptItem(ItemMapping itemMapping) { + return axolotlTemptItems.contains(itemMapping.getJavaId()); + } + + public boolean isFish(GeyserItemStack itemStack) { + return fishes.contains(itemStack.getJavaId()); } public boolean isFlower(ItemMapping mapping) { @@ -111,6 +139,10 @@ public class TagCache { return piglinLoved.contains(mapping.getJavaId()); } + public boolean isSmallFlower(GeyserItemStack itemStack) { + return smallFlowers.contains(itemStack.getJavaId()); + } + public boolean isAxeEffective(BlockMapping blockMapping) { return axeEffective.contains(blockMapping.getJavaBlockId()); } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java index cc9a7c09f..c65f63111 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/TeleportCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -66,6 +66,10 @@ public class TeleportCache { unconfirmedFor++; } + public void resetUnconfirmedFor() { + unconfirmedFor = 0; + } + public boolean shouldResend() { return unconfirmedFor >= RESEND_THRESHOLD; } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java index 01c5949c7..09e7e9234 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldBorder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -30,7 +30,6 @@ import com.nukkitx.math.vector.Vector2d; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerFogPacket; import lombok.Getter; import lombok.Setter; import org.geysermc.geyser.entity.EntityDefinitions; @@ -38,7 +37,6 @@ import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import javax.annotation.Nonnull; -import java.util.Collections; public class WorldBorder { private static final double DEFAULT_WORLD_BORDER_SIZE = 5.9999968E7D; @@ -131,11 +129,26 @@ public class WorldBorder { } /** - * @return true as long the entity is within the world limits. + * @return true as long as the player entity is within the world limits. */ public boolean isInsideBorderBoundaries() { - Vector3f entityPosition = session.getPlayerEntity().getPosition(); - return entityPosition.getX() > minX && entityPosition.getX() < maxX && entityPosition.getZ() > minZ && entityPosition.getZ() < maxZ; + return isInsideBorderBoundaries(session.getPlayerEntity().getPosition()); + } + + public boolean isInsideBorderBoundaries(Vector3f position) { + return position.getX() > minX && position.getX() < maxX && position.getZ() > minZ && position.getZ() < maxZ; + } + + private static final int CLOSE_TO_BORDER = 5; + + /** + * @return if the player is close to the border boundaries. Used to always indicate a border even if there is no + * warning blocks set. + */ + public boolean isCloseToBorderBoundaries() { + Vector3f position = session.getPlayerEntity().getPosition(); + return !(position.getX() > minX + CLOSE_TO_BORDER && position.getX() < maxX - CLOSE_TO_BORDER + && position.getZ() > minZ + CLOSE_TO_BORDER && position.getZ() < maxZ - CLOSE_TO_BORDER); } /** @@ -151,7 +164,7 @@ public class WorldBorder { // Move the player back, but allow gravity to take place // Teleported = true makes going back better, but disconnects the player from their mounted entity playerEntity.moveAbsolute(Vector3f.from(playerEntity.getPosition().getX(), (newPosition.getY() - EntityDefinitions.PLAYER.offset()), playerEntity.getPosition().getZ()), - playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), playerEntity.isOnGround(), session.getRidingVehicleEntity() == null); + playerEntity.getYaw(), playerEntity.getPitch(), playerEntity.getHeadYaw(), playerEntity.isOnGround(), playerEntity.getVehicle() == null); } return isInWorldBorder; } @@ -245,16 +258,16 @@ public class WorldBorder { float particlePosY = entityPosition.getY(); float particlePosZ = entityPosition.getZ(); - if (entityPosition.getX() > warningMaxX) { + if (entityPosition.getX() > Math.min(warningMaxX, maxX - CLOSE_TO_BORDER)) { drawWall(Vector3f.from(maxX, particlePosY, particlePosZ), true); } - if (entityPosition.getX() < warningMinX) { + if (entityPosition.getX() < Math.max(warningMinX, minX + CLOSE_TO_BORDER)) { drawWall(Vector3f.from(minX, particlePosY, particlePosZ), true); } - if (entityPosition.getZ() > warningMaxZ) { + if (entityPosition.getZ() > Math.min(warningMaxZ, maxZ - CLOSE_TO_BORDER)) { drawWall(Vector3f.from(particlePosX, particlePosY, maxZ), false); } - if (entityPosition.getZ() < warningMinZ) { + if (entityPosition.getZ() < Math.max(warningMinZ, minZ + CLOSE_TO_BORDER)) { drawWall(Vector3f.from(particlePosX, particlePosY, minZ), false); } } diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java index a9564b157..17679ad3e 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,24 +26,36 @@ package org.geysermc.geyser.session.cache; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; import lombok.Getter; import lombok.Setter; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession; +import org.geysermc.geyser.session.GeyserSession; -@Getter -public class WorldCache { +public final class WorldCache { private final GeyserSession session; + @Getter private final ScoreboardSession scoreboardSession; + @Getter private Scoreboard scoreboard; + @Getter @Setter private Difficulty difficulty = Difficulty.EASY; + /** + * Whether our cooldown changed the title time, and the true title times need to be re-sent. + */ + private boolean titleTimesNeedReset = false; + private int trueTitleFadeInTime; + private int trueTitleStayTime; + private int trueTitleFadeOutTime; + public WorldCache(GeyserSession session) { this.session = session; this.scoreboard = new Scoreboard(session); scoreboardSession = new ScoreboardSession(session); + resetTitleTimes(false); } public void removeScoreboard() { @@ -58,4 +70,55 @@ public class WorldCache { int pps = scoreboardSession.getPacketsPerSecond(); return Math.max(pps, pendingPps); } + + public void markTitleTimesAsIncorrect() { + titleTimesNeedReset = true; + } + + /** + * Store the true active title times. + */ + public void setTitleTimes(int fadeInTime, int stayTime, int fadeOutTime) { + trueTitleFadeInTime = fadeInTime; + trueTitleStayTime = stayTime; + trueTitleFadeOutTime = fadeOutTime; + // The translator will sync this for us + titleTimesNeedReset = false; + } + + /** + * If needed, ensure that the Bedrock client will use the correct timings for titles. + */ + public void synchronizeCorrectTitleTimes() { + if (titleTimesNeedReset) { + forceSyncCorrectTitleTimes(); + } + } + + private void forceSyncCorrectTitleTimes() { + SetTitlePacket titlePacket = new SetTitlePacket(); + titlePacket.setType(SetTitlePacket.Type.TIMES); + titlePacket.setText(""); + titlePacket.setFadeInTime(trueTitleFadeInTime); + titlePacket.setStayTime(trueTitleStayTime); + titlePacket.setFadeOutTime(trueTitleFadeOutTime); + titlePacket.setPlatformOnlineId(""); + titlePacket.setXuid(""); + + session.sendUpstreamPacket(titlePacket); + titleTimesNeedReset = false; + } + + /** + * Reset the true active title times to the (Java Edition 1.18.2) defaults. + */ + public void resetTitleTimes(boolean clientSync) { + trueTitleFadeInTime = 10; + trueTitleStayTime = 70; + trueTitleFadeOutTime = 20; + + if (clientSync) { + forceSyncCorrectTitleTimes(); + } + } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java index 90f19eb24..6794af498 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FakeHeadProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.skin; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; @@ -106,7 +105,7 @@ public class FakeHeadProvider { session.getPlayerWithCustomHeads().add(entity.getUuid()); - GameProfile.Property texturesProperty = entity.getProfile().getProperty("textures"); + String texturesProperty = entity.getTexturesProperty(); SkinProvider.EXECUTOR_SERVICE.execute(() -> { try { @@ -182,7 +181,7 @@ public class FakeHeadProvider { @Getter @Setter private static class FakeHeadEntry { - private final GameProfile.Property texturesProperty; + private final String texturesProperty; private final String fakeHeadSkinUrl; private PlayerEntity entity; @@ -192,18 +191,7 @@ public class FakeHeadProvider { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; FakeHeadEntry that = (FakeHeadEntry) o; - return equals(texturesProperty, that.texturesProperty) && Objects.equals(fakeHeadSkinUrl, that.fakeHeadSkinUrl); - } - - private boolean equals(GameProfile.Property a, GameProfile.Property b) { - //TODO actually fix this in MCAuthLib - if (a == b) { - return true; - } - if (a == null || b == null) { - return false; - } - return Objects.equals(a.getName(), b.getName()) && Objects.equals(a.getValue(), b.getValue()) && Objects.equals(a.getSignature(), b.getSignature()); + return Objects.equals(texturesProperty, that.texturesProperty) && Objects.equals(fakeHeadSkinUrl, that.fakeHeadSkinUrl); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java b/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java index 5beeed9b1..7a800890b 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java +++ b/core/src/main/java/org/geysermc/geyser/skin/FloodgateSkinUploader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -30,6 +30,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.Getter; +import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.GeyserSession; @@ -48,8 +49,6 @@ import java.util.List; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; -import static org.geysermc.geyser.util.PluginMessageUtils.getSkinChannel; - public final class FloodgateSkinUploader { private final ObjectMapper JACKSON = new ObjectMapper(); private final List skinQueue = new ArrayList<>(); @@ -126,7 +125,7 @@ public final class FloodgateSkinUploader { byte[] bytes = (value + '\0' + signature) .getBytes(StandardCharsets.UTF_8); - PluginMessageUtils.sendMessage(session, getSkinChannel(), bytes); + PluginMessageUtils.sendMessage(session, PluginMessageChannels.SKIN, bytes); } break; case LOG_MESSAGE: diff --git a/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkin.java b/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkin.java index e51882036..bb638556d 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkin.java +++ b/core/src/main/java/org/geysermc/geyser/skin/ProvidedSkin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java index 16833d634..4eb92c3ac 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,7 +26,6 @@ package org.geysermc.geyser.skin; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -34,9 +33,9 @@ import com.nukkitx.protocol.bedrock.data.skin.ImageData; import com.nukkitx.protocol.bedrock.data.skin.SerializedSkin; import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.auth.AuthType; import org.geysermc.geyser.session.auth.BedrockClientData; import org.geysermc.geyser.text.GeyserLocale; @@ -54,7 +53,7 @@ public class SkinManager { * Builds a Bedrock player list entry from our existing, cached Bedrock skin information */ public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, PlayerEntity playerEntity) { - GameProfileData data = GameProfileData.from(playerEntity.getProfile()); + GameProfileData data = GameProfileData.from(playerEntity); SkinProvider.Cape cape = SkinProvider.getCachedCape(data.capeUrl()); SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); @@ -65,8 +64,8 @@ public class SkinManager { return buildEntryManually( session, - playerEntity.getProfile().getId(), - playerEntity.getProfile().getName(), + playerEntity.getUuid(), + playerEntity.getUsername(), playerEntity.getGeyserId(), skin.getTextureUrl(), skin.getSkinData(), @@ -227,31 +226,31 @@ public class SkinManager { } /** - * Generate the GameProfileData from the given GameProfile + * Generate the GameProfileData from the given player entity * - * @param profile GameProfile to build the GameProfileData from + * @param entity entity to build the GameProfileData from * @return The built GameProfileData */ - public static GameProfileData from(GameProfile profile) { + public static GameProfileData from(PlayerEntity entity) { try { - GameProfile.Property skinProperty = profile.getProperty("textures"); + String texturesProperty = entity.getTexturesProperty(); - if (skinProperty == null) { + if (texturesProperty == null) { // Likely offline mode - return loadBedrockOrOfflineSkin(profile); + return loadBedrockOrOfflineSkin(entity); } - GameProfileData data = loadFromJson(skinProperty.getValue()); + GameProfileData data = loadFromJson(texturesProperty); if (data != null) { return data; } else { - return loadBedrockOrOfflineSkin(profile); + return loadBedrockOrOfflineSkin(entity); } } catch (IOException exception) { - GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + profile.getName()); + GeyserImpl.getInstance().getLogger().debug("Something went wrong while processing skin for " + entity.getUsername()); if (GeyserImpl.getInstance().getConfig().isDebugMode()) { exception.printStackTrace(); } - return loadBedrockOrOfflineSkin(profile); + return loadBedrockOrOfflineSkin(entity); } } @@ -280,14 +279,15 @@ public class SkinManager { * @return default skin with default cape when texture data is invalid, or the Bedrock player's skin if this * is a Bedrock player. */ - private static GameProfileData loadBedrockOrOfflineSkin(GameProfile profile) { + private static GameProfileData loadBedrockOrOfflineSkin(PlayerEntity entity) { // Fallback to the offline mode of working it out - boolean isAlex = (Math.abs(profile.getId().hashCode() % 2) == 1); + UUID uuid = entity.getUuid(); + boolean isAlex = (Math.abs(uuid.hashCode() % 2) == 1); String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl(); String capeUrl = SkinProvider.EMPTY_CAPE.getTextureUrl(); if (("steve".equals(skinUrl) || "alex".equals(skinUrl)) && GeyserImpl.getInstance().getConfig().getRemote().getAuthType() != AuthType.ONLINE) { - GeyserSession session = GeyserImpl.getInstance().connectionByUuid(profile.getId()); + GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid); if (session != null) { skinUrl = session.getClientData().getSkinId(); diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java index 91c555f3d..43cf30b47 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkinProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,7 +27,6 @@ package org.geysermc.geyser.skin; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntArrayTag; import com.github.steveice10.opennbt.tag.builtin.Tag; @@ -53,9 +52,9 @@ import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.List; import java.util.*; import java.util.concurrent.*; +import java.util.function.Predicate; public class SkinProvider { public static final boolean ALLOW_THIRD_PARTY_CAPES = GeyserImpl.getInstance().getConfig().isAllowThirdPartyCapes(); @@ -83,6 +82,12 @@ public class SkinProvider { private static final Map cachedGeometry = new ConcurrentHashMap<>(); + /** + * Citizens NPCs use UUID version 2, while legitimate Minecraft players use version 4, and + * offline mode players use version 3. + */ + public static final Predicate IS_NPC = uuid -> uuid.version() == 2; + public static final boolean ALLOW_THIRD_PARTY_EARS = GeyserImpl.getInstance().getConfig().isAllowThirdPartyEars(); public static final String EARS_GEOMETRY; public static final String EARS_GEOMETRY_SLIM; @@ -108,10 +113,12 @@ public class SkinProvider { WEARING_CUSTOM_SKULL = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkull\"}}", wearingCustomSkull, false); String wearingCustomSkullSlim = new String(FileUtils.readAllBytes("bedrock/skin/geometry.humanoid.wearingCustomSkullSlim.json"), StandardCharsets.UTF_8); WEARING_CUSTOM_SKULL_SLIM = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.wearingCustomSkullSlim\"}}", wearingCustomSkullSlim, false); + } + public static void registerCacheImageTask(GeyserImpl geyser) { // Schedule Daily Image Expiry if we are caching them - if (GeyserImpl.getInstance().getConfig().getCacheImages() > 0) { - GeyserImpl.getInstance().getScheduledThread().scheduleAtFixedRate(() -> { + if (geyser.getConfig().getCacheImages() > 0) { + geyser.getScheduledThread().scheduleAtFixedRate(() -> { File cacheFolder = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("images").toFile(); if (!cacheFolder.exists()) { return; @@ -148,7 +155,7 @@ public class SkinProvider { } public static CompletableFuture requestSkinData(PlayerEntity entity) { - SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity.getProfile()); + SkinManager.GameProfileData data = SkinManager.GameProfileData.from(entity); return requestSkinAndCape(entity.getUuid(), data.skinUrl(), data.capeUrl()) .thenApplyAsync(skinAndCape -> { @@ -293,6 +300,10 @@ public class SkinProvider { String username, boolean newThread) { if (officialCape.isFailed() && ALLOW_THIRD_PARTY_CAPES) { for (CapeProvider provider : CapeProvider.VALUES) { + if (provider.type != CapeUrlType.USERNAME && IS_NPC.test(playerId)) { + continue; + } + Cape cape1 = getOrDefault( requestCape(provider.getUrlFor(playerId, username), provider, newThread), EMPTY_CAPE, 4 @@ -330,6 +341,10 @@ public class SkinProvider { */ public static CompletableFuture requestUnofficialEars(Skin officialSkin, UUID playerId, String username, boolean newThread) { for (EarsProvider provider : EarsProvider.VALUES) { + if (provider.type != CapeUrlType.USERNAME && IS_NPC.test(playerId)) { + continue; + } + Skin skin1 = getOrDefault( requestEars(provider.getUrlFor(playerId, username), newThread, officialSkin), officialSkin, 4 @@ -529,12 +544,11 @@ public class SkinProvider { * @param skullOwner the CompoundTag of the skull with no textures * @return a completable GameProfile with textures included */ - public static CompletableFuture requestTexturesFromUsername(CompoundTag skullOwner) { + public static CompletableFuture requestTexturesFromUsername(CompoundTag skullOwner) { return CompletableFuture.supplyAsync(() -> { Tag uuidTag = skullOwner.get("Id"); String uuidToString = ""; JsonNode node; - GameProfile gameProfile = new GameProfile(UUID.randomUUID(), ""); boolean retrieveUuidFromInternet = !(uuidTag instanceof IntArrayTag); // also covers null check if (!retrieveUuidFromInternet) { @@ -560,15 +574,12 @@ public class SkinProvider { // Get textures from UUID node = WebUtils.getJson("https://sessionserver.mojang.com/session/minecraft/profile/" + uuidToString); - List profileProperties = new ArrayList<>(); JsonNode properties = node.get("properties"); if (properties == null) { GeyserImpl.getInstance().getLogger().debug("No properties found in Mojang response for " + uuidToString); return null; } - profileProperties.add(new GameProfile.Property("textures", node.get("properties").get(0).get("value").asText())); - gameProfile.setProperties(profileProperties); - return gameProfile; + return node.get("properties").get(0).get("value").asText(); } catch (Exception e) { if (GeyserImpl.getInstance().getConfig().isDebugMode()) { e.printStackTrace(); @@ -584,6 +595,8 @@ public class SkinProvider { HttpURLConnection con = (HttpURLConnection) new URL(imageUrl).openConnection(); con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); + con.setConnectTimeout(10000); + con.setReadTimeout(10000); BufferedImage image = ImageIO.read(con.getInputStream()); if (image == null) throw new NullPointerException(); diff --git a/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java b/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java index 100f06caf..58054e9c5 100644 --- a/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java +++ b/core/src/main/java/org/geysermc/geyser/skin/SkullSkinManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -50,7 +50,7 @@ public class SkullSkinManager extends SkinManager { public static void requestAndHandleSkin(PlayerEntity entity, GeyserSession session, Consumer skinConsumer) { - GameProfileData data = GameProfileData.from(entity.getProfile()); + GameProfileData data = GameProfileData.from(entity); SkinProvider.requestSkin(entity.getUuid(), data.skinUrl(), true) .whenCompleteAsync((skin, throwable) -> { diff --git a/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java b/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java index 9ff55d61b..27b277c72 100644 --- a/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java +++ b/core/src/main/java/org/geysermc/geyser/text/AsteriskSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/text/ChatColor.java b/core/src/main/java/org/geysermc/geyser/text/ChatColor.java index 29901d857..d39c0d696 100644 --- a/core/src/main/java/org/geysermc/geyser/text/ChatColor.java +++ b/core/src/main/java/org/geysermc/geyser/text/ChatColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/text/DummyLegacyHoverEventSerializer.java b/core/src/main/java/org/geysermc/geyser/text/DummyLegacyHoverEventSerializer.java new file mode 100644 index 000000000..fdce1f879 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/text/DummyLegacyHoverEventSerializer.java @@ -0,0 +1,69 @@ +/* + * 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.text; + +import net.kyori.adventure.key.Key; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.event.HoverEvent; +import net.kyori.adventure.text.serializer.gson.LegacyHoverEventSerializer; +import net.kyori.adventure.util.Codec; +import org.jetbrains.annotations.NotNull; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +public final class DummyLegacyHoverEventSerializer implements LegacyHoverEventSerializer { + private final HoverEvent.ShowEntity dummyShowEntity; + private final HoverEvent.ShowItem dummyShowItem; + + public DummyLegacyHoverEventSerializer() { + dummyShowEntity = HoverEvent.ShowEntity.of(Key.key("geysermc", "dummyshowitem"), + UUID.nameUUIDFromBytes("entitiesareprettyneat".getBytes(StandardCharsets.UTF_8))); + dummyShowItem = HoverEvent.ShowItem.of(Key.key("geysermc", "dummyshowentity"), 0); + } + + @Override + public HoverEvent.@NotNull ShowItem deserializeShowItem(@NotNull Component input) { + return dummyShowItem; + } + + @Override + public HoverEvent.@NotNull ShowEntity deserializeShowEntity(@NotNull Component input, + Codec.Decoder componentDecoder) { + return dummyShowEntity; + } + + @Override + public @NotNull Component serializeShowItem(HoverEvent.@NotNull ShowItem input) { + return Component.empty(); + } + + @Override + public @NotNull Component serializeShowEntity(HoverEvent.@NotNull ShowEntity input, + Codec.Encoder componentEncoder) { + return Component.empty(); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java index 8fc98402a..86e015c0f 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/GeyserLocale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,10 +28,10 @@ package org.geysermc.geyser.text; import org.geysermc.geyser.GeyserBootstrap; import org.geysermc.geyser.GeyserImpl; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.MessageFormat; import java.util.HashMap; import java.util.Locale; @@ -116,12 +116,22 @@ public class GeyserLocale { return locale; } + Properties localeProp = new Properties(); + + File localLanguage; + Path localFolder = bootstrap.getConfigFolder().resolve("languages"); + if (Files.exists(localFolder)) { + localLanguage = localFolder.resolve(locale + ".properties").toFile(); + } else { + localLanguage = null; + } + boolean validLocalLanguage = localLanguage != null && localLanguage.exists(); + InputStream localeStream = bootstrap.getResourceOrNull("languages/texts/" + locale + ".properties"); // Load the locale if (localeStream != null) { try { - Properties localeProp = new Properties(); try (InputStreamReader reader = new InputStreamReader(localeStream, StandardCharsets.UTF_8)) { localeProp.load(reader); } catch (Exception e) { @@ -130,18 +140,37 @@ public class GeyserLocale { // Insert the locale into the mappings LOCALE_MAPPINGS.put(locale, localeProp); - return locale; } finally { try { localeStream.close(); } catch (IOException ignored) {} } } else { - if (GeyserImpl.getInstance() != null) { + if (GeyserImpl.getInstance() != null && !validLocalLanguage) { + // Don't warn on missing locales if a local file has been found GeyserImpl.getInstance().getLogger().warning("Missing locale: " + locale); } - return null; } + + // Load any language overrides that exist after, to override any strings that we just added + // By loading both, we ensure that if a language string doesn't exist in the custom properties folder, + // it's loaded from our jar + if (validLocalLanguage) { + try (InputStream stream = new FileInputStream(localLanguage)) { + localeProp.load(stream); + } catch (IOException e) { + String message = "Unable to load custom language override!"; + if (GeyserImpl.getInstance() != null) { + GeyserImpl.getInstance().getLogger().error(message, e); + } else { + System.err.println(message); + e.printStackTrace(); + } + } + + LOCALE_MAPPINGS.putIfAbsent(locale, localeProp); + } + return localeProp.isEmpty() ? null : locale; } /** diff --git a/core/src/main/java/org/geysermc/geyser/text/GsonComponentSerializerWrapper.java b/core/src/main/java/org/geysermc/geyser/text/GsonComponentSerializerWrapper.java index 930d4a62c..2140dcc88 100644 --- a/core/src/main/java/org/geysermc/geyser/text/GsonComponentSerializerWrapper.java +++ b/core/src/main/java/org/geysermc/geyser/text/GsonComponentSerializerWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,7 +31,6 @@ import com.google.gson.JsonElement; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.function.UnaryOperator; @@ -62,9 +61,14 @@ public record GsonComponentSerializerWrapper(GsonComponentSerializer source) imp } @Override - public @Nullable Component deserialize(@NotNull String input) { + public @NotNull Component deserialize(@NotNull String input) { // See https://github.com/KyoriPowered/adventure/issues/447 - return this.serializer().fromJson(input, Component.class); + Component component = this.serializer().fromJson(input, Component.class); + if (component == null) { + return Component.empty(); + } + + return component; } @Override diff --git a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java index 4f8680c73..57749f29e 100644 --- a/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java +++ b/core/src/main/java/org/geysermc/geyser/text/MinecraftLocale.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java b/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java index 129fb1f40..43e8c69e3 100644 --- a/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/text/MinecraftTranslationRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java new file mode 100644 index 000000000..296cacaf5 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/text/TextDecoration.java @@ -0,0 +1,93 @@ +/* + * 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.text; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import net.kyori.adventure.text.format.NamedTextColor; +import net.kyori.adventure.text.format.Style; + +import java.util.EnumSet; +import java.util.Locale; +import java.util.Set; + +public final class TextDecoration { + private final String translationKey; + private final Style style; + private final Set parameters; + + public TextDecoration(CompoundTag tag) { + translationKey = (String) tag.get("translation_key").getValue(); + + CompoundTag styleTag = tag.get("style"); + Style.Builder builder = Style.style(); + StringTag color = styleTag.get("color"); + if (color != null) { + builder.color(NamedTextColor.NAMES.value(color.getValue())); + } + //TODO implement the rest + Tag italic = styleTag.get("italic"); + if (italic != null && ((Number) italic.getValue()).byteValue() == (byte) 1) { + builder.decorate(net.kyori.adventure.text.format.TextDecoration.ITALIC); + } + style = builder.build(); + + this.parameters = EnumSet.noneOf(Parameter.class); + ListTag parameters = tag.get("parameters"); + for (Tag parameter : parameters) { + this.parameters.add(Parameter.valueOf(((String) parameter.getValue()).toUpperCase(Locale.ROOT))); + } + } + + public String translationKey() { + return translationKey; + } + + public Style style() { + return style; + } + + public Set parameters() { + return parameters; + } + + @Override + public String toString() { + return "TextDecoration{" + + "translationKey='" + translationKey + '\'' + + ", style=" + style + + ", parameters=" + parameters + + '}'; + } + + public enum Parameter { + CONTENT, + SENDER, + TEAM_NAME + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java index 964faab0a..3d2cc563e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/BlockCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java b/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java index 2156cc670..6980968ab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/CollisionRemapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java index a7babead3..dcbad4758 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/DirtPathCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java index 3c858dc92..c101fcdfb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/DoorCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/OtherCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/OtherCollision.java index 2a81077ca..b2e2deceb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/OtherCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/OtherCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java index fddc2e39b..2aa74499a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/ScaffoldingCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java index 912d6a9b9..998e15ded 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/SnowCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java index 1f47d8abb..822202ff2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/SolidCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/SpawnerCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/SpawnerCollision.java index 698b8f82d..7d4dfedc2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/SpawnerCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/SpawnerCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java b/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java index 49b9f6c3f..0660c3cf6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java +++ b/core/src/main/java/org/geysermc/geyser/translator/collision/TrapdoorCollision.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java index e8eba1654..dd53e4c5b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/entity/EntityMetadataTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java index d34f5195c..bf806bd06 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AbstractBlockInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java index b7aaad7b1..e56586b14 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/AnvilInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,7 +27,12 @@ package org.geysermc.geyser.translator.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.ItemStackRequest; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeOptionalStackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; +import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import org.geysermc.geyser.inventory.AnvilContainer; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; @@ -35,12 +40,34 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.updater.AnvilInventoryUpdater; +import java.util.Objects; + public class AnvilInventoryTranslator extends AbstractBlockInventoryTranslator { public AnvilInventoryTranslator() { super(3, "minecraft:anvil[facing=north]", com.nukkitx.protocol.bedrock.data.inventory.ContainerType.ANVIL, AnvilInventoryUpdater.INSTANCE, "minecraft:chipped_anvil", "minecraft:damaged_anvil"); } + @Override + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + return action.getType() == StackRequestActionType.CRAFT_RECIPE_OPTIONAL; + } + + @Override + protected ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + // Guarded by shouldHandleRequestFirst check + CraftRecipeOptionalStackRequestActionData data = (CraftRecipeOptionalStackRequestActionData) request.getActions()[0]; + AnvilContainer container = (AnvilContainer) inventory; + + // Required as of 1.18.30 - FilterTextPackets no longer appear to be sent + String name = request.getFilterStrings()[data.getFilteredStringIndex()]; + if (!Objects.equals(name, container.getNewName())) { + container.checkForRename(session, name); + } + + return super.translateRequest(session, inventory, request); + } + @Override public int bedrockSlotToJava(StackRequestSlotInfoData slotInfoData) { return switch (slotInfoData.getContainer()) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java index becca359b..8016ca24f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BaseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java index f0820d9e8..54dc533c6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BeaconInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -38,16 +38,17 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.ints.IntSets; import org.geysermc.geyser.inventory.BeaconContainer; +import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.holder.BlockInventoryHolder; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InventoryUtils; -import java.util.Collections; +import java.util.OptionalInt; public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator { public BeaconInventoryTranslator() { @@ -104,7 +105,7 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator } @Override - public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { return action.getType() == StackRequestActionType.BEACON_PAYMENT; } @@ -112,9 +113,13 @@ public class BeaconInventoryTranslator extends AbstractBlockInventoryTranslator public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { // Input a beacon payment BeaconPaymentStackRequestActionData beaconPayment = (BeaconPaymentStackRequestActionData) request.getActions()[0]; - ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(beaconPayment.getPrimaryEffect(), beaconPayment.getSecondaryEffect()); + ServerboundSetBeaconPacket packet = new ServerboundSetBeaconPacket(toJava(beaconPayment.getPrimaryEffect()), toJava(beaconPayment.getSecondaryEffect())); session.sendDownstreamPacket(packet); - return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); + } + + private OptionalInt toJava(int effectChoice) { + return effectChoice == -1 ? OptionalInt.empty() : OptionalInt.of(effectChoice); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java index 43bea55ab..0c4fe12e7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/BrewingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java index 08caa7784..226abe157 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CartographyInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -42,7 +42,7 @@ public class CartographyInventoryTranslator extends AbstractBlockInventoryTransl } @Override - public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, + protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) { if (javaDestinationSlot == 0) { // Bedrock Edition can use paper or an empty map in slot 0 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java index ea01dc43d..61e2258b6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/CraftingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,6 +37,11 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, UIInventoryUpdater.INSTANCE); } + @Override + public int getGridSize() { + return 9; + } + @Override public SlotType getSlotType(int javaSlot) { if (javaSlot == 0) { @@ -47,7 +52,7 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato @Override public BedrockContainerSlot javaSlotToBedrockContainer(int slot) { - if (slot >= 1 && slot <= 9) { + if (isCraftingGrid(slot)) { return new BedrockContainerSlot(ContainerSlotType.CRAFTING_INPUT, slot + 31); } if (slot == 0) { @@ -76,4 +81,8 @@ public class CraftingInventoryTranslator extends AbstractBlockInventoryTranslato } return super.javaSlotToBedrock(slot); } + + public static boolean isCraftingGrid(int slot) { + return slot >= 1 && slot <= 9; + } } 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 f18a902ff..800b35901 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,23 +27,22 @@ package org.geysermc.geyser.translator.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundContainerButtonClickPacket; -import com.nukkitx.protocol.bedrock.data.inventory.*; +import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; +import com.nukkitx.protocol.bedrock.data.inventory.EnchantOptionData; +import com.nukkitx.protocol.bedrock.data.inventory.ItemStackRequest; +import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import com.nukkitx.protocol.bedrock.packet.PlayerEnchantOptionsPacket; -import org.geysermc.geyser.inventory.EnchantingContainer; -import org.geysermc.geyser.inventory.GeyserEnchantOption; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.inventory.BedrockContainerSlot; -import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import it.unimi.dsi.fastutil.ints.IntSets; +import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.item.Enchantment; +import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.session.GeyserSession; import java.util.Arrays; -import java.util.Collections; public class EnchantingInventoryTranslator extends AbstractBlockInventoryTranslator { public EnchantingInventoryTranslator() { @@ -104,7 +103,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla } @Override - public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { return action.getType() == StackRequestActionType.CRAFT_RECIPE; } @@ -130,7 +129,7 @@ public class EnchantingInventoryTranslator extends AbstractBlockInventoryTransla } ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), javaSlot); session.sendDownstreamPacket(packet); - return acceptRequest(request, makeContainerEntries(session, inventory, Collections.emptySet())); + return acceptRequest(request, makeContainerEntries(session, inventory, IntSets.emptySet())); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java index 4265b39e3..23bab8c0e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/Generic3X3InventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java index fae539db8..33b00d202 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/GrindstoneInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java index 9356dcfb6..729717a5d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/HopperInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 66fd6959e..6f4ca7ee4 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,12 +26,8 @@ package org.geysermc.geyser.translator.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; @@ -43,15 +39,13 @@ import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import org.checkerframework.checker.nullness.qual.Nullable; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.CartographyContainer; -import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.inventory.BedrockContainerSlot; -import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.inventory.*; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.click.ClickPlan; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.inventory.chest.DoubleChestInventoryTranslator; import org.geysermc.geyser.translator.inventory.chest.SingleChestInventoryTranslator; import org.geysermc.geyser.translator.inventory.furnace.BlastFurnaceInventoryTranslator; @@ -119,6 +113,13 @@ public abstract class InventoryTranslator { public abstract SlotType getSlotType(int javaSlot); public abstract Inventory createInventory(String name, int windowId, ContainerType containerType, PlayerInventory playerInventory); + /** + * Used for crafting-related transactions. Will override in PlayerInventoryTranslator and CraftingInventoryTranslator. + */ + public int getGridSize() { + return -1; + } + /** * Should be overwritten in cases where specific inventories should reject an item being in a specific spot. * For examples, looms use this to reject items that are dyes in Bedrock but not in Java. @@ -127,7 +128,7 @@ public abstract class InventoryTranslator { * * @return true if this transfer should be rejected */ - public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, + protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) { return false; } @@ -136,18 +137,18 @@ public abstract class InventoryTranslator { * Should be overrided if this request matches a certain criteria and shouldn't be treated normally. * E.G. anvil renaming or enchanting */ - public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { return false; } /** * If {@link #shouldHandleRequestFirst(StackRequestActionData, Inventory)} returns true, this will be called */ - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + protected ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { return rejectRequest(request); } - public void translateRequests(GeyserSession session, Inventory inventory, List requests) { + public final void translateRequests(GeyserSession session, Inventory inventory, List requests) { boolean refresh = false; ItemStackResponsePacket responsePacket = new ItemStackResponsePacket(); for (ItemStackRequest request : requests) { @@ -184,6 +185,9 @@ public abstract class InventoryTranslator { InventoryUtils.updateCursor(session); updateInventory(session, inventory); } + + // We're done with our batch of inventory requests so this hack should be reset + inventory.resetNextStateId(); } public ItemStackResponsePacket.Response translateRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { @@ -196,10 +200,6 @@ public abstract class InventoryTranslator { case PLACE: { TransferStackRequestActionData transferAction = (TransferStackRequestActionData) action; if (!(checkNetId(session, inventory, transferAction.getSource()) && checkNetId(session, inventory, transferAction.getDestination()))) { - if (session.getGameMode().equals(GameMode.CREATIVE) && transferAction.getSource().getContainer() == ContainerSlotType.CRAFTING_INPUT && - transferAction.getSource().getSlot() >= 28 && transferAction.getSource().getSlot() <= 31) { - return rejectRequest(request, false); - } if (session.getGeyser().getConfig().isDebugMode()) { session.getGeyser().getLogger().error("DEBUG: About to reject TAKE/PLACE request made by " + session.name()); dumpStackRequestDetails(session, inventory, transferAction.getSource(), transferAction.getDestination()); @@ -209,17 +209,19 @@ public abstract class InventoryTranslator { int sourceSlot = bedrockSlotToJava(transferAction.getSource()); int destSlot = bedrockSlotToJava(transferAction.getDestination()); + boolean isSourceCursor = isCursor(transferAction.getSource()); + boolean isDestCursor = isCursor(transferAction.getDestination()); if (shouldRejectItemPlace(session, inventory, transferAction.getSource().getContainer(), - isCursor(transferAction.getSource()) ? -1 : sourceSlot, - transferAction.getDestination().getContainer(), isCursor(transferAction.getDestination()) ? -1 : destSlot)) { + isSourceCursor ? -1 : sourceSlot, + transferAction.getDestination().getContainer(), isDestCursor ? -1 : destSlot)) { // This item would not be here in Java return rejectRequest(request, false); } - if (isCursor(transferAction.getSource()) && isCursor(transferAction.getDestination())) { //??? + if (isSourceCursor && isDestCursor) { //??? return rejectRequest(request); - } else if (isCursor(transferAction.getSource())) { //releasing cursor + } else if (isSourceCursor) { //releasing cursor int sourceAmount = cursor.getAmount(); if (transferAction.getCount() == sourceAmount) { //release all plan.add(Click.LEFT, destSlot); @@ -228,7 +230,7 @@ public abstract class InventoryTranslator { plan.add(Click.RIGHT, destSlot); } } - } else if (isCursor(transferAction.getDestination())) { //picking up into cursor + } else if (isDestCursor) { //picking up into cursor GeyserItemStack sourceItem = plan.getItem(sourceSlot); int sourceAmount = sourceItem.getAmount(); if (cursor.isEmpty()) { //picking up into empty cursor @@ -285,26 +287,38 @@ public abstract class InventoryTranslator { } case SWAP: { SwapStackRequestActionData swapAction = (SwapStackRequestActionData) action; - if (!(checkNetId(session, inventory, swapAction.getSource()) && checkNetId(session, inventory, swapAction.getDestination()))) { + StackRequestSlotInfoData source = swapAction.getSource(); + StackRequestSlotInfoData destination = swapAction.getDestination(); + + if (!(checkNetId(session, inventory, source) && checkNetId(session, inventory, destination))) { if (session.getGeyser().getConfig().isDebugMode()) { session.getGeyser().getLogger().error("DEBUG: About to reject SWAP request made by " + session.name()); - dumpStackRequestDetails(session, inventory, swapAction.getSource(), swapAction.getDestination()); + dumpStackRequestDetails(session, inventory, source, destination); } return rejectRequest(request); } - int sourceSlot = bedrockSlotToJava(swapAction.getSource()); - int destSlot = bedrockSlotToJava(swapAction.getDestination()); - boolean isSourceCursor = isCursor(swapAction.getSource()); - boolean isDestCursor = isCursor(swapAction.getDestination()); + int sourceSlot = bedrockSlotToJava(source); + int destSlot = bedrockSlotToJava(destination); + boolean isSourceCursor = isCursor(source); + boolean isDestCursor = isCursor(destination); - if (shouldRejectItemPlace(session, inventory, swapAction.getSource().getContainer(), + if (shouldRejectItemPlace(session, inventory, source.getContainer(), isSourceCursor ? -1 : sourceSlot, - swapAction.getDestination().getContainer(), isDestCursor ? -1 : destSlot)) { + destination.getContainer(), isDestCursor ? -1 : destSlot)) { // This item would not be here in Java return rejectRequest(request, false); } + if (!isSourceCursor && destination.getContainer() == ContainerSlotType.HOTBAR || destination.getContainer() == ContainerSlotType.HOTBAR_AND_INVENTORY) { + // Tell the server we're pressing one of the hotbar keys to save clicks + Click click = InventoryUtils.getClickForHotbarSwap(destination.getSlot()); + if (click != null) { + plan.add(click, sourceSlot); + break; + } + } + if (isSourceCursor && isDestCursor) { //??? return rejectRequest(request); } else if (isSourceCursor) { //swap cursor @@ -416,6 +430,8 @@ public abstract class InventoryTranslator { int leftover = 0; ClickPlan plan = new ClickPlan(session, this, inventory); + // Track all the crafting table slots to report back the contents of the slots after crafting + IntSet affectedSlots = new IntOpenHashSet(); for (StackRequestActionData action : request.getActions()) { switch (action.getType()) { case CRAFT_RECIPE: { @@ -447,6 +463,7 @@ public abstract class InventoryTranslator { return rejectRequest(request); } craftState = CraftState.INGREDIENTS; + affectedSlots.add(bedrockSlotToJava(((ConsumeStackRequestActionData) action).getSource())); break; } case TAKE: @@ -507,23 +524,17 @@ public abstract class InventoryTranslator { } } plan.execute(false); - return acceptRequest(request, makeContainerEntries(session, inventory, plan.getAffectedSlots())); + affectedSlots.addAll(plan.getAffectedSlots()); + return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - int gridSize; - int gridDimensions; - if (this instanceof PlayerInventoryTranslator) { - gridSize = 4; - gridDimensions = 2; - } else if (this instanceof CraftingInventoryTranslator) { - gridSize = 9; - gridDimensions = 3; - } else { + final int gridSize = getGridSize(); + if (gridSize == -1) { return rejectRequest(request); } + int gridDimensions = gridSize == 4 ? 2 : 3; - Recipe recipe; Ingredient[] ingredients = new Ingredient[0]; ItemStack output = null; int recipeWidth = 0; @@ -552,7 +563,7 @@ public abstract class InventoryTranslator { craftState = CraftState.RECIPE_ID; int recipeId = autoCraftAction.getRecipeNetworkId(); - recipe = session.getCraftingRecipes().get(recipeId); + GeyserRecipe recipe = session.getCraftingRecipes().get(recipeId); if (recipe == null) { return rejectRequest(request); } @@ -566,24 +577,21 @@ public abstract class InventoryTranslator { } } - switch (recipe.getType()) { - case CRAFTING_SHAPED -> { - ShapedRecipeData shapedData = (ShapedRecipeData) recipe.getData(); - ingredients = shapedData.getIngredients(); - recipeWidth = shapedData.getWidth(); - output = shapedData.getResult(); - if (shapedData.getWidth() > gridDimensions || shapedData.getHeight() > gridDimensions) { - return rejectRequest(request); - } + if (recipe.isShaped()) { + GeyserShapedRecipe shapedRecipe = (GeyserShapedRecipe) recipe; + ingredients = shapedRecipe.ingredients(); + recipeWidth = shapedRecipe.width(); + output = shapedRecipe.result(); + if (recipeWidth > gridDimensions || shapedRecipe.height() > gridDimensions) { + return rejectRequest(request); } - case CRAFTING_SHAPELESS -> { - ShapelessRecipeData shapelessData = (ShapelessRecipeData) recipe.getData(); - ingredients = shapelessData.getIngredients(); - recipeWidth = gridDimensions; - output = shapelessData.getResult(); - if (ingredients.length > gridSize) { - return rejectRequest(request); - } + } else { + GeyserShapelessRecipe shapelessRecipe = (GeyserShapelessRecipe) recipe; + ingredients = shapelessRecipe.ingredients(); + recipeWidth = gridDimensions; + output = shapelessRecipe.result(); + if (ingredients.length > gridSize) { + return rejectRequest(request); } } break; @@ -707,7 +715,7 @@ public abstract class InventoryTranslator { /** * Handled in {@link PlayerInventoryTranslator} */ - public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + protected ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { return rejectRequest(request); } @@ -742,14 +750,14 @@ public abstract class InventoryTranslator { } } - public static ItemStackResponsePacket.Response acceptRequest(ItemStackRequest request, List containerEntries) { + protected static ItemStackResponsePacket.Response acceptRequest(ItemStackRequest request, List containerEntries) { return new ItemStackResponsePacket.Response(ItemStackResponsePacket.ResponseStatus.OK, request.getRequestId(), containerEntries); } /** * Reject an incorrect ItemStackRequest. */ - public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequest request) { + protected static ItemStackResponsePacket.Response rejectRequest(ItemStackRequest request) { return rejectRequest(request, true); } @@ -759,7 +767,7 @@ public abstract class InventoryTranslator { * @param throwError whether this request was truly erroneous (true), or known as an outcome and should not be treated * as bad (false). */ - public static ItemStackResponsePacket.Response rejectRequest(ItemStackRequest request, boolean throwError) { + protected static ItemStackResponsePacket.Response rejectRequest(ItemStackRequest request, boolean throwError) { if (throwError && GeyserImpl.getInstance().getConfig().isDebugMode()) { new Throwable("DEBUGGING: ItemStackRequest rejected " + request.toString()).printStackTrace(); } @@ -834,12 +842,15 @@ public abstract class InventoryTranslator { return -1; } - public List makeContainerEntries(GeyserSession session, Inventory inventory, Set affectedSlots) { + protected final List makeContainerEntries(GeyserSession session, Inventory inventory, IntSet affectedSlots) { Map> containerMap = new HashMap<>(); - for (int slot : affectedSlots) { + // Manually call iterator to prevent Integer boxing + IntIterator it = affectedSlots.iterator(); + while (it.hasNext()) { + int slot = it.nextInt(); BedrockContainerSlot bedrockSlot = javaSlotToBedrockContainer(slot); - List list = containerMap.computeIfAbsent(bedrockSlot.getContainer(), k -> new ArrayList<>()); - list.add(makeItemEntry(session, bedrockSlot.getSlot(), inventory.getItem(slot))); + List list = containerMap.computeIfAbsent(bedrockSlot.container(), k -> new ArrayList<>()); + list.add(makeItemEntry(session, bedrockSlot.slot(), inventory.getItem(slot))); } List containerEntries = new ArrayList<>(); @@ -853,7 +864,7 @@ public abstract class InventoryTranslator { return containerEntries; } - public static ItemStackResponsePacket.ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) { + private static ItemStackResponsePacket.ItemEntry makeItemEntry(GeyserSession session, int bedrockSlot, GeyserItemStack itemStack) { ItemStackResponsePacket.ItemEntry itemEntry; if (!itemStack.isEmpty()) { // As of 1.16.210: Bedrock needs confirmation on what the current item durability is. 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 b59914a13..fc4090c73 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java index d035543bc..a7b736d72 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/LoomInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -41,13 +41,13 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequ import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; -import org.geysermc.geyser.translator.inventory.item.BannerTranslator; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator; import java.util.Collections; import java.util.List; @@ -102,7 +102,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } @Override - public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, + protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) { if (javaDestinationSlot != 1) { return false; @@ -117,7 +117,7 @@ public class LoomInventoryTranslator extends AbstractBlockInventoryTranslator { } @Override - public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { // If the LOOM_MATERIAL slot is not empty, we are crafting a pattern that does not come from an item // Remove the CRAFT_NON_IMPLEMENTED_DEPRECATED when 1.17.30 is dropped return (action.getType() == StackRequestActionType.CRAFT_NON_IMPLEMENTED_DEPRECATED || action.getType() == StackRequestActionType.CRAFT_LOOM) diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java index cf0c475f0..061f6c5ea 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/MerchantInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,12 +26,15 @@ package org.geysermc.geyser.translator.inventory; import com.github.steveice10.mc.protocol.data.game.inventory.ContainerType; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData; import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ItemStackRequest; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.AutoCraftRecipeStackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket; import org.geysermc.geyser.entity.type.Entity; @@ -44,6 +47,9 @@ import org.geysermc.geyser.inventory.BedrockContainerSlot; import org.geysermc.geyser.inventory.SlotType; import org.geysermc.geyser.inventory.updater.InventoryUpdater; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; +import org.geysermc.geyser.util.InventoryUtils; + +import java.util.concurrent.TimeUnit; public class MerchantInventoryTranslator extends BaseInventoryTranslator { private final InventoryUpdater updater; @@ -131,11 +137,53 @@ public class MerchantInventoryTranslator extends BaseInventoryTranslator { } } + @Override + public ItemStackResponsePacket.Response translateCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + // Behavior as of 1.18.10. + // We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to + // store a map of net ID to trade index on our end. + int tradeChoice = ((CraftRecipeStackRequestActionData) request.getActions()[0]).getRecipeNetworkId() - 1; + return handleTrade(session, inventory, request, tradeChoice); + } + @Override public ItemStackResponsePacket.Response translateAutoCraftingRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - // We're not crafting here - // Called at least by consoles when pressing a trade option button - return translateRequest(session, inventory, request); + // 1.18.10 update - seems impossible to call without consoles/controller input + // We set the net ID to the trade index + 1. This doesn't appear to cause issues and means we don't have to + // store a map of net ID to trade index on our end. + int tradeChoice = ((AutoCraftRecipeStackRequestActionData) request.getActions()[0]).getRecipeNetworkId() - 1; + return handleTrade(session, inventory, request, tradeChoice); + } + + private ItemStackResponsePacket.Response handleTrade(GeyserSession session, Inventory inventory, ItemStackRequest request, int tradeChoice) { + ServerboundSelectTradePacket packet = new ServerboundSelectTradePacket(tradeChoice); + session.sendDownstreamPacket(packet); + + if (session.isEmulatePost1_14Logic()) { + // 1.18 Java cooperates nicer than older versions + if (inventory instanceof MerchantContainer merchantInventory) { + merchantInventory.onTradeSelected(session, tradeChoice); + } + return translateRequest(session, inventory, request); + } else { + // 1.18 servers works fine without a workaround, but ViaVersion needs to work around 1.13 servers, + // so we need to work around that with the delay. Specifically they force a window refresh after a + // trade packet has been sent. + session.scheduleInEventLoop(() -> { + if (inventory instanceof MerchantContainer merchantInventory) { + merchantInventory.onTradeSelected(session, tradeChoice); + // Ignore output since we don't want to send a delayed response packet back to the client + translateRequest(session, inventory, request); + + // Resync items once more + updateInventory(session, inventory); + InventoryUtils.updateCursor(session); + } + }, 100, TimeUnit.MILLISECONDS); + + // Revert this request, for now + return rejectRequest(request); + } } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java index 0fd9f114f..e2349e5a5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/PlayerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -35,6 +35,7 @@ import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.*; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; +import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import org.geysermc.geyser.inventory.*; @@ -55,6 +56,11 @@ public class PlayerInventoryTranslator extends InventoryTranslator { super(46); } + @Override + public int getGridSize() { + return 4; + } + @Override public void updateInventory(GeyserSession session, Inventory inventory) { updateCraftingGrid(session, inventory); @@ -370,14 +376,17 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } } } - for (int slot : affectedSlots) { + // Manually call iterator to prevent Integer boxing + IntIterator it = affectedSlots.iterator(); + while (it.hasNext()) { + int slot = it.nextInt(); sendCreativeAction(session, inventory, slot); } return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); } @Override - public ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + protected ItemStackResponsePacket.Response translateCreativeRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { ItemStack javaCreativeItem = null; IntSet affectedSlots = new IntOpenHashSet(); CraftState craftState = CraftState.START; @@ -401,7 +410,6 @@ public class PlayerInventoryTranslator extends InventoryTranslator { break; } case CRAFT_RESULTS_DEPRECATED: { - CraftResultsDeprecatedStackRequestActionData deprecatedCraftAction = (CraftResultsDeprecatedStackRequestActionData) action; if (craftState != CraftState.RECIPE_ID) { return rejectRequest(request); } @@ -453,11 +461,36 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } break; } + case DROP: { + // Can be replicated as of 1.18.2 Bedrock on mobile by clicking from the creative menu to outside it + if (craftState != CraftState.DEPRECATED) { + return rejectRequest(request); + } + + DropStackRequestActionData dropAction = (DropStackRequestActionData) action; + if (dropAction.getSource().getContainer() != ContainerSlotType.CREATIVE_OUTPUT || dropAction.getSource().getSlot() != 50) { + return rejectRequest(request); + } + + ItemStack dropStack; + if (dropAction.getCount() == javaCreativeItem.getAmount()) { + dropStack = javaCreativeItem; + } else { + // Specify custom count + dropStack = new ItemStack(javaCreativeItem.getId(), dropAction.getCount(), javaCreativeItem.getNbt()); + } + ServerboundSetCreativeModeSlotPacket creativeDropPacket = new ServerboundSetCreativeModeSlotPacket(-1, dropStack); + session.sendDownstreamPacket(creativeDropPacket); + break; + } default: return rejectRequest(request); } } - for (int slot : affectedSlots) { + // Manually call iterator to prevent Integer boxing + IntIterator it = affectedSlots.iterator(); + while (it.hasNext()) { + int slot = it.nextInt(); sendCreativeAction(session, inventory, slot); } return acceptRequest(request, makeContainerEntries(session, inventory, affectedSlots)); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index f92474fb3..f77ff2229 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java index 4e34bca14..3aaa5ed07 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/SmithingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java index e7140f7b2..e0e2e27bd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/StonecutterInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,20 +31,14 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.Ser import com.nukkitx.protocol.bedrock.data.inventory.ContainerSlotType; import com.nukkitx.protocol.bedrock.data.inventory.ItemStackRequest; import com.nukkitx.protocol.bedrock.data.inventory.StackRequestSlotInfoData; -import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftResultsDeprecatedStackRequestActionData; +import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.CraftRecipeStackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionData; import com.nukkitx.protocol.bedrock.data.inventory.stackrequestactions.StackRequestActionType; import com.nukkitx.protocol.bedrock.packet.ItemStackResponsePacket; -import it.unimi.dsi.fastutil.ints.IntList; -import org.geysermc.geyser.inventory.GeyserItemStack; -import org.geysermc.geyser.inventory.Inventory; -import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.inventory.StonecutterContainer; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.inventory.BedrockContainerSlot; -import org.geysermc.geyser.inventory.SlotType; +import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.inventory.updater.UIInventoryUpdater; -import org.geysermc.geyser.translator.inventory.item.ItemTranslator; +import org.geysermc.geyser.session.GeyserSession; public class StonecutterInventoryTranslator extends AbstractBlockInventoryTranslator { public StonecutterInventoryTranslator() { @@ -52,32 +46,27 @@ public class StonecutterInventoryTranslator extends AbstractBlockInventoryTransl } @Override - public boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { - // First is pre-1.18. TODO remove after 1.17.40 support is dropped and refactor stonecutter support to use CraftRecipeStackRequestActionData's recipe ID - return action.getType() == StackRequestActionType.CRAFT_NON_IMPLEMENTED_DEPRECATED || action.getType() == StackRequestActionType.CRAFT_RECIPE; + protected boolean shouldHandleRequestFirst(StackRequestActionData action, Inventory inventory) { + return action.getType() == StackRequestActionType.CRAFT_RECIPE; } @Override - public ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { - // TODO: Also surely to change in the future - StackRequestActionData data = request.getActions()[1]; - if (!(data instanceof CraftResultsDeprecatedStackRequestActionData craftData)) { + protected ItemStackResponsePacket.Response translateSpecialRequest(GeyserSession session, Inventory inventory, ItemStackRequest request) { + // Guarded by shouldHandleRequestFirst + CraftRecipeStackRequestActionData data = (CraftRecipeStackRequestActionData) request.getActions()[0]; + + // Look up all possible options of cutting from this ID + GeyserStonecutterData craftingData = session.getStonecutterRecipes().get(data.getRecipeNetworkId()); + if (craftingData == null) { return rejectRequest(request); } StonecutterContainer container = (StonecutterContainer) inventory; - // Get the ID of the item we are cutting - int id = inventory.getItem(0).getJavaId(); - // Look up all possible options of cutting from this ID - IntList results = session.getStonecutterRecipes().get(id); - if (results == null) { - return rejectRequest(request); - } - - ItemStack javaOutput = ItemTranslator.translateToJava(craftData.getResultItems()[0], session.getItemMappings()); - int button = results.indexOf(javaOutput.getId()); + int button = craftingData.buttonId(); // If we've already pressed the button with this item, no need to press it again! if (container.getStonecutterButton() != button) { + ItemStack javaOutput = craftingData.output(); + // Getting the index of the item in the Java stonecutter list ServerboundContainerButtonClickPacket packet = new ServerboundContainerButtonClickPacket(inventory.getId(), button); session.sendDownstreamPacket(packet); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/ChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/ChestInventoryTranslator.java index 417aa5bf3..65d789c0b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/ChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/ChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -42,7 +42,7 @@ public abstract class ChestInventoryTranslator extends BaseInventoryTranslator { } @Override - public boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, + protected boolean shouldRejectItemPlace(GeyserSession session, Inventory inventory, ContainerSlotType bedrockSourceContainer, int javaSourceSlot, ContainerSlotType bedrockDestinationContainer, int javaDestinationSlot) { // Reject any item placements that occur in the unusable inventory space if (bedrockSourceContainer == ContainerSlotType.CONTAINER && javaSourceSlot >= this.size) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java index a42001d34..fc3279de1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/DoubleChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java index 86696b21b..4d158c4fe 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/chest/SingleChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java index de7ea4de7..472f92b4d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/AbstractFurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java index 7839d5370..67b4a1fab 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/BlastFurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java index 5c9030197..756b296e8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/FurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java index 350e00de3..1a6b5ac3e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/furnace/SmokerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java index b4c49cb12..064793d29 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/AbstractHorseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java index 79f34da57..035f8efa2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/ChestedHorseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/DonkeyInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/DonkeyInventoryTranslator.java index ea0a580f0..72972fb3b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/DonkeyInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/DonkeyInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java index 429125362..9ca153c5f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/HorseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/LlamaInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/LlamaInventoryTranslator.java index 97aa7edf2..ca0f85938 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/LlamaInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/horse/LlamaInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CompassTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CompassTranslator.java index 7367e28db..4c2978082 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CompassTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/CompassTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,42 +26,45 @@ package org.geysermc.geyser.translator.inventory.item; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @ItemRemapper public class CompassTranslator extends ItemTranslator { - private final List appliedItems; - - public CompassTranslator() { - appliedItems = Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) - .getItems() - .values() - .stream() - .filter(entry -> entry.getJavaIdentifier().endsWith("compass")) - .collect(Collectors.toList()); + @Override + protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + if (isLodestoneCompass(itemStack.getNbt())) { + // NBT will be translated in nbt/LodestoneCompassTranslator if applicable + return super.translateToBedrock(itemStack, mappings.getLodestoneCompass(), mappings); + } + return super.translateToBedrock(itemStack, mapping, mappings); } @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings); - - Tag lodestoneTag = itemStack.getNbt().get("LodestoneTracked"); - if (lodestoneTag instanceof ByteTag) { - // Get the fake lodestonecompass entry - mapping = mappings.getStoredItems().lodestoneCompass(); - // NBT will be translated in nbt/LodestoneCompassTranslator + protected ItemMapping getItemMapping(int javaId, CompoundTag nbt, ItemMappings mappings) { + if (isLodestoneCompass(nbt)) { + return mappings.getLodestoneCompass(); } + return super.getItemMapping(javaId, nbt, mappings); + } - return super.translateToBedrock(itemStack, mapping, mappings); + private boolean isLodestoneCompass(CompoundTag nbt) { + if (nbt != null) { + Tag lodestoneTag = nbt.get("LodestoneTracked"); + return lodestoneTag instanceof ByteTag; + } + return false; } @Override @@ -76,6 +79,9 @@ public class CompassTranslator extends ItemTranslator { @Override public List getAppliedItems() { - return appliedItems; + return Arrays.stream(Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems()) + .filter(entry -> entry.getJavaIdentifier().endsWith("compass")) + .collect(Collectors.toList()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/FilledMapTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/FilledMapTranslator.java new file mode 100644 index 000000000..3dfa2d82f --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/FilledMapTranslator.java @@ -0,0 +1,68 @@ +/* + * 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.translator.inventory.item; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; +import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import org.geysermc.geyser.network.MinecraftProtocol; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; + +import java.util.Collections; +import java.util.List; + +@ItemRemapper +public class FilledMapTranslator extends ItemTranslator { + + @Override + protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); + CompoundTag nbt = itemStack.getNbt(); + if (nbt != null && nbt.get("display") instanceof CompoundTag display) { + // Note: damage 5 treasure map, 6 ??? + Tag mapColor = display.get("MapColor"); + if (mapColor != null && mapColor.getValue() instanceof Number color) { + // Java Edition allows any color; Bedrock only allows some. So let's take what colors we can get + switch (color.intValue()) { + case 3830373 -> builder.damage(3); // Ocean Monument + case 5393476 -> builder.damage(4); // Woodland explorer + } + } + } + return builder; + } + + @Override + public List getAppliedItems() { + return Collections.singletonList( + Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getMapping("minecraft:filled_map") + ); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemRemapper.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemRemapper.java index 651228c15..937d6d062 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemRemapper.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemRemapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java index 84ab0dc55..539d20207 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/ItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,16 +34,20 @@ import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; -import org.geysermc.geyser.util.FileUtils; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.text.MessageTranslator; +import org.geysermc.geyser.util.FileUtils; import javax.annotation.Nonnull; +import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.stream.Collectors; @@ -68,11 +72,11 @@ public abstract class ItemTranslator { try { if (NbtItemStackTranslator.class.isAssignableFrom(clazz)) { - NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.newInstance(); + NbtItemStackTranslator nbtItemTranslator = (NbtItemStackTranslator) clazz.getDeclaredConstructor().newInstance(); loadedNbtItemTranslators.put(nbtItemTranslator, priority); continue; } - ItemTranslator itemStackTranslator = (ItemTranslator) clazz.newInstance(); + ItemTranslator itemStackTranslator = (ItemTranslator) clazz.getDeclaredConstructor().newInstance(); List appliedItems = itemStackTranslator.getAppliedItems(); for (ItemMapping item : appliedItems) { ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId()); @@ -84,7 +88,7 @@ public abstract class ItemTranslator { } ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator); } - } catch (InstantiationException | IllegalAccessException e) { + } catch (InstantiationException | InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { GeyserImpl.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName()); } } @@ -155,18 +159,13 @@ public abstract class ItemTranslator { nbt = translateDisplayProperties(session, nbt, bedrockItem); if (session.isAdvancedTooltips()) { - nbt = addAdvancedTooltips(nbt, session.getItemMappings().getMapping(stack), session.getLocale()); + nbt = addAdvancedTooltips(nbt, bedrockItem, session.getLocale()); } ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), nbt); - ItemData.Builder builder; - ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId()); - if (itemStackTranslator != null) { - builder = itemStackTranslator.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); - } else { - builder = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); - } + ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.getOrDefault(bedrockItem.getJavaId(), DEFAULT_TRANSLATOR); + ItemData.Builder builder = itemStackTranslator.translateToBedrock(itemStack, bedrockItem, session.getItemMappings()); if (bedrockItem.isBlock()) { builder.blockRuntimeId(bedrockItem.getBedrockBlockId()); } @@ -206,15 +205,31 @@ public abstract class ItemTranslator { int maxDurability = mapping.getMaxDamage(); if (maxDurability != 0) { - int durability = maxDurability - ((IntTag) newNbt.get("Damage")).getValue(); - if (durability != maxDurability) { - listTag.add(new StringTag("", "§r§f" + String.format(MessageTranslator.convertMessage("item.durability", language), durability, maxDurability))); + Tag durabilityTag = newNbt.get("Damage"); + if (durabilityTag instanceof IntTag) { + int durability = maxDurability - ((IntTag) durabilityTag).getValue(); + if (durability != maxDurability) { + Component component = Component.text() + .resetStyle() + .color(NamedTextColor.WHITE) + .append(Component.translatable("item.durability", + Component.text(durability), + Component.text(maxDurability))) + .build(); + listTag.add(new StringTag("", MessageTranslator.convertMessage(component, language))); + } } } listTag.add(new StringTag("", "§r§8" + mapping.getJavaIdentifier())); if (nbt != null) { - listTag.add(new StringTag("", "§r§8" + String.format(MessageTranslator.convertMessage("item.nbt_tags", language), nbt.size()))); + Component component = Component.text() + .resetStyle() + .color(NamedTextColor.DARK_GRAY) + .append(Component.translatable("item.nbt_tags", + Component.text(nbt.size()))) + .build(); + listTag.add(new StringTag("", MessageTranslator.convertMessage(component, language))); } compoundTag.put(listTag); newNbt.put(compoundTag); @@ -245,6 +260,19 @@ public abstract class ItemTranslator { return canModifyBedrock; } + /** + * Given an item stack, determine the item mapping that should be applied to Bedrock players. + */ + @Nonnull + public static ItemMapping getBedrockItemMapping(GeyserSession session, @Nonnull GeyserItemStack itemStack) { + if (itemStack.isEmpty()) { + return ItemMapping.AIR; + } + int javaId = itemStack.getJavaId(); + return ITEM_STACK_TRANSLATORS.getOrDefault(javaId, DEFAULT_TRANSLATOR) + .getItemMapping(javaId, itemStack.getNbt(), session.getItemMappings()); + } + private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() { @Override public List getAppliedItems() { @@ -252,7 +280,7 @@ public abstract class ItemTranslator { } }; - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { if (itemStack == null) { // Return, essentially, air return ItemData.builder(); @@ -275,9 +303,16 @@ public abstract class ItemTranslator { return new ItemStack(mapping.getJavaId(), itemData.getCount(), this.translateToJavaNBT("", itemData.getTag())); } + /** + * Used for initialization only and only called once. + */ public abstract List getAppliedItems(); - public NbtMap translateNbtToBedrock(CompoundTag tag) { + protected ItemMapping getItemMapping(int javaId, CompoundTag nbt, ItemMappings mappings) { + return mappings.getMapping(javaId); + } + + protected NbtMap translateNbtToBedrock(CompoundTag tag) { NbtMapBuilder builder = NbtMap.builder(); if (tag.getValue() != null && !tag.getValue().isEmpty()) { for (String str : tag.getValue().keySet()) { @@ -356,7 +391,7 @@ public abstract class ItemTranslator { return null; } - public CompoundTag translateToJavaNBT(String name, NbtMap tag) { + private CompoundTag translateToJavaNBT(String name, NbtMap tag) { CompoundTag javaTag = new CompoundTag(name); Map javaValue = javaTag.getValue(); if (tag != null && !tag.isEmpty()) { @@ -451,9 +486,8 @@ public abstract class ItemTranslator { public static CompoundTag translateDisplayProperties(GeyserSession session, CompoundTag tag, ItemMapping mapping, char translationColor) { boolean hasCustomName = false; if (tag != null) { - CompoundTag display = tag.get("display"); - if (display != null && display.contains("Name")) { - String name = ((StringTag) display.get("Name")).getValue(); + if (tag.get("display") instanceof CompoundTag display && display.get("Name") instanceof StringTag tagName) { + String name = tagName.getValue(); // Get the translated name and prefix it with a reset char name = MessageTranslator.convertMessageLenient(name, session.getLocale()); @@ -473,8 +507,10 @@ public abstract class ItemTranslator { if (tag == null) { tag = new CompoundTag(""); } - CompoundTag display = tag.get("display"); - if (display == null) { + CompoundTag display; + if (tag.get("display") instanceof CompoundTag oldDisplay) { + display = oldDisplay; + } else { display = new CompoundTag("display"); // Add to the new root tag tag.put(display); diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/NbtItemStackTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/NbtItemStackTranslator.java index 6c2c501fd..bfa7ebc2e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/NbtItemStackTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/NbtItemStackTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -29,12 +29,12 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.registry.type.ItemMapping; -public class NbtItemStackTranslator { +public abstract class NbtItemStackTranslator { /** * Translate the item NBT to Bedrock * @param session the client's current session - * @param itemTag the item's CompoundTag + * @param itemTag the item's CompoundTag (cloned from Geyser's cached copy) * @param mapping Geyser's item mapping */ public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java index 5455b1189..bf16af38f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/PotionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,25 +36,15 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @ItemRemapper public class PotionTranslator extends ItemTranslator { - private final List appliedItems; - - public PotionTranslator() { - appliedItems = Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) - .getItems() - .values() - .stream() - .filter(entry -> entry.getJavaIdentifier().endsWith("potion")) - .collect(Collectors.toList()); - } - @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, mapping, mappings); Tag potionTag = itemStack.getNbt().get("Potion"); if (potionTag instanceof StringTag) { @@ -84,6 +74,9 @@ public class PotionTranslator extends ItemTranslator { @Override public List getAppliedItems() { - return appliedItems; + return Arrays.stream(Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems()) + .filter(entry -> entry.getJavaIdentifier().endsWith("potion")) + .collect(Collectors.toList()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/TippedArrowTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/TippedArrowTranslator.java index 01ecbb09f..d831ce586 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/TippedArrowTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/TippedArrowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -36,30 +36,18 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; +import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @ItemRemapper public class TippedArrowTranslator extends ItemTranslator { - - private final List appliedItems; - private static final int TIPPED_ARROW_JAVA_ID = Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) .getMapping("minecraft:tipped_arrow") .getJavaId(); - public TippedArrowTranslator() { - appliedItems = Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) - .getItems() - .values() - .stream() - .filter(entry -> entry.getJavaIdentifier().contains("arrow") - && !entry.getJavaIdentifier().contains("spectral")) - .collect(Collectors.toList()); - } - @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { + protected ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { if (!mapping.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) { // We're only concerned about minecraft:arrow when translating Bedrock -> Java return super.translateToBedrock(itemStack, mapping, mappings); @@ -93,6 +81,10 @@ public class TippedArrowTranslator extends ItemTranslator { @Override public List getAppliedItems() { - return appliedItems; + return Arrays.stream(Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems()) + .filter(entry -> entry.getJavaIdentifier().contains("arrow") + && !entry.getJavaIdentifier().contains("spectral")) + .collect(Collectors.toList()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java index 071ead230..c3abf2495 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/AxolotlBucketTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/BannerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java similarity index 59% rename from core/src/main/java/org/geysermc/geyser/translator/inventory/item/BannerTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java index d2c9e5dd6..ed4865411 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/BannerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BannerTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,28 +23,25 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.inventory.item; +package org.geysermc.geyser.translator.inventory.item.nbt; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.nbt.NbtList; import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.geyser.network.MinecraftProtocol; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ItemMapping; -import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.item.ItemRemapper; +import org.geysermc.geyser.translator.inventory.item.NbtItemStackTranslator; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import javax.annotation.Nonnull; +import java.util.*; import java.util.stream.Collectors; @ItemRemapper -public class BannerTranslator extends ItemTranslator { +public class BannerTranslator extends NbtItemStackTranslator { /** * Holds what a Java ominous banner pattern looks like. * @@ -79,10 +76,8 @@ public class BannerTranslator extends ItemTranslator { } public BannerTranslator() { - appliedItems = Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) - .getItems() - .values() - .stream() + appliedItems = Arrays.stream(Registries.ITEMS.forVersion(MinecraftProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) + .getItems()) .filter(entry -> entry.getJavaIdentifier().endsWith("banner")) .collect(Collectors.toList()); } @@ -96,10 +91,7 @@ public class BannerTranslator extends ItemTranslator { public static NbtList convertBannerPattern(ListTag patterns) { List tagsList = new ArrayList<>(); for (Tag patternTag : patterns.getValue()) { - NbtMap newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); - if (newPatternTag != null) { - tagsList.add(newPatternTag); - } + tagsList.add(getBedrockBannerPattern((CompoundTag) patternTag)); } return new NbtList<>(NbtType.COMPOUND, tagsList); @@ -111,35 +103,14 @@ public class BannerTranslator extends ItemTranslator { * @param pattern Java edition pattern nbt * @return The Bedrock edition format pattern nbt */ - public static NbtMap getBedrockBannerPattern(CompoundTag pattern) { - String patternName = (String) pattern.get("Pattern").getValue(); - - // Return null if its the globe pattern as it doesn't exist on bedrock - if (patternName.equals("glb")) { - return null; - } - + @Nonnull + private static NbtMap getBedrockBannerPattern(CompoundTag pattern) { return NbtMap.builder() .putInt("Color", 15 - (int) pattern.get("Color").getValue()) - .putString("Pattern", patternName) + .putString("Pattern", (String) pattern.get("Pattern").getValue()) .build(); } - /** - * Convert a list of patterns from Bedrock nbt to Java nbt - * - * @param patterns The patterns to convert - * @return The new converted patterns - */ - public static ListTag convertBannerPattern(List patterns) { - List tagsList = new ArrayList<>(); - for (NbtMap patternTag : patterns) { - tagsList.add(getJavaBannerPattern(patternTag)); - } - - return new ListTag("Patterns", tagsList); - } - /** * Convert the Bedrock edition banner pattern nbt to Java edition * @@ -154,64 +125,54 @@ public class BannerTranslator extends ItemTranslator { return new CompoundTag("", tags); } - @Override - public ItemData.Builder translateToBedrock(ItemStack itemStack, ItemMapping mapping, ItemMappings mappings) { - if (itemStack.getNbt() == null) { - return super.translateToBedrock(itemStack, mapping, mappings); + /** + * Convert a list of patterns from Java nbt to Bedrock nbt, or vice versa (we just need to invert the color) + * + * @param patterns The patterns to convert + */ + private void invertBannerColors(ListTag patterns) { + for (Tag patternTag : patterns.getValue()) { + IntTag color = ((CompoundTag) patternTag).get("Color"); + color.setValue(15 - color.getValue()); } - - ItemData.Builder builder = super.translateToBedrock(itemStack, mapping, mappings); - - CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag"); - if (blockEntityTag != null && blockEntityTag.contains("Patterns")) { - ListTag patterns = blockEntityTag.get("Patterns"); - - NbtMapBuilder nbtBuilder = builder.build().getTag().toBuilder(); //TODO fix ugly hack - if (patterns.equals(OMINOUS_BANNER_PATTERN)) { - // Remove the current patterns and set the ominous banner type - nbtBuilder.remove("Patterns"); - nbtBuilder.putInt("Type", 1); - } else { - nbtBuilder.put("Patterns", convertBannerPattern(patterns)); - } - - builder.tag(nbtBuilder.build()); - } - - return builder; } @Override - public ItemStack translateToJava(ItemData itemData, ItemMapping mapping, ItemMappings mappings) { - if (itemData.getTag() == null) { - return super.translateToJava(itemData, mapping, mappings); + public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemMapping mapping) { + CompoundTag blockEntityTag = itemTag.get("BlockEntityTag"); + if (blockEntityTag != null && blockEntityTag.get("Patterns") instanceof ListTag patterns) { + if (patterns.equals(OMINOUS_BANNER_PATTERN)) { + // Remove the current patterns and set the ominous banner type + itemTag.put(new IntTag("Type", 1)); + } else { + invertBannerColors(patterns); + itemTag.put(patterns); + } + itemTag.remove("BlockEntityTag"); } + } - ItemStack itemStack = super.translateToJava(itemData, mapping, mappings); - - NbtMap nbtTag = itemData.getTag(); - if (nbtTag.containsKey("Type", NbtType.INT) && nbtTag.getInt("Type") == 1) { + @Override + public void translateToJava(CompoundTag itemTag, ItemMapping mapping) { + if (itemTag.get("Type") instanceof IntTag type && type.getValue() == 1) { // Ominous banner pattern - itemStack.getNbt().remove("Type"); + itemTag.remove("Type"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); blockEntityTag.put(OMINOUS_BANNER_PATTERN); - itemStack.getNbt().put(blockEntityTag); - } else if (nbtTag.containsKey("Patterns", NbtType.LIST)) { - List patterns = nbtTag.getList("Patterns", NbtType.COMPOUND); - + itemTag.put(blockEntityTag); + } else if (itemTag.get("Patterns") instanceof ListTag patterns) { CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(convertBannerPattern(patterns)); + invertBannerColors(patterns); + blockEntityTag.put(patterns); - itemStack.getNbt().put(blockEntityTag); - itemStack.getNbt().remove("Patterns"); // Remove the old Bedrock patterns list + itemTag.put(blockEntityTag); + itemTag.remove("Patterns"); // Remove the old Bedrock patterns list } - - return itemStack; } @Override - public List getAppliedItems() { - return appliedItems; + public boolean acceptItem(ItemMapping mapping) { + return appliedItems.contains(mapping); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java index 10ad58544..a507d02cc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BasicItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -51,13 +51,11 @@ public class BasicItemTranslator extends NbtItemStackTranslator { } } - CompoundTag displayTag = itemTag.get("display"); - if (displayTag == null) { + if (!(itemTag.get("display") instanceof CompoundTag displayTag)) { return; } - Tag loreTag = displayTag.get("Lore"); - if (loreTag instanceof ListTag listTag) { + if (displayTag.get("Lore") instanceof ListTag listTag) { List lore = new ArrayList<>(); for (Tag tag : listTag.getValue()) { if (!(tag instanceof StringTag)) continue; diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BookPagesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BookPagesTranslator.java index b3371aab7..ec741f261 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BookPagesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/BookPagesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java index e1dda45ed..723798c89 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/CrossbowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantedBookTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantedBookTranslator.java index 8a009bc2d..9b1d423c1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantedBookTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/EnchantedBookTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 ddc5f3780..cd6d5d6ff 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -121,23 +121,22 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { private CompoundTag remapEnchantment(CompoundTag tag) { - Tag javaEnchLvl = tag.get("lvl"); - if (!(javaEnchLvl instanceof ShortTag || javaEnchLvl instanceof IntTag)) - return null; - Tag javaEnchId = tag.get("id"); if (!(javaEnchId instanceof StringTag)) return null; Enchantment enchantment = Enchantment.getByJavaIdentifier(((StringTag) javaEnchId).getValue()); if (enchantment == null) { - GeyserImpl.getInstance().getLogger().debug("Unknown java enchantment: " + javaEnchId.getValue()); + GeyserImpl.getInstance().getLogger().debug("Unknown Java enchantment while NBT item translating: " + javaEnchId.getValue()); return null; } + Tag javaEnchLvl = tag.get("lvl"); + CompoundTag bedrockTag = new CompoundTag(""); bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal())); - bedrockTag.put(new ShortTag("lvl", ((Number) javaEnchLvl.getValue()).shortValue())); + // If the tag cannot parse, Java Edition 1.18.2 sets to 0 + bedrockTag.put(new ShortTag("lvl", javaEnchLvl != null && javaEnchLvl.getValue() instanceof Number lvl ? lvl.shortValue() : (short) 0)); return bedrockTag; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkBaseTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkBaseTranslator.java index c68f4f4d9..6a4438358 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkBaseTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkBaseTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkRocketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkRocketTranslator.java index 8c1154dea..566b0ac2b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkRocketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkRocketTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkStarTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkStarTranslator.java index e66589f6d..c907375b9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkStarTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/FireworkStarTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java index ddf76b595..9c74e7123 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LeatherArmorTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LodestoneCompassTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LodestoneCompassTranslator.java index 924735626..f4b91165d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LodestoneCompassTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/LodestoneCompassTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/MapItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/MapItemTranslator.java index 23739340e..80b22dafb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/MapItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/MapItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java index 1e182568a..680be00fd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/PlayerHeadTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/ShulkerBoxItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/ShulkerBoxItemTranslator.java index f4160ec08..1b9acdb96 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/ShulkerBoxItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/ShulkerBoxItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java index 316ebc1ae..dbacc75fe 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/item/nbt/TropicalFishBucketTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index 6cafb6012..537c93a41 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -42,6 +42,7 @@ import org.geysermc.geyser.level.chunk.bitarray.BitArray; import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.util.JavaCodecEntry; import org.geysermc.geyser.util.MathUtils; // Array index formula by https://wiki.vg/Chunk_Format @@ -55,27 +56,26 @@ public class BiomeTranslator { ListTag serverBiomes = worldGen.get("value"); session.setBiomeGlobalPalette(MathUtils.getGlobalPaletteForSize(serverBiomes.size())); - for (Tag tag : serverBiomes) { - CompoundTag biomeTag = (CompoundTag) tag; - + for (CompoundTag biomeTag : JavaCodecEntry.iterateAsTag(worldGen)) { String javaIdentifier = ((StringTag) biomeTag.get("name")).getValue(); - int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, -1); + int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); int javaId = ((IntTag) biomeTag.get("id")).getValue(); - if (bedrockId == -1) { - // There is no matching Bedrock variation for this biome; let's set the closest match based on biome category - String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue(); - String replacementBiome = switch (category) { - case "extreme_hills" -> "minecraft:mountains"; - case "icy" -> "minecraft:ice_spikes"; - case "mesa" -> "minecraft:badlands"; - case "mushroom" -> "minecraft:mushroom_fields"; - case "nether" -> "minecraft:nether_wastes"; - default -> "minecraft:ocean"; // Typically ID 0 so a good default - case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category; - }; - bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome); - } + // TODO - the category tag no longer exists - find a better replacement option +// if (bedrockId == -1) { +// // There is no matching Bedrock variation for this biome; let's set the closest match based on biome category +// String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue(); +// String replacementBiome = switch (category) { +// case "extreme_hills" -> "minecraft:mountains"; +// case "icy" -> "minecraft:ice_spikes"; +// case "mesa" -> "minecraft:badlands"; +// case "mushroom" -> "minecraft:mushroom_fields"; +// case "nether" -> "minecraft:nether_wastes"; +// default -> "minecraft:ocean"; // Typically ID 0 so a good default +// case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category; +// }; +// bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome); +// } // When we see the Java ID, we should instead apply the Bedrock ID biomeTranslations.put(javaId, bedrockId); @@ -126,11 +126,10 @@ public class BiomeTranslator { storage = new BlockStorage(bitArray, bedrockPalette); } else { storage = new BlockStorage(0); - BitArray bitArray = storage.getBitArray(); // Each section of biome corresponding to a chunk section contains 4 * 4 * 4 entries for (int i = 0; i < 64; i++) { - int javaId = biomeData.getPalette().idToState(biomeData.getStorage().get(i)); + int javaId = palette.idToState(biomeData.getStorage().get(i)); int x = i & 3; int y = (i >> 4) & 3; int z = (i >> 2) & 3; @@ -139,7 +138,9 @@ public class BiomeTranslator { int idx = storage.idFor(biomeId); // Convert biome coordinates into block coordinates // Bedrock expects a full 4096 blocks - multiplyIdToStorage(bitArray, idx, x, y, z); + // Implementation note: storage.getBitArray() must be called and not stored - if the palette + // grows, then the instance can change + multiplyIdToStorage(storage.getBitArray(), idx, x, y, z); } } return storage; diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java index 9cd1981c6..725a17e7a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BannerBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,9 +28,10 @@ package org.geysermc.geyser.translator.level.block.entity; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; 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 com.nukkitx.nbt.NbtMapBuilder; -import org.geysermc.geyser.translator.inventory.item.BannerTranslator; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.translator.inventory.item.nbt.BannerTranslator; @BlockEntity(type = BlockEntityType.BANNER) public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @@ -41,8 +42,11 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement builder.put("Base", 15 - bannerColor); } - if (tag.contains("Patterns")) { - ListTag patterns = tag.get("Patterns"); + if (tag == null) { + return; + } + + if (tag.get("Patterns") instanceof ListTag patterns) { if (patterns.equals(BannerTranslator.OMINOUS_BANNER_PATTERN)) { // This is an ominous banner; don't try to translate the raw patterns (it doesn't translate correctly) // and tell the Bedrock client that this is an ominous banner @@ -52,8 +56,9 @@ public class BannerBlockEntityTranslator extends BlockEntityTranslator implement } } - if (tag.contains("CustomName")) { - builder.put("CustomName", tag.get("CustomName").getValue()); + Tag customName = tag.get("CustomName"); + if (customName != null) { + builder.put("CustomName", customName.getValue()); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java index d6492bffe..7d1a8b514 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BeaconBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java index fe7971105..4ca9792ad 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java index 3534e5be7..94760b66c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BedrockOnlyBlockEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,7 +26,10 @@ package org.geysermc.geyser.translator.level.block.entity; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtList; import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtType; +import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; /** @@ -59,6 +62,18 @@ public interface BedrockOnlyBlockEntity extends RequiresBlockState { return FlowerPotBlockEntityTranslator.getTag(session, blockState, position); } else if (PistonBlockEntityTranslator.isBlock(blockState)) { return PistonBlockEntityTranslator.getTag(blockState, position); + } else if (BlockStateValues.isCauldron(blockState)) { + // As of 1.18.30: this is required to make rendering not look weird on chunk load (lava and snow cauldrons look dim) + return NbtMap.builder() + .putString("id", "Cauldron") + .putByte("isMovable", (byte) 0) + .putShort("PotionId", (short) -1) + .putShort("PotionType", (short) -1) + .putList("Items", NbtType.END, NbtList.EMPTY) + .putInt("x", position.getX()) + .putInt("y", position.getY()) + .putInt("z", position.getZ()) + .build(); } return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java index 32b765166..3e320029b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java index 602ac140c..83db13bc6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/BlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java index 7880f8106..53e1af8a5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CampfireBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java index 87221ab01..9700bd9bb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/CommandBlockBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java index b6a10dd8f..f5ec3607c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/DoubleChestBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java index e5abe74a7..bafb07753 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EmptyBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java index 530bcf241..9ff449055 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/EndGatewayBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java index b6c498d9f..845e2e429 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/FlowerPotBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java index a94804164..bb036a1b0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/JigsawBlockBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,16 +28,25 @@ package org.geysermc.geyser.translator.level.block.entity; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; +import com.github.steveice10.opennbt.tag.builtin.Tag; import com.nukkitx.nbt.NbtMapBuilder; +import org.geysermc.geyser.level.block.BlockStateValues; @BlockEntity(type = BlockEntityType.JIGSAW) -public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator { +public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @Override public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - builder.put("joint", ((StringTag) tag.get("joint")).getValue()); - builder.put("name", ((StringTag) tag.get("name")).getValue()); - builder.put("target_pool", ((StringTag) tag.get("pool")).getValue()); + Tag jointTag = tag.get("joint"); + if (jointTag instanceof StringTag) { + builder.put("joint", ((StringTag) jointTag).getValue()); + } else { + // Tag is not present in at least 1.14.4 Paper + // Minecraft 1.18.1 deliberately has a fallback here, but not for any other value + builder.put("joint", BlockStateValues.getHorizontalFacingJigsaws().contains(blockState) ? "aligned" : "rollable"); + } + builder.put("name", getOrDefault(tag.get("name"), "")); + builder.put("target_pool", getOrDefault(tag.get("pool"), "")); builder.put("final_state", ((StringTag) tag.get("final_state")).getValue()); - builder.put("target", ((StringTag) tag.get("target")).getValue()); + builder.put("target", getOrDefault(tag.get("target"), "")); } } 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 1363f6641..f6561ccbe 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java index 2f29cdef6..cf4d52859 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/PistonBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/RequiresBlockState.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/RequiresBlockState.java index 990ae314e..240886583 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/RequiresBlockState.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/RequiresBlockState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java index 8b934f29b..83e989f49 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java index 0eaabae12..bd3f96836 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SignBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java index 4286b2b21..94e2d4767 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SkullBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,27 +25,18 @@ package org.geysermc.geyser.translator.level.block.entity; -import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinProvider; -import org.geysermc.geyser.skin.SkullSkinManager; -import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.List; -import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.TimeUnit; @BlockEntity(type = BlockEntityType.SKULL) public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { @@ -62,7 +53,7 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements builder.put("SkullType", skullVariant); } - public static CompletableFuture getProfile(CompoundTag tag) { + private static CompletableFuture getTextures(CompoundTag tag) { CompoundTag owner = tag.get("SkullOwner"); if (owner != null) { CompoundTag properties = owner.get("Properties"); @@ -73,76 +64,23 @@ public class SkullBlockEntityTranslator extends BlockEntityTranslator implements ListTag textures = properties.get("textures"); LinkedHashMap tag1 = (LinkedHashMap) textures.get(0).getValue(); StringTag texture = (StringTag) tag1.get("Value"); - - List profileProperties = new ArrayList<>(); - - GameProfile gameProfile = new GameProfile(UUID.randomUUID(), ""); - profileProperties.add(new GameProfile.Property("textures", texture.getValue())); - gameProfile.setProperties(profileProperties); - return CompletableFuture.completedFuture(gameProfile); + return CompletableFuture.completedFuture(texture.getValue()); } return CompletableFuture.completedFuture(null); } - public static void spawnPlayer(GeyserSession session, CompoundTag tag, int posX, int posY, int posZ, int blockState) { - float x = posX + .5f; - float y = posY - .01f; - float z = posZ + .5f; - float rotation; - - byte floorRotation = BlockStateValues.getSkullRotation(blockState); - if (floorRotation == -1) { - // Wall skull - y += 0.25f; - rotation = BlockStateValues.getSkullWallDirections().get(blockState); - switch ((int) rotation) { - case 180 -> z += 0.24f; // North - case 0 -> z -= 0.24f; // South - case 90 -> x += 0.24f; // West - case 270 -> x -= 0.24f; // East - } - } else { - rotation = (180f + (floorRotation * 22.5f)) % 360; - } - + public static void translateSkull(GeyserSession session, CompoundTag tag, int posX, int posY, int posZ, int blockState) { Vector3i blockPosition = Vector3i.from(posX, posY, posZ); - Vector3f entityPosition = Vector3f.from(x, y, z); - - getProfile(tag).whenComplete((gameProfile, throwable) -> { - if (gameProfile == null) { + getTextures(tag).whenComplete((texturesProperty, throwable) -> { + if (texturesProperty == null) { session.getGeyser().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition + " " + tag); return; } - if (session.getEventLoop().inEventLoop()) { - spawnPlayer(session, gameProfile, blockPosition, entityPosition, rotation, blockState); + session.getSkullCache().putSkull(blockPosition, texturesProperty, blockState); } else { - session.executeInEventLoop(() -> spawnPlayer(session, gameProfile, blockPosition, entityPosition, rotation, blockState)); + session.executeInEventLoop(() -> session.getSkullCache().putSkull(blockPosition, texturesProperty, blockState)); } }); } - - private static void spawnPlayer(GeyserSession session, GameProfile profile, Vector3i blockPosition, - Vector3f entityPosition, float rotation, int blockState) { - long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); - - SkullPlayerEntity existingSkull = session.getSkullCache().get(blockPosition); - if (existingSkull != null) { - // Ensure that two skulls can't spawn on the same point - existingSkull.despawnEntity(blockPosition); - } - - SkullPlayerEntity player = new SkullPlayerEntity(session, geyserId, profile, entityPosition, rotation, blockState); - - // Cache entity - session.getSkullCache().put(blockPosition, player); - - player.spawnEntity(); - - SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.scheduleInEventLoop(() -> { - // Delay to minimize split-second "player" pop-in - player.setFlag(EntityFlag.INVISIBLE, false); - player.updateBedrockMetadata(); - }, 250, TimeUnit.MILLISECONDS))); - } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index d9aebc479..3d11d5ced 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java index c06998af4..03c40c796 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/LevelEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java index df882d0d0..820606675 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/PlaySoundEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java index 5c3e890a2..1cb3670fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundEventEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -40,7 +40,7 @@ public record SoundEventEventTranslator(SoundEvent soundEvent, levelSoundEvent.setIdentifier(identifier); levelSoundEvent.setExtraData(extraData); levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast()); - levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); + levelSoundEvent.setPosition(Vector3f.from(packet.getPosition().getX() + 0.5f, packet.getPosition().getY() + 0.5f, packet.getPosition().getZ() + 0.5f)); levelSoundEvent.setBabySound(false); session.sendUpstreamPacket(levelSoundEvent); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java index 48a4bf2fd..f59c5686d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/event/SoundLevelEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java index 37485120d..d49cdd6d0 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/PacketTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/Translator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/Translator.java index 3dc812170..f9d5e7771 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/Translator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/Translator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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/bedrock/BedrockAdventureSettingsTranslator.java index d4de9e22a..641161127 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockAdventureSettingsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -44,15 +44,15 @@ public class BedrockAdventureSettingsTranslator extends PacketTranslator { switch (packet.getAction()) { case SWING_ARM -> // Delay so entity damage can be processed first - session.scheduleInEventLoop(() -> - session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)), + session.scheduleInEventLoop(() -> { + session.sendDownstreamPacket(new ServerboundSwingPacket(Hand.MAIN_HAND)); + session.activateArmAnimationTicking(); + }, 25, TimeUnit.MILLISECONDS ); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java index 828f5a934..67f0d0d59 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockBlockEntityDataTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket; +import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import org.geysermc.geyser.session.GeyserSession; @@ -41,15 +41,11 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator SignUtils.JAVA_CHARACTER_WIDTH_MAX) { @@ -104,16 +100,13 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator { + case BOAT, CHEST_BOAT -> { // Include type of boat in the name int variant = ((BoatEntity) entity).getVariant(); String typeOfBoat = switch (variant) { @@ -61,9 +61,10 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator "jungle"; case 4 -> "acacia"; case 5 -> "dark_oak"; + case 6 -> "mangrove"; default -> "oak"; }; - itemName = typeOfBoat + "_boat"; + itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT); } case LEASH_KNOT -> itemName = "lead"; case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART -> diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java index b7961c8fb..4e729bc59 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockFilterTextTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,15 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundRenameItemPacket; import com.nukkitx.protocol.bedrock.packet.FilterTextPacket; import org.geysermc.geyser.inventory.AnvilContainer; import org.geysermc.geyser.inventory.CartographyContainer; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.ItemUtils; /** * Used to send strings to the server and filter out unwanted words. @@ -50,28 +47,7 @@ public class BedrockFilterTextTranslator extends PacketTranslator 1; + + if (session.getPlayerInventory().getHeldItemSlot() != containerAction.getSlot()) { + // Dropping an item that you don't have selected isn't supported in Java, but we can workaround it with an inventory hack + PlayerInventory inventory = session.getPlayerInventory(); + int hotbarSlot = inventory.getOffsetForHotbar(containerAction.getSlot()); + Click clickType = dropAll ? Click.DROP_ALL : Click.DROP_ONE; + Int2ObjectMap changedItem; + if (dropAll) { + inventory.setItem(hotbarSlot, GeyserItemStack.EMPTY, session); + changedItem = Int2ObjectMaps.singleton(hotbarSlot, null); + } else { + GeyserItemStack itemStack = inventory.getItem(hotbarSlot); + if (itemStack.isEmpty()) { + return; + } + itemStack.sub(1); + changedItem = Int2ObjectMaps.singleton(hotbarSlot, itemStack.getItemStack()); + } + ServerboundContainerClickPacket dropPacket = new ServerboundContainerClickPacket( + inventory.getId(), inventory.getStateId(), hotbarSlot, clickType.actionType, clickType.action, + inventory.getCursor().getItemStack(), changedItem); + session.sendDownstreamPacket(dropPacket); + return; + } + if (session.getPlayerInventory().getItemInHand().isEmpty()) { return; } - boolean dropAll = worldAction.getToItem().getCount() > 1; - ServerboundPlayerActionPacket dropAllPacket = new ServerboundPlayerActionPacket( + ServerboundPlayerActionPacket dropPacket = new ServerboundPlayerActionPacket( dropAll ? PlayerAction.DROP_ITEM_STACK : PlayerAction.DROP_ITEM, - BlockUtils.POSITION_ZERO, - Direction.DOWN + Vector3i.ZERO, + Direction.DOWN, + session.getNextSequence() ); - session.sendDownstreamPacket(dropAllPacket); + session.sendDownstreamPacket(dropPacket); if (dropAll) { session.getPlayerInventory().setItemInHand(GeyserItemStack.EMPTY); @@ -109,11 +139,29 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { + final Vector3i packetBlockPosition = packet.getBlockPosition(); + Vector3i blockPos = BlockUtils.getBlockPosition(packetBlockPosition, packet.getBlockFace()); + + if (session.getGeyser().getConfig().isDisableBedrockScaffolding()) { + float yaw = session.getPlayerEntity().getYaw(); + boolean isGodBridging = switch (packet.getBlockFace()) { + case 2 -> yaw <= -135f || yaw > 135f; + case 3 -> yaw <= 45f && yaw > -45f; + case 4 -> yaw > 45f && yaw <= 135f; + case 5 -> yaw <= -45f && yaw > -135f; + default -> false; + }; + if (isGodBridging) { + restoreCorrectBlock(session, blockPos, packet); + return; + } + } + // Check to make sure the client isn't spamming interaction // Based on Nukkit 1.0, with changes to ensure holding down still works boolean hasAlreadyClicked = System.currentTimeMillis() - session.getLastInteractionTime() < 110.0 && - packet.getBlockPosition().distanceSquared(session.getLastInteractionBlockPosition()) < 0.00001; - session.setLastInteractionBlockPosition(packet.getBlockPosition()); + packetBlockPosition.distanceSquared(session.getLastInteractionBlockPosition()) < 0.00001; + session.setLastInteractionBlockPosition(packetBlockPosition); session.setLastInteractionPlayerPosition(session.getPlayerEntity().getPosition()); if (hasAlreadyClicked) { break; @@ -126,19 +174,11 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator - (session.getGameMode().equals(GameMode.CREATIVE) ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { + (creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { restoreCorrectBlock(session, blockPos, packet); return; } + double clickPositionFullX = (double) packetBlockPosition.getX() + (double) packet.getClickPosition().getX(); + double clickPositionFullY = (double) packetBlockPosition.getY() + (double) packet.getClickPosition().getY(); + double clickPositionFullZ = (double) packetBlockPosition.getZ() + (double) packet.getClickPosition().getZ(); + + // More recent Paper check - https://github.com/PaperMC/Paper/blob/87e11bf7fdf48ecdf3e1cae383c368b9b61d7df9/patches/server/0470-Move-range-check-for-block-placing-up.patch + double clickDiffX = playerPosition.getX() - clickPositionFullX; + double clickDiffY = playerPosition.getY() - clickPositionFullY; + double clickDiffZ = playerPosition.getZ() - clickPositionFullZ; + if (((clickDiffX * clickDiffX) + (clickDiffY * clickDiffY) + (clickDiffZ * clickDiffZ)) > + (creative ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { + restoreCorrectBlock(session, blockPos, packet); + return; + } + + Vector3f blockCenter = Vector3f.from(packetBlockPosition.getX() + 0.5f, packetBlockPosition.getY() + 0.5f, packetBlockPosition.getZ() + 0.5f); // Vanilla check if (!(session.getPlayerEntity().getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0) - .distanceSquared(packet.getBlockPosition().toFloat().add(0.5f, 0.5f, 0.5f)) < MAXIMUM_BLOCK_PLACING_DISTANCE)) { + .distanceSquared(blockCenter) < MAXIMUM_BLOCK_PLACING_DISTANCE)) { // The client thinks that its blocks have been successfully placed. Restore the server's blocks instead. restoreCorrectBlock(session, blockPos, packet); return; } + + // More recent vanilla check (as of 1.18.2) + double clickDistanceX = clickPositionFullX - blockCenter.getX(); + double clickDistanceY = clickPositionFullY - blockCenter.getY(); + double clickDistanceZ = clickPositionFullZ - blockCenter.getZ(); + if (!(Math.abs(clickDistanceX) < 1.0000001D && Math.abs(clickDistanceY) < 1.0000001D && Math.abs(clickDistanceZ) < 1.0000001D)) { + restoreCorrectBlock(session, blockPos, packet); + return; + } /* Block place checks end - client is good to go */ @@ -190,24 +256,25 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { - ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND); + ServerboundUseItemPacket itemPacket = new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence()); session.sendDownstreamPacket(itemPacket); }, 5, TimeUnit.MILLISECONDS)); } @@ -245,7 +312,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { - if (packet.getActions().size() == 1 && packet.getLegacySlots().size() > 0) { - InventoryActionData actionData = packet.getActions().get(0); - LegacySetItemSlotData slotData = packet.getLegacySlots().get(0); - if (slotData.getContainerId() == 6 && actionData.getToItem().getId() != 0) { - // The player is trying to swap out an armor piece that already has an item in it - // Java Edition does not allow this; let's revert it - session.getInventoryTranslator().updateInventory(session, session.getPlayerInventory()); - } - } - // Handled when sneaking if (session.getPlayerInventory().getItemInHand().getJavaId() == mappings.getStoredItems().shield().getJavaId()) { break; @@ -280,8 +337,45 @@ 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().getId() != 0) { + // 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.getId(), 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 ? @@ -317,15 +411,14 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator processEntityInteraction(session, packet, entity); // Interact + case 1 -> { // Attack + int entityId; if (entity.getDefinition() == EntityDefinitions.ENDER_DRAGON) { // Redirects the attack to its body entity, this only happens when // attacking the underbelly of the ender dragon - ServerboundInteractPacket attackPacket = new ServerboundInteractPacket((int) entity.getEntityId() + 3, - InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + entityId = entity.getEntityId() + 3; } else { - ServerboundInteractPacket attackPacket = new ServerboundInteractPacket((int) entity.getEntityId(), - InteractAction.ATTACK, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); + entityId = entity.getEntityId(); } - break; + ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entityId, + InteractAction.ATTACK, session.isSneaking()); + session.sendDownstreamPacket(attackPacket); + } } break; } } + private void processEntityInteraction(GeyserSession session, InventoryTransactionPacket packet, Entity entity) { + Vector3f entityPosition = entity.getPosition(); + if (!session.getWorldBorder().isInsideBorderBoundaries(entityPosition)) { + // No transaction is able to go through (as of Java Edition 1.18.1) + return; + } + + Vector3f clickPosition = packet.getClickPosition().sub(entityPosition); + boolean isSpectator = session.getGameMode() == GameMode.SPECTATOR; + for (Hand hand : EntityUtils.HANDS) { + session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(), + InteractAction.INTERACT_AT, clickPosition.getX(), clickPosition.getY(), clickPosition.getZ(), + hand, session.isSneaking())); + + InteractionResult result; + if (isSpectator) { + result = InteractionResult.PASS; + } else { + result = entity.interactAt(hand); + } + + if (!result.consumesAction()) { + session.sendDownstreamPacket(new ServerboundInteractPacket(entity.getEntityId(), + InteractAction.INTERACT, hand, session.isSneaking())); + if (!isSpectator) { + result = entity.interact(hand); + } + } + + if (result.consumesAction()) { + if (result.shouldSwing() && hand == Hand.OFF_HAND) { + // Currently, Bedrock will send us the arm swing packet in most cases. But it won't for offhand. + session.sendDownstreamPacket(new ServerboundSwingPacket(hand)); + // Note here to look into sending the animation packet back to Bedrock + } + return; + } + } + } + /** * Restore the correct block state from the server without updating the chunk cache. * diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java index 7ed6e8866..6f7973f28 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockItemFrameDropItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -47,7 +47,7 @@ public class BedrockItemFrameDropItemTranslator extends PacketTranslator 8 || - packet.getContainerId() != ContainerId.INVENTORY || session.getPlayerInventory().getHeldItemSlot() == packet.getHotbarSlot()) { + int newSlot = packet.getHotbarSlot(); + if (!session.isSpawned() || newSlot > 8 || packet.getContainerId() != ContainerId.INVENTORY + || session.getPlayerInventory().getHeldItemSlot() == newSlot) { // For the last condition - Don't update the slot if the slot is the same - not Java Edition behavior and messes with plugins such as Grief Prevention return; } @@ -52,25 +53,30 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND)), + session.scheduleInEventLoop(() -> session.sendDownstreamPacket(new ServerboundUseItemPacket(Hand.MAIN_HAND, session.getNextSequence())), 50, TimeUnit.MILLISECONDS); } - // Java sends a cooldown indicator whenever you switch an item - CooldownUtils.sendCooldown(session); + if (oldItem.getJavaId() != newItem.getJavaId()) { + // Java sends a cooldown indicator whenever you switch to a new item type + CooldownUtils.sendCooldown(session); + } // Update the interactive tag, if an entity is present if (session.getMouseoverEntity() != null) { - InteractiveTagManager.updateTag(session, session.getMouseoverEntity()); + session.getMouseoverEntity().updateInteractiveTag(); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java index 6d971daeb..0bb3df071 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockMoveEntityAbsoluteTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -45,7 +45,7 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, RequestChunkRadiusPacket packet) { + session.setClientRenderDistance(packet.getRadius()); + + if (session.isLoggedIn()) { + session.sendJavaClientSettings(); + } + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java index 59712da7f..1631ea4c7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockRespawnTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,10 +27,7 @@ package org.geysermc.geyser.translator.protocol.bedrock; import com.github.steveice10.mc.protocol.data.game.ClientCommand; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientCommandPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import com.nukkitx.protocol.bedrock.packet.RespawnPacket; -import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -41,28 +38,6 @@ public class BedrockRespawnTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, RespawnPacket packet) { if (packet.getState() == RespawnPacket.State.CLIENT_READY) { - // Previously we only sent the respawn packet before the server finished loading - // The message included was 'Otherwise when immediate respawn is on the client never loads' - // But I assume the new if statement below fixes that problem - RespawnPacket respawnPacket = new RespawnPacket(); - respawnPacket.setRuntimeEntityId(0); - respawnPacket.setPosition(Vector3f.ZERO); - respawnPacket.setState(RespawnPacket.State.SERVER_READY); - session.sendUpstreamPacket(respawnPacket); - - if (session.isSpawned()) { - // Client might be stuck; resend spawn information - PlayerEntity entity = session.getPlayerEntity(); - entity.updateBedrockMetadata(); // TODO test? - - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); - movePlayerPacket.setPosition(entity.getPosition()); - movePlayerPacket.setRotation(entity.getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.RESPAWN); - session.sendUpstreamPacket(movePlayerPacket); - } - ServerboundClientCommandPacket javaRespawnPacket = new ServerboundClientCommandPacket(ClientCommand.RESPAWN); session.sendDownstreamPacket(javaRespawnPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java index 1840c9b0d..6cc60dd45 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockServerSettingsRequestTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,26 +27,31 @@ package org.geysermc.geyser.translator.protocol.bedrock; import com.nukkitx.protocol.bedrock.packet.ServerSettingsRequestPacket; import com.nukkitx.protocol.bedrock.packet.ServerSettingsResponsePacket; +import org.geysermc.cumulus.form.CustomForm; +import org.geysermc.cumulus.form.impl.FormDefinitions; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.SettingsUtils; -import org.geysermc.cumulus.CustomForm; import java.util.concurrent.TimeUnit; @Translator(packet = ServerSettingsRequestPacket.class) public class BedrockServerSettingsRequestTranslator extends PacketTranslator { + private final FormDefinitions formDefinitions = FormDefinitions.instance(); + @Override public void translate(GeyserSession session, ServerSettingsRequestPacket packet) { - CustomForm window = SettingsUtils.buildForm(session); - int windowId = session.getFormCache().addForm(window); + CustomForm form = SettingsUtils.buildForm(session); + int formId = session.getFormCache().addForm(form); + + String jsonData = formDefinitions.codecFor(form).jsonData(form); // Fixes https://bugs.mojang.com/browse/MCPE-94012 because of the delay session.scheduleInEventLoop(() -> { ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket(); - serverSettingsResponsePacket.setFormData(window.getJsonData()); - serverSettingsResponsePacket.setFormId(windowId); + serverSettingsResponsePacket.setFormData(jsonData); + serverSettingsResponsePacket.setFormId(formId); session.sendUpstreamPacket(serverSettingsResponsePacket); }, 1, TimeUnit.SECONDS); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index a2c0806b0..8641a35ff 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -43,7 +43,17 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat if (session.getRemoteAuthType() == AuthType.ONLINE) { if (!session.isLoggedIn()) { - LoginEncryptionUtils.buildAndShowLoginWindow(session); + if (session.getGeyser().getConfig().getSavedUserLogins().contains(session.name())) { + if (session.getGeyser().refreshTokenFor(session.name()) == null) { + LoginEncryptionUtils.buildAndShowConsentWindow(session); + } else { + // If the refresh token is not null and we're here, then the refresh token expired + // and the expiration form has been cached + session.getFormCache().resendAllForms(); + } + } else { + LoginEncryptionUtils.buildAndShowLoginWindow(session); + } } // else we were able to log the user in } @@ -55,6 +65,9 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat if (session.getOpenInventory() != null && session.getOpenInventory().isPending()) { InventoryUtils.openInventory(session, session.getOpenInventory()); } + + // What am I to expect - as of Bedrock 1.18 + session.getFormCache().resendAllForms(); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java index 19797b8a2..ca6ac09dd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockShowCreditsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java index 3cf121cf9..e52fac371 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockTextTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,9 +25,9 @@ package org.geysermc.geyser.translator.protocol.bedrock; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.text.MessageTranslator; @@ -39,6 +39,20 @@ public class BedrockTextTranslator extends PacketTranslator { public void translate(GeyserSession session, TextPacket packet) { String message = packet.getMessage(); + // The order here is important - strip out illegal characters first, then check if it's blank + // (in case the message is blank after removing) + if (message.indexOf(ChatColor.ESCAPE) != -1) { + // Filter out all escape characters - Java doesn't let you type these + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < message.length(); i++) { + char c = message.charAt(i); + if (c != ChatColor.ESCAPE) { + builder.append(c); + } + } + message = builder.toString(); + } + if (message.isBlank()) { // Java Edition (as of 1.17.1) just doesn't pass on these messages, so... we won't either! return; @@ -48,7 +62,6 @@ public class BedrockTextTranslator extends PacketTranslator { return; } - ServerboundChatPacket chatPacket = new ServerboundChatPacket(message); - session.sendDownstreamPacket(chatPacket); + session.sendChat(message); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java index 775ec15b5..b693b7f3c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/BedrockEntityEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,11 +25,8 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity; -import com.github.steveice10.mc.protocol.data.game.inventory.VillagerTrade; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSelectTradePacket; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; -import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.MerchantContainer; import org.geysermc.geyser.session.GeyserSession; @@ -50,21 +47,14 @@ public class BedrockEntityEventTranslator extends PacketTranslator { + // Not sent as of 1.18.10 ServerboundSelectTradePacket selectTradePacket = new ServerboundSelectTradePacket(packet.getData()); session.sendDownstreamPacket(selectTradePacket); session.scheduleInEventLoop(() -> { - SessionPlayerEntity villager = session.getPlayerEntity(); Inventory openInventory = session.getOpenInventory(); if (openInventory instanceof MerchantContainer merchantInventory) { - VillagerTrade[] trades = merchantInventory.getVillagerTrades(); - if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) { - VillagerTrade trade = merchantInventory.getVillagerTrades()[packet.getData()]; - openInventory.setItem(2, GeyserItemStack.from(trade.getOutput()), session); - // TODO this logic doesn't add up - villager.addFakeTradeExperience(trade.getXp()); - villager.updateBedrockMetadata(); - } + merchantInventory.onTradeSelected(session, packet.getData()); } }, 100, TimeUnit.MILLISECONDS); return; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java index 8494daade..fe519c329 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockActionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,10 +25,12 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; import com.github.steveice10.mc.protocol.data.game.entity.player.*; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.*; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerAbilitiesPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.LevelEventType; @@ -39,10 +41,8 @@ import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.ItemFrameEntity; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; -import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.BlockRegistries; -import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -77,79 +77,63 @@ public class BedrockActionTranslator extends PacketTranslator { @@ -43,8 +43,8 @@ public class BedrockEmoteTranslator 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, BlockUtils.POSITION_ZERO, - Direction.DOWN); + ServerboundPlayerActionPacket swapHandsPacket = new ServerboundPlayerActionPacket(PlayerAction.SWAP_HANDS, Vector3i.ZERO, + Direction.DOWN, session.getNextSequence()); session.sendDownstreamPacket(swapHandsPacket); if (session.getGeyser().getConfig().getEmoteOffhandWorkaround() == EmoteOffhandWorkaroundOption.NO_EMOTES) { @@ -52,7 +52,7 @@ public class BedrockEmoteTranslator extends PacketTranslator { } } - long javaId = session.getPlayerEntity().getEntityId(); + int javaId = session.getPlayerEntity().getEntityId(); for (GeyserSession otherSession : session.getGeyser().getSessionManager().getSessions().values()) { if (otherSession != session) { if (otherSession.isClosed()) continue; @@ -65,7 +65,7 @@ public class BedrockEmoteTranslator extends PacketTranslator { } } - private void playEmote(GeyserSession otherSession, long javaId, String emoteId) { + private void playEmote(GeyserSession otherSession, int javaId, String emoteId) { Entity otherEntity = otherSession.getEntityCache().getEntityByJavaId(javaId); // Must be ran on same thread if (otherEntity == null) return; EmotePacket otherEmotePacket = new EmotePacket(); 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 26a25725e..fed8f5ce6 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,10 +28,10 @@ package org.geysermc.geyser.translator.protocol.bedrock.entity.player; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.InteractAction; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; +import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket; import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.InteractPacket; @@ -40,7 +40,6 @@ import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.entity.InteractiveTagManager; @Translator(packet = InteractPacket.class) public class BedrockInteractTranslator extends PacketTranslator { @@ -62,19 +61,18 @@ public class BedrockInteractTranslator extends PacketTranslator if (session.getPlayerInventory().getItemInHand().getJavaId() == session.getItemMappings().getStoredItems().shield().getJavaId()) { break; } - ServerboundInteractPacket interactPacket = new ServerboundInteractPacket((int) entity.getEntityId(), + ServerboundInteractPacket interactPacket = new ServerboundInteractPacket(entity.getEntityId(), InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking()); session.sendDownstreamPacket(interactPacket); break; case DAMAGE: - ServerboundInteractPacket attackPacket = new ServerboundInteractPacket((int) entity.getEntityId(), + ServerboundInteractPacket attackPacket = new ServerboundInteractPacket(entity.getEntityId(), InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); session.sendDownstreamPacket(attackPacket); break; case LEAVE_VEHICLE: - ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket((int) entity.getEntityId(), PlayerState.START_SNEAKING); + ServerboundPlayerCommandPacket sneakPacket = new ServerboundPlayerCommandPacket(entity.getEntityId(), PlayerState.START_SNEAKING); session.sendDownstreamPacket(sneakPacket); - session.setRidingVehicleEntity(null); break; case MOUSEOVER: // Handle the buttons for mobile - "Mount", etc; and the suggestions for console - "ZL: Mount", etc @@ -85,7 +83,7 @@ public class BedrockInteractTranslator extends PacketTranslator return; } - InteractiveTagManager.updateTag(session, interactEntity); + interactEntity.updateInteractiveTag(); } else { if (session.getMouseoverEntity() != null) { // No interactive tag should be sent @@ -97,13 +95,11 @@ public class BedrockInteractTranslator extends PacketTranslator break; case OPEN_INVENTORY: if (session.getOpenInventory() == null) { - Entity ridingEntity = session.getRidingVehicleEntity(); - if (ridingEntity instanceof AbstractHorseEntity) { - if (ridingEntity.getFlag(EntityFlag.TAMED)) { - // We should request to open the horse inventory instead - ServerboundPlayerCommandPacket openHorseWindowPacket = new ServerboundPlayerCommandPacket((int) session.getPlayerEntity().getEntityId(), PlayerState.OPEN_HORSE_INVENTORY); - session.sendDownstreamPacket(openHorseWindowPacket); - } + Entity ridingEntity = session.getPlayerEntity().getVehicle(); + if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) { + // This mob has an inventory of its own that we should open instead. + ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY); + session.sendDownstreamPacket(openVehicleWindowPacket); } else { session.setOpenInventory(session.getPlayerInventory()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java index 1555722d6..0d3ef4cbc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockMovePlayerTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,14 +37,12 @@ import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; +import org.geysermc.geyser.level.BedrockDimension; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @Translator(packet = MovePlayerPacket.class) public class BedrockMovePlayerTranslator extends PacketTranslator { - /* The upper and lower bounds to check for the void floor that only exists in Bedrock. These are the constants for the overworld. */ - private static final int BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y = -104; - private static final int BEDROCK_OVERWORLD_VOID_FLOOR_LOWER_Y = BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y + 2; @Override public void translate(GeyserSession session, MovePlayerPacket packet) { @@ -67,7 +65,8 @@ public class BedrockMovePlayerTranslator extends PacketTranslator= (extendedWorld ? BEDROCK_OVERWORLD_VOID_FLOOR_UPPER_Y : -40)) { + // The void floor is offset about 40 blocks below the bottom of the world + BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + int voidFloorLocation = bedrockDimension.minY() - 40; + if (floorY <= (voidFloorLocation + 2) && floorY >= voidFloorLocation) { // Work around there being a floor at the bottom of the world and teleport the player below it // Moving from below to above the void floor works fine entity.setPosition(entity.getPosition().sub(0, 4f, 0)); @@ -140,6 +140,8 @@ public class BedrockMovePlayerTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, RiderJumpPacket packet) { - Entity vehicle = session.getRidingVehicleEntity(); + Entity vehicle = session.getPlayerEntity().getVehicle(); if (vehicle instanceof AbstractHorseEntity) { - ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket((int) vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); + ServerboundPlayerCommandPacket playerCommandPacket = new ServerboundPlayerCommandPacket(vehicle.getEntityId(), PlayerState.START_HORSE_JUMP, packet.getJumpStrength()); session.sendDownstreamPacket(playerCommandPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java index b149f8836..2096275cf 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java index 2ac8587bf..df8cd07c1 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/world/BedrockLevelSoundEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java index 8f4e93635..4f4c2e549 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaAwardStatsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java index c9512b87b..1011eb739 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaBossEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java index e0c3a9b95..fdc2fa2fb 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaChangeDifficultyTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 5e918d5d3..b6f7a2451 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,6 +27,8 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.data.game.command.CommandNode; 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 com.nukkitx.protocol.bedrock.data.command.CommandData; import com.nukkitx.protocol.bedrock.data.command.CommandEnumData; @@ -58,6 +60,7 @@ import java.util.*; public class JavaCommandsTranslator extends PacketTranslator { private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers(); + private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.keySet().toArray(new String[0]); private static final String[] ENUM_BOOLEAN = {"true", "false"}; private static final String[] VALID_COLORS; private static final String[] VALID_SCOREBOARD_SLOTS; @@ -203,10 +206,11 @@ public class JavaCommandsTranslator extends PacketTranslator CommandParam.BLOCK_POSITION; case COLUMN_POS, VEC3 -> CommandParam.POSITION; case MESSAGE -> CommandParam.MESSAGE; - case NBT, NBT_COMPOUND_TAG, NBT_TAG, NBT_PATH -> CommandParam.JSON; + case NBT_COMPOUND_TAG, NBT_TAG, NBT_PATH -> CommandParam.JSON; //TODO NBT was removed case RESOURCE_LOCATION, FUNCTION -> CommandParam.FILE_PATH; case BOOL -> ENUM_BOOLEAN; case OPERATION -> CommandParam.OPERATOR; // ">=", "==", etc @@ -229,6 +233,14 @@ public class JavaCommandsTranslator extends PacketTranslator VALID_COLORS; case SCOREBOARD_SLOT -> VALID_SCOREBOARD_SLOTS; case MOB_EFFECT -> ALL_EFFECT_IDENTIFIERS; + case RESOURCE, RESOURCE_OR_TAG -> { + String resource = ((ResourceProperties) node.getProperties()).getRegistryKey(); + if (resource.equals("minecraft:attribute")) { + yield ATTRIBUTES; + } else { + yield CommandParam.STRING; + } + } default -> CommandParam.STRING; }; } @@ -236,7 +248,7 @@ public class JavaCommandsTranslator extends PacketTranslator // So if paramNode.getName() == "value" and enumData.getName() == "bool": - children.add(new ParamInfo(paramNode, new CommandParamData(paramNode.getName(), this.paramNode.isExecutable(), enumData, type, null, Collections.emptyList()))); + children.add(new ParamInfo(paramNode, new CommandParamData(paramNode.getName(), optional, enumData, type, null, Collections.emptyList()))); } } 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 14f54c710..32c1f747f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * 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 @@ -32,9 +32,10 @@ import com.nukkitx.protocol.bedrock.packet.TransferPacket; import com.nukkitx.protocol.bedrock.packet.UnknownPacket; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; -import org.geysermc.cumulus.Form; import org.geysermc.cumulus.Forms; -import org.geysermc.cumulus.util.FormType; +import org.geysermc.cumulus.form.Form; +import org.geysermc.cumulus.form.util.FormType; +import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.session.GeyserSession; @@ -57,21 +58,20 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { + Form form = Forms.fromJson(dataString, type, (ignored, response) -> { byte[] raw = response.getBytes(StandardCharsets.UTF_8); byte[] finalData = new byte[raw.length + 2]; @@ -83,7 +83,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundLoginDisconnectPacket packet) { + Component disconnectReason = packet.getReason(); + + boolean isOutdatedMessage = false; + if (disconnectReason instanceof TranslatableComponent component) { + String key = component.key(); + isOutdatedMessage = "multiplayer.disconnect.incompatible".equals(key) || + // Legacy string (starting from at least 1.15.2) + "multiplayer.disconnect.outdated_server".equals(key) + // Reproduced on 1.15.2 server with ViaVersion 4.0.0-21w20a with 1.18.2 Java client + || key.startsWith("Outdated server!"); + } else { + if (disconnectReason instanceof TextComponent component) { + if (component.content().startsWith("Outdated server!")) { + // Reproduced with vanilla 1.8.8 server and 1.18.2 Java client + isOutdatedMessage = true; + } else { + List children = component.children(); + for (int i = 0; i < children.size(); i++) { + if (children.get(i) instanceof TextComponent child && child.content().startsWith("Outdated server!")) { + // Reproduced on Paper 1.17.1 + isOutdatedMessage = true; + break; + } + } + } + } + } + + String serverDisconnectMessage = MessageTranslator.convertMessage(disconnectReason, session.getLocale()); + String disconnectMessage; + if (isOutdatedMessage) { + String locale = session.getLocale(); + PlatformType platform = session.getGeyser().getPlatformType(); + String outdatedType = (platform == PlatformType.BUNGEECORD || platform == PlatformType.VELOCITY) ? + "geyser.network.remote.outdated.proxy" : "geyser.network.remote.outdated.server"; + disconnectMessage = GeyserLocale.getPlayerLocaleString(outdatedType, locale, MinecraftProtocol.getJavaVersions().get(0)) + '\n' + + GeyserLocale.getPlayerLocaleString("geyser.network.remote.original_disconnect_message", locale, serverDisconnectMessage); + } else { + disconnectMessage = serverDisconnectMessage; + } + // The client doesn't manually get disconnected so we have to do it ourselves - session.disconnect(MessageTranslator.convertMessage(packet.getReason(), session.getLocale())); + session.disconnect(disconnectMessage); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java index 76a867e30..a5c949c10 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaLoginTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,53 +25,79 @@ package org.geysermc.geyser.translator.protocol.java; -import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; -import com.github.steveice10.mc.protocol.data.game.setting.ChatVisibility; -import com.github.steveice10.mc.protocol.data.game.setting.SkinPart; +import com.github.steveice10.mc.protocol.data.game.MessageType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket; -import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundClientInformationPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundCustomPayloadPacket; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.nukkitx.protocol.bedrock.data.GameRuleData; import com.nukkitx.protocol.bedrock.data.PlayerPermission; -import com.nukkitx.protocol.bedrock.packet.*; -import org.geysermc.geyser.session.auth.AuthType; -import org.geysermc.geyser.entity.type.player.PlayerEntity; +import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; +import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; +import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; +import org.geysermc.floodgate.pluginmessage.PluginMessageChannels; +import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; +import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.session.auth.AuthType; +import org.geysermc.geyser.text.TextDecoration; +import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.level.BiomeTranslator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; +import org.geysermc.geyser.util.JavaCodecEntry; import org.geysermc.geyser.util.PluginMessageUtils; -import java.util.Arrays; -import java.util.List; +import java.util.Map; @Translator(packet = ClientboundLoginPacket.class) public class JavaLoginTranslator extends PacketTranslator { - private static final List SKIN_PART_VALUES = Arrays.asList(SkinPart.values()); @Override public void translate(GeyserSession session, ClientboundLoginPacket packet) { - PlayerEntity entity = session.getPlayerEntity(); + SessionPlayerEntity entity = session.getPlayerEntity(); entity.setEntityId(packet.getEntityId()); + Map dimensions = session.getDimensions(); + dimensions.clear(); + + JavaDimension.load(packet.getRegistry(), dimensions); + + Map chatTypes = session.getChatTypes(); + chatTypes.clear(); + for (CompoundTag tag : JavaCodecEntry.iterateAsTag(packet.getRegistry().get("minecraft:chat_type"))) { + int id = ((IntTag) tag.get("id")).getValue(); + CompoundTag element = tag.get("element"); + CompoundTag chat = element.get("chat"); + if (chat == null) { + continue; + } + CompoundTag decoration = chat.get("decoration"); + if (decoration == null) { + continue; + } + MessageType type = MessageType.from(id); + chatTypes.put(type, new TextDecoration(decoration)); + } + // If the player is already initialized and a join game packet is sent, they // are swapping servers - String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); if (session.isSpawned()) { - String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); + String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), packet.getDimension()); DimensionUtils.switchDimension(session, fakeDim); session.getWorldCache().removeScoreboard(); } session.setWorldName(packet.getWorldName()); - BiomeTranslator.loadServerBiomes(session, packet.getDimensionCodec()); + BiomeTranslator.loadServerBiomes(session, packet.getRegistry()); session.getTagCache().clear(); session.setGameMode(packet.getGameMode()); + String newDimension = packet.getDimension(); + boolean needsSpawnPacket = !session.isSentSpawnPacket(); if (needsSpawnPacket) { // The player has yet to spawn so let's do that using some of the information in this Java packet @@ -90,6 +116,8 @@ public class JavaLoginTranslator extends PacketTranslator { + + @Override + public void translate(GeyserSession session, ClientboundPlayerChatPacket packet) { + TextPacket textPacket = new TextPacket(); + textPacket.setPlatformChatId(""); + textPacket.setSourceName(""); + textPacket.setXuid(session.getAuthData().xuid()); + // TODO new types + textPacket.setType(switch (packet.getType()) { + case CHAT -> TextPacket.Type.CHAT; + case SYSTEM -> TextPacket.Type.SYSTEM; + case GAME_INFO -> TextPacket.Type.TIP; + default -> TextPacket.Type.RAW; + }); + + textPacket.setNeedsTranslation(false); + Component message = packet.getUnsignedContent() == null ? packet.getSignedContent() : packet.getUnsignedContent(); + + TextDecoration decoration = session.getChatTypes().get(packet.getType()); + if (decoration != null) { + // As of 1.19 - do this to apply all the styling for signed messages + // Though, Bedrock cannot care about the signed stuff. + TranslatableComponent.Builder withDecoration = Component.translatable() + .key(decoration.translationKey()) + .style(decoration.style()); + Set parameters = decoration.parameters(); + List args = new ArrayList<>(3); + if (parameters.contains(TextDecoration.Parameter.TEAM_NAME)) { + args.add(packet.getSenderTeamName()); + } + if (parameters.contains(TextDecoration.Parameter.SENDER)) { + args.add(packet.getSenderName()); + } + if (parameters.contains(TextDecoration.Parameter.CONTENT)) { + args.add(message); + } + withDecoration.args(args); + textPacket.setMessage(MessageTranslator.convertMessage(withDecoration.build(), session.getLocale())); + } else { + textPacket.setMessage(MessageTranslator.convertMessage(message, session.getLocale())); + } + + session.sendUpstreamPacket(textPacket); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java index 8f97b1a8d..3471ce576 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRespawnTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,9 +33,9 @@ import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import org.geysermc.geyser.entity.attribute.GeyserAttributeType; import org.geysermc.geyser.entity.type.player.SessionPlayerEntity; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.DimensionUtils; @@ -46,6 +46,8 @@ public class JavaRespawnTranslator extends PacketTranslator { +@Translator(packet = ClientboundSystemChatPacket.class) +public class JavaSystemChatTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundChatPacket packet) { + public void translate(GeyserSession session, ClientboundSystemChatPacket packet) { TextPacket textPacket = new TextPacket(); textPacket.setPlatformChatId(""); textPacket.setSourceName(""); textPacket.setXuid(session.getAuthData().xuid()); + // TODO new types textPacket.setType(switch (packet.getType()) { case CHAT -> TextPacket.Type.CHAT; case SYSTEM -> TextPacket.Type.SYSTEM; - case NOTIFICATION -> TextPacket.Type.TIP; + case GAME_INFO -> TextPacket.Type.TIP; default -> TextPacket.Type.RAW; }); textPacket.setNeedsTranslation(false); - textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.getLocale())); + textPacket.setMessage(MessageTranslator.convertMessage(packet.getContent(), session.getLocale())); session.sendUpstreamPacket(textPacket); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java index c1f6f77d2..a1d8da90c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateAdvancementsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,7 +27,7 @@ package org.geysermc.geyser.translator.protocol.java; import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateAdvancementsPacket; -import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; +import com.nukkitx.protocol.bedrock.packet.ToastRequestPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -36,7 +36,7 @@ import org.geysermc.geyser.session.cache.AdvancementsCache; import org.geysermc.geyser.level.GeyserAdvancement; import org.geysermc.geyser.text.MinecraftLocale; -import java.util.Map; +import java.util.Locale; @Translator(packet = ClientboundUpdateAdvancementsPacket.class) public class JavaUpdateAdvancementsTranslator extends PacketTranslator { @@ -56,48 +56,39 @@ public class JavaUpdateAdvancementsTranslator extends PacketTranslator> progress : packet.getProgress().entrySet()) { - GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(progress.getKey()); + for (String advancementId : packet.getProgress().keySet()) { + GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(advancementId); if (advancement != null && advancement.getDisplayData() != null) { - if (session.getAdvancementsCache().isEarned(advancement)) { - // Java uses some pink color for toast challenge completes - String color = advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE ? - "§d" : "§a"; + if (advancement.getDisplayData().isShowToast() && session.getAdvancementsCache().isEarned(advancement)) { + String frameType = advancement.getDisplayData().getFrameType().toString().toLowerCase(Locale.ROOT); + String frameTitle = advancement.getDisplayColor() + MinecraftLocale.getLocaleString("advancements.toast." + frameType, session.getLocale()); String advancementName = MessageTranslator.convertMessage(advancement.getDisplayData().getTitle(), session.getLocale()); - // Send an action bar message stating they earned an achievement - // Sent for instances where broadcasting advancements through chat are disabled - SetTitlePacket titlePacket = new SetTitlePacket(); - titlePacket.setText(color + "[" + MinecraftLocale.getLocaleString("advancements.toast." + - advancement.getDisplayData().getFrameType().toString().toLowerCase(), session.getLocale()) + "]§f " + advancementName); - titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - titlePacket.setFadeOutTime(3); - titlePacket.setFadeInTime(3); - titlePacket.setStayTime(3); - titlePacket.setXuid(""); - titlePacket.setPlatformOnlineId(""); - session.sendUpstreamPacket(titlePacket); + ToastRequestPacket toastRequestPacket = new ToastRequestPacket(); + toastRequestPacket.setTitle(frameTitle); + toastRequestPacket.setContent(advancementName); + session.sendUpstreamPacket(toastRequestPacket); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index fd8c42ffc..f1de83914 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,6 +31,7 @@ import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; +import com.github.steveice10.mc.protocol.data.game.recipe.data.SmithingRecipeData; import com.github.steveice10.mc.protocol.data.game.recipe.data.StoneCuttingRecipeData; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; import com.nukkitx.nbt.NbtMap; @@ -40,6 +41,10 @@ import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; import it.unimi.dsi.fastutil.ints.*; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserStonecutterData; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; @@ -76,7 +81,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion())); + Int2ObjectMap recipeMap = new Int2ObjectOpenHashMap<>(Registries.RECIPES.forVersion(session.getUpstream().getProtocolVersion())); Int2ObjectMap> unsortedStonecutterData = new Int2ObjectOpenHashMap<>(); CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); @@ -96,7 +101,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { @@ -114,7 +119,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { @@ -128,6 +133,23 @@ 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(); + ItemData output = ItemTranslator.translateToBedrock(session, recipeData.getResult()); + for (ItemStack base : recipeData.getBase().getOptions()) { + ItemData bedrockBase = ItemTranslator.translateToBedrock(session, base); + + for (ItemStack addition : recipeData.getAddition().getOptions()) { + ItemData bedrockAddition = ItemTranslator.translateToBedrock(session, addition); + + UUID uuid = UUID.randomUUID(); + craftingDataPacket.getCraftingData().add(CraftingData.fromShapeless(uuid.toString(), + Arrays.asList(bedrockBase, bedrockAddition), + Collections.singletonList(output), uuid, "smithing_table", 2, netId++)); + } + } + } default -> { List craftingData = recipeTypes.get(recipe.getType()); if (craftingData != null) { @@ -139,21 +161,22 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore // We can get the correct order for button pressing data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> - session.getItemMappings().getItems() - .getOrDefault(stoneCuttingRecipeData.getResult().getId(), ItemMapping.AIR) + session.getItemMappings().getMapping(stoneCuttingRecipeData.getResult()) .getJavaIdentifier()))); // Now that it's sorted, let's translate these recipes + int buttonId = 0; for (StoneCuttingRecipeData stoneCuttingData : data.getValue()) { // As of 1.16.4, all stonecutter recipes have one ingredient option ItemStack ingredient = stoneCuttingData.getIngredient().getOptions()[0]; ItemData input = ItemTranslator.translateToBedrock(session, ingredient); - ItemData output = ItemTranslator.translateToBedrock(session, stoneCuttingData.getResult()); + ItemStack javaOutput = stoneCuttingData.getResult(); + ItemData output = ItemTranslator.translateToBedrock(session, javaOutput); if (input.equals(ItemData.AIR) || output.equals(ItemData.AIR)) { // Probably modded items continue; @@ -162,18 +185,16 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator new IntArrayList()); - outputs.add(stoneCuttingData.getResult().getId()); + // Add the net ID as the key and the button required + output for the value + stonecutterRecipeMap.put(netId++, new GeyserStonecutterData(buttonId++, javaOutput)); } } session.sendUpstreamPacket(craftingDataPacket); session.setCraftingRecipes(recipeMap); - session.getUnlockedRecipes().clear(); session.setStonecutterRecipes(stonecutterRecipeMap); session.getLastRecipeNetId().set(netId); } @@ -202,7 +223,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundAnimatePacket packet) { - Entity entity; - if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) { - entity = session.getPlayerEntity(); - } else { - entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); - } + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); if (entity == null) return; @@ -55,6 +52,9 @@ public class JavaAnimateTranslator extends PacketTranslator { @@ -40,12 +39,7 @@ public class JavaSetEntityDataTranslator extends PacketTranslator definition = entity.getDefinition(); @@ -65,8 +59,9 @@ public class JavaSetEntityDataTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundSetPassengersPacket packet) { - Entity entity; - if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) { - entity = session.getPlayerEntity(); - } else { - entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); - } - + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); if (entity == null) return; - LongOpenHashSet passengers = entity.getPassengers().clone(); - boolean rider = true; - for (long passengerId : packet.getPassengerIds()) { + // Handle new/existing passengers + List newPassengers = new ArrayList<>(); + for (int passengerId : packet.getPassengerIds()) { Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId); - if (passengerId == session.getPlayerEntity().getEntityId()) { - passenger = session.getPlayerEntity(); - session.setRidingVehicleEntity(entity); + if (passenger == session.getPlayerEntity()) { + session.getPlayerEntity().setVehicle(entity); // We need to confirm teleports before entering a vehicle, or else we will likely exit right out session.confirmTeleport(passenger.getPosition().sub(0, EntityDefinitions.PLAYER.offset(), 0).toDouble()); } - // Passenger hasn't loaded in (likely since we're waiting for a skin response) - // and entity link needs to be set later - if (passenger == null && passengerId != 0) { - session.getEntityCache().addCachedPlayerEntityLink(passengerId, packet.getEntityId()); - } if (passenger == null) { + // Can occur if the passenger is outside the client's tracking range + // In this case, another SetPassengers packet will be sent when the passenger is spawned. continue; } + boolean rider = packet.getPassengerIds()[0] == passengerId; EntityLinkData.Type type = rider ? EntityLinkData.Type.RIDER : EntityLinkData.Type.PASSENGER; SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); - linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), type, false)); + linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), type, false, false)); session.sendUpstreamPacket(linkPacket); - passengers.add(passengerId); - - // Head rotation on boats - if (entity.getDefinition() == EntityDefinitions.BOAT) { - passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1); - passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f); - passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 1f); - passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, -90f); - } else { - passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0); - passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f); - passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f); - } - - passenger.updateBedrockMetadata(); - rider = false; - } - - entity.setPassengers(passengers); - - for (long passengerId : entity.getPassengers()) { - Entity passenger = session.getEntityCache().getEntityByJavaId(passengerId); - if (passengerId == session.getPlayerEntity().getEntityId()) { - passenger = session.getPlayerEntity(); - } - if (passenger == null) { - continue; - } - if (Arrays.stream(packet.getPassengerIds()).noneMatch(id -> id == passengerId)) { - SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); - linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), EntityLinkData.Type.REMOVE, false)); - session.sendUpstreamPacket(linkPacket); - passengers.remove(passenger.getEntityId()); - passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0); - passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f); - passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f); - passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, 0f); - - EntityUtils.updateMountOffset(passenger, entity, false, false, (packet.getPassengerIds().length > 1)); - } else { - EntityUtils.updateMountOffset(passenger, entity, (packet.getPassengerIds()[0] == passengerId), true, (packet.getPassengerIds().length > 1)); - } + newPassengers.add(passenger); + passenger.setVehicle(entity); + EntityUtils.updateRiderRotationLock(passenger, entity, true); + EntityUtils.updateMountOffset(passenger, entity, rider, true, (packet.getPassengerIds().length > 1)); // Force an update to the passenger metadata passenger.updateBedrockMetadata(); } + // Handle passengers that were removed + for (Entity passenger : entity.getPassengers()) { + if (passenger == null) { + continue; + } + if (!newPassengers.contains(passenger)) { + SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); + linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), EntityLinkData.Type.REMOVE, false, false)); + session.sendUpstreamPacket(linkPacket); + + passenger.setVehicle(null); + EntityUtils.updateRiderRotationLock(passenger, entity, false); + EntityUtils.updateMountOffset(passenger, entity, false, false, (packet.getPassengerIds().length > 1)); + // Force an update to the passenger metadata + passenger.updateBedrockMetadata(); + } + } + + entity.setPassengers(newPassengers); + switch (entity.getDefinition().entityType()) { case HORSE, SKELETON_HORSE, DONKEY, MULE, RAVAGER -> { entity.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 181.0f); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java similarity index 63% rename from core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java index 0a329f607..06f141aa6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaRecipeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaSoundEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,29 +23,23 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.translator.protocol.java; +package org.geysermc.geyser.translator.protocol.java.entity; -import com.github.steveice10.mc.protocol.data.game.UnlockRecipesAction; -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRecipePacket; +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundSoundEntityPacket; +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; +import org.geysermc.geyser.util.SoundUtils; -import java.util.Arrays; - -/** - * Used to list recipes that we can definitely use the recipe book for (and therefore save on packet usage) - */ -@Translator(packet = ClientboundRecipePacket.class) -public class JavaRecipeTranslator extends PacketTranslator { - +@Translator(packet = ClientboundSoundEntityPacket.class) +public class JavaSoundEntityTranslator extends PacketTranslator { @Override - public void translate(GeyserSession session, ClientboundRecipePacket packet) { - if (packet.getAction() == UnlockRecipesAction.REMOVE) { - session.getUnlockedRecipes().removeAll(Arrays.asList(packet.getRecipes())); - } else { - session.getUnlockedRecipes().addAll(Arrays.asList(packet.getRecipes())); + public void translate(GeyserSession session, ClientboundSoundEntityPacket packet) { + Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); + if (entity == null) { + return; } + SoundUtils.playBuiltinSound(session, packet.getSound(), entity.getPosition(), packet.getVolume(), packet.getPitch()); } } - diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java index 75d7bc976..a449ba50a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaTakeItemEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -49,12 +49,7 @@ public class JavaTakeItemEntityTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundBlockBreakAckPacket packet) { - ChunkUtils.updateBlock(session, packet.getNewState(), packet.getPosition()); - if (packet.getAction() == PlayerAction.START_DIGGING && !packet.isSuccessful()) { - LevelEventPacket stopBreak = new LevelEventPacket(); - stopBreak.setType(LevelEventType.BLOCK_STOP_BREAK); - stopBreak.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - stopBreak.setData(0); - session.setBreakingBlock(BlockStateValues.JAVA_AIR_ID); - session.sendUpstreamPacket(stopBreak); - } - } -} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/entity/factory/BaseEntityFactory.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java similarity index 64% rename from core/src/main/java/org/geysermc/geyser/entity/factory/BaseEntityFactory.java rename to core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java index dff1617f9..6afb0b3ef 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/factory/BaseEntityFactory.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaBlockChangedAckTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -23,17 +23,18 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.geyser.entity.factory; +package org.geysermc.geyser.translator.protocol.java.entity.player; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.EntityDefinition; +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundBlockChangedAckPacket; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; -import java.util.UUID; +@Translator(packet = ClientboundBlockChangedAckPacket.class) +public class JavaBlockChangedAckTranslator extends PacketTranslator { -@FunctionalInterface -public interface BaseEntityFactory extends EntityFactory { - - T create(GeyserSession session, long javaId, long bedrockId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw); -} + @Override + public void translate(GeyserSession session, ClientboundBlockChangedAckPacket packet) { + // TODO + } +} \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java index 98b69a0b8..44ae7f425 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerAbilitiesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,6 +37,7 @@ public class JavaPlayerAbilitiesTranslator extends PacketTranslator { + GameProfile profile = entry.getProfile(); PlayerEntity playerEntity; - boolean self = entry.getProfile().getId().equals(session.getPlayerEntity().getUuid()); + boolean self = profile.getId().equals(session.getPlayerEntity().getUuid()); if (self) { // Entity is ourself playerEntity = session.getPlayerEntity(); } else { - playerEntity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId()); + playerEntity = session.getEntityCache().getPlayerEntity(profile.getId()); } + GameProfile.Property textures = profile.getProperty("textures"); + String texturesProperty = textures == null ? null : textures.getValue(); + if (playerEntity == null) { // It's a new player playerEntity = new PlayerEntity( session, -1, session.getEntityCache().getNextEntityId().incrementAndGet(), - entry.getProfile(), + profile.getId(), Vector3f.ZERO, Vector3f.ZERO, - 0, 0, 0 + 0, 0, 0, + profile.getName(), + texturesProperty ); session.getEntityCache().addPlayerEntity(playerEntity); } else { - playerEntity.setProfile(entry.getProfile()); + playerEntity.setUsername(profile.getName()); + playerEntity.setTexturesProperty(texturesProperty); } playerEntity.setPlayerList(true); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java new file mode 100644 index 000000000..81a86311a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerLookAtTranslator.java @@ -0,0 +1,68 @@ +/* + * 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.translator.protocol.java.entity.player; + +import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerLookAtPacket; +import com.nukkitx.math.vector.Vector3f; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.protocol.PacketTranslator; +import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.MathUtils; + +@Translator(packet = ClientboundPlayerLookAtPacket.class) +public class JavaPlayerLookAtTranslator extends PacketTranslator { + @Override + public void translate(GeyserSession session, ClientboundPlayerLookAtPacket packet) { + var targetPosition = targetPosition(session, packet); + var selfPosition = session.getPlayerEntity().getPosition(); + + var xDelta = targetPosition.getX() - selfPosition.getX(); + var yDelta = targetPosition.getY() - selfPosition.getY(); + var zDelta = targetPosition.getZ() - selfPosition.getZ(); + var sqrt = Math.sqrt(xDelta * xDelta + zDelta * zDelta); + + var yaw = MathUtils.wrapDegrees(-Math.toDegrees(Math.atan2(yDelta, sqrt))); + var pitch = MathUtils.wrapDegrees(Math.toDegrees(Math.atan2(zDelta, xDelta)) - 90.0); + + var self = session.getPlayerEntity(); + // headYaw is also set to yaw in this packet + self.updateRotation(yaw, pitch, yaw, self.isOnGround()); + } + + public Vector3f targetPosition(GeyserSession session, ClientboundPlayerLookAtPacket packet) { + if (packet.getTargetEntityOrigin() != null) { + var entityId = packet.getTargetEntityId(); + var target = session.getEntityCache().getEntityByJavaId(entityId); + if (target != null) { + return switch (packet.getTargetEntityOrigin()) { + case FEET -> target.getPosition(); + case EYES -> target.getPosition().add(0, target.getBoundingBoxHeight(), 0); + }; + } + } + return Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); + } +} 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 3e94321f9..f5d21ecc9 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -28,22 +28,22 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; import com.github.steveice10.mc.protocol.data.game.entity.player.PositionElement; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.level.ServerboundAcceptTeleportationPacket; +import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityLinkData; import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; import com.nukkitx.protocol.bedrock.packet.RespawnPacket; import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket; -import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.EntityDefinitions; -import org.geysermc.geyser.entity.type.player.PlayerEntity; +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.text.GeyserLocale; 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; -import org.geysermc.geyser.text.GeyserLocale; @Translator(packet = ClientboundPlayerPositionPacket.class) public class JavaPlayerPositionTranslator extends PacketTranslator { @@ -53,9 +53,10 @@ public class JavaPlayerPositionTranslator extends PacketTranslator 1); + vehicle.getPassengers().remove(entity); + session.getPlayerEntity().setVehicle(null); + + EntityUtils.updateRiderRotationLock(entity, null, false); + EntityUtils.updateMountOffset(entity, null, false, false, entity.getPassengers().size() > 1); + entity.updateBedrockMetadata(); } // If coordinates are relative, then add to the existing coordinate @@ -114,26 +114,37 @@ public class JavaPlayerPositionTranslator extends PacketTranslator 0f) { + // Needed as of 1.18.30 (tested with a totem of undying on SPIGOT 1.12.2 + // This shouldn't be triggered on a proper respawn because JavaSetHealthTranslator sets the health back to 20 + // https://github.com/GeyserMC/Geyser/issues/2957 + RespawnPacket respawnPacket = new RespawnPacket(); + respawnPacket.setRuntimeEntityId(0); + respawnPacket.setPosition(entity.getPosition()); + respawnPacket.setState(RespawnPacket.State.SERVER_READY); + session.sendUpstreamPacket(respawnPacket); + } entity.setHealth(packet.getHealth()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java index b80b59ff4..49cca79d2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -31,18 +31,14 @@ import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.*; -import org.geysermc.geyser.entity.factory.BaseEntityFactory; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.FallingBlockEntity; -import org.geysermc.geyser.entity.type.FishingHookEntity; -import org.geysermc.geyser.entity.type.ItemFrameEntity; +import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.type.*; import org.geysermc.geyser.entity.type.player.PlayerEntity; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.text.GeyserLocale; @Translator(packet = ClientboundAddEntityPacket.class) public class JavaAddEntityTranslator extends PacketTranslator { @@ -53,6 +49,7 @@ public class JavaAddEntityTranslator extends PacketTranslator definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); if (definition == null) { @@ -63,30 +60,28 @@ public class JavaAddEntityTranslator extends PacketTranslator) definition.factory()).create(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), - packet.getUuid(), definition, position, motion, yaw, pitch, 0f); + entity = definition.factory().create(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), + packet.getUuid(), definition, position, motion, yaw, pitch, headYaw); } session.getEntityCache().spawnEntity(entity); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java index 33e230c14..419f99cae 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddExperienceOrbTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddMobTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddMobTranslator.java deleted file mode 100644 index e6b82f365..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddMobTranslator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.translator.protocol.java.entity.spawn; - -import com.github.steveice10.mc.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddMobPacket; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.factory.BaseEntityFactory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.text.GeyserLocale; - -@Translator(packet = ClientboundAddMobPacket.class) -public class JavaAddMobTranslator extends PacketTranslator { - - @Override - public void translate(GeyserSession session, ClientboundAddMobPacket packet) { - Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); - Vector3f motion = Vector3f.from(packet.getMotionX(), packet.getMotionY(), packet.getMotionZ()); - - EntityDefinition definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); - if (definition == null) { - session.getGeyser().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.entity.type_null", packet.getType())); - return; - } - - Entity entity = ((BaseEntityFactory) definition.factory()).create(session, packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), - packet.getUuid(), definition, position, motion, packet.getYaw(), packet.getPitch(), packet.getHeadYaw() - ); - session.getEntityCache().spawnEntity(entity); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java index 74dcaf022..c54b75f4f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddPlayerTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -48,7 +48,9 @@ public class JavaAddPlayerTranslator extends PacketTranslator inventorySize) { + GeyserImpl geyser = session.getGeyser(); + geyser.getLogger().warning("ClientboundContainerSetContentPacket sent to " + session.name() + + " that exceeds inventory size!"); + if (geyser.getConfig().isDebugMode()) { + geyser.getLogger().debug(packet); + geyser.getLogger().debug(inventory); + } + InventoryTranslator translator = session.getInventoryTranslator(); + if (translator != null) { + translator.updateInventory(session, inventory); + } + // 1.18.1 behavior: the previous items will be correctly set, but the state ID and carried item will not + // as this produces a stack trace on the client. + // If Java processes this correctly in the future, we can revert this behavior + return; + } + GeyserItemStack newItem = GeyserItemStack.from(packet.getItems()[i]); inventory.setItem(i, newItem, session); } @@ -55,6 +73,10 @@ public class JavaContainerSetContentTranslator extends PacketTranslator 0 || stateId != inventory.getStateId()); + inventory.setStateId(stateId); + session.getPlayerInventory().setCursor(GeyserItemStack.from(packet.getCarriedItem()), session); InventoryUtils.updateCursor(session); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java index 2ffab0d38..30c2abe25 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetDataTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java index 54cc91ca6..36307e7bd 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaContainerSetSlotTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,10 +27,6 @@ package org.geysermc.geyser.translator.protocol.java.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; -import com.github.steveice10.mc.protocol.data.game.recipe.Recipe; -import com.github.steveice10.mc.protocol.data.game.recipe.RecipeType; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapedRecipeData; -import com.github.steveice10.mc.protocol.data.game.recipe.data.ShapelessRecipeData; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.inventory.ClientboundContainerSetSlotPacket; import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; @@ -39,18 +35,17 @@ import com.nukkitx.protocol.bedrock.packet.CraftingDataPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.inventory.InventoryTranslator; -import org.geysermc.geyser.translator.inventory.CraftingInventoryTranslator; import org.geysermc.geyser.translator.inventory.PlayerInventoryTranslator; 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.InventoryUtils; import java.util.Arrays; import java.util.Collections; -import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -71,14 +66,17 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator 0 || stateId != inventory.getStateId()); + inventory.setStateId(stateId); InventoryTranslator translator = session.getInventoryTranslator(); if (translator != null) { if (session.getCraftingGridFuture() != null) { session.getCraftingGridFuture().cancel(false); } - session.setCraftingGridFuture(session.scheduleInEventLoop(() -> updateCraftingGrid(session, packet, inventory, translator), 150, TimeUnit.MILLISECONDS)); + updateCraftingGrid(session, packet.getSlot(), packet.getItem(), inventory, translator); GeyserItemStack newItem = GeyserItemStack.from(packet.getItem()); if (packet.getContainerId() == 0 && !(translator instanceof PlayerInventoryTranslator)) { @@ -92,21 +90,23 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator { int offset = gridSize == 4 ? 28 : 32; int gridDimensions = gridSize == 4 ? 2 : 3; int firstRow = -1, height = -1; @@ -134,62 +134,10 @@ public class JavaContainerSetSlotTranslator extends PacketTranslator 0 ? packet.getVillagerLevel() - 1 : 0); // -1 crashes client - recipe.put("buyA", getItemTag(session, trade.getFirstInput(), trade.getSpecialPrice())); - if (trade.getSecondInput() != null) { - recipe.put("buyB", getItemTag(session, trade.getSecondInput(), 0)); - } + recipe.put("buyA", getItemTag(session, trade.getFirstInput(), trade.getSpecialPrice(), trade.getDemand(), trade.getPriceMultiplier())); + recipe.put("buyB", getItemTag(session, trade.getSecondInput())); recipe.putInt("uses", trade.getNumUses()); recipe.putByte("rewardExp", (byte) 1); tags.add(recipe.build()); @@ -144,12 +146,31 @@ public class JavaMerchantOffersTranslator extends PacketTranslator { @@ -57,8 +56,7 @@ public class JavaOpenScreenTranslator extends PacketTranslator= 2 && session.getGameMode() == GameMode.CREATIVE && packet.getNbt() != null && packet.getNbt().size() > 5) { ContainerOpenPacket openPacket = new ContainerOpenPacket(); - openPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + openPacket.setBlockPosition(position); openPacket.setId((byte) 1); openPacket.setType(ContainerType.COMMAND_BLOCK); openPacket.setUniqueEntityId(-1); 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 3504168a5..8824f88c4 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.level.block.value.*; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundBlockEventPacket; import com.nukkitx.math.vector.Vector3i; @@ -35,14 +34,13 @@ import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.BlockEventPacket; import it.unimi.dsi.fastutil.objects.Object2IntMaps; import org.geysermc.common.PlatformType; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.level.physics.Direction; 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.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.translator.level.block.entity.NoteblockBlockEntityTranslator; -import org.geysermc.geyser.translator.level.block.entity.PistonBlockEntity; -import org.geysermc.geyser.level.physics.Direction; @Translator(packet = ClientboundBlockEventPacket.class) public class JavaBlockEventTranslator extends PacketTranslator { @@ -50,8 +48,8 @@ public class JavaBlockEventTranslator extends PacketTranslator 0 ? 1 : 0); @@ -60,11 +58,12 @@ public class JavaBlockEventTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundCustomSoundPacket packet) { - String packetSound; - if (packet.getSound() instanceof BuiltinSound) { - packetSound = ((BuiltinSound) packet.getSound()).getName(); - } else if (packet.getSound() instanceof CustomSound) { - packetSound = ((CustomSound) packet.getSound()).getName(); - } else { - session.getGeyser().getLogger().debug("Unknown sound packet, we were unable to map this. " + packet.toString()); - return; - } - - SoundMapping soundMapping = Registries.SOUNDS.get(packetSound.replace("minecraft:", "")); - String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { - // no mapping - session.getGeyser().getLogger() - .debug("[PlaySound] Defaulting to sound server gave us for " + packet.toString()); - playsound = packetSound.replace("minecraft:", ""); - } else { - playsound = soundMapping.getPlaysound(); - } - PlaySoundPacket playSoundPacket = new PlaySoundPacket(); - playSoundPacket.setSound(playsound); + playSoundPacket.setSound(SoundUtils.translatePlaySound(packet.getSound())); playSoundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); playSoundPacket.setVolume(packet.getVolume()); playSoundPacket.setPitch(packet.getPitch()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java index d97035b5c..d5ac1abba 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaExplodeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundExplodePacket; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; @@ -34,10 +33,10 @@ import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; +import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.util.ChunkUtils; @Translator(packet = ClientboundExplodePacket.class) @@ -45,7 +44,7 @@ public class JavaExplodeTranslator extends PacketTranslator { @@ -40,19 +43,18 @@ public class JavaForgetLevelChunkTranslator extends PacketTranslator iterator = session.getSkullCache().keySet().iterator(); - while (iterator.hasNext()) { - Vector3i position = iterator.next(); + // Checks if a skull is in an unloaded chunk then removes it + List removedSkulls = new ArrayList<>(); + for (Vector3i position : session.getSkullCache().getSkulls().keySet()) { if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { - session.getSkullCache().get(position).despawnEntity(); - iterator.remove(); + removedSkulls.add(position); } } + removedSkulls.forEach(session.getSkullCache()::removeSkull); if (!session.getGeyser().getWorldManager().shouldExpectLecternHandled()) { // Do the same thing with lecterns - iterator = session.getLecternCache().iterator(); + Iterator iterator = session.getLecternCache().iterator(); while (iterator.hasNext()) { Vector3i position = iterator.next(); if ((position.getX() >> 4) == packet.getX() && (position.getZ() >> 4) == packet.getZ()) { @@ -60,5 +62,7 @@ public class JavaForgetLevelChunkTranslator extends PacketTranslator { @@ -96,24 +97,24 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator bedrockBlockEntities = new ObjectArrayList<>(blockEntities.length); BitSet waterloggedPaletteIds = new BitSet(); - BitSet pistonOrFlowerPaletteIds = new BitSet(); + BitSet bedrockOnlyBlockEntityIds = new BitSet(); - boolean overworld = session.getChunkCache().isExtendedHeight(); - int maxBedrockSectionY = ((overworld ? MAXIMUM_ACCEPTED_HEIGHT_OVERWORLD : MAXIMUM_ACCEPTED_HEIGHT) >> 4) - 1; + BedrockDimension bedrockDimension = session.getChunkCache().getBedrockDimension(); + int maxBedrockSectionY = (bedrockDimension.height() >> 4) - 1; int sectionCount; byte[] payload; ByteBuf byteBuf = null; - GeyserChunkSection[] sections = new GeyserChunkSection[javaChunks.length - (yOffset + ((overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4))]; + GeyserChunkSection[] sections = new GeyserChunkSection[javaChunks.length - (yOffset + (bedrockDimension.minY() >> 4))]; try { - NetInput in = new StreamNetInput(new ByteArrayInputStream(packet.getChunkData())); + ByteBuf in = Unpooled.wrappedBuffer(packet.getChunkData()); for (int sectionY = 0; sectionY < chunkSize; sectionY++) { - ChunkSection javaSection = ChunkSection.read(in, biomeGlobalPalette); + ChunkSection javaSection = session.getCodecHelper().readChunkSection(in, biomeGlobalPalette); javaChunks[sectionY] = javaSection.getChunkData(); javaBiomes[sectionY] = javaSection.getBiomeData(); - int bedrockSectionY = sectionY + (yOffset - ((overworld ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) >> 4)); + int bedrockSectionY = sectionY + (yOffset - (bedrockDimension.minY() >> 4)); if (bedrockSectionY < 0 || maxBedrockSectionY < bedrockSectionY) { // Ignore this chunk section since it goes outside the bounds accepted by the Bedrock client continue; @@ -141,7 +142,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), javaId @@ -170,7 +171,7 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 8) & 0xF), (packet.getZ() << 4) + ((yzx >> 4) & 0xF)), javaPalette.idToState(paletteId) @@ -230,9 +231,9 @@ public class JavaLevelChunkWithLightTranslator extends PacketTranslator> 4; - for (int i = 0; i < chunkSize; i++) { + // As of 1.18.30, the amount of biomes read is dependent on how high Bedrock thinks the dimension is + int biomeCount = bedrockDimension.height() >> 4; + int dimensionOffset = bedrockDimension.minY() >> 4; + for (int i = 0; i < biomeCount; i++) { int biomeYOffset = dimensionOffset + i; if (biomeYOffset < yOffset) { - // Ignore this biome section since it goes above or below the height of the Java world + // Ignore this biome section since it goes below the height of the Java world byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA); continue; } - BiomeTranslator.toNewBedrockBiome(session, javaBiomes[i + (dimensionOffset - yOffset)]).writeToNetwork(byteBuf); - } - - // As of 1.17.10, Bedrock hardcodes to always read 32 biome sections - // As of 1.18, this hardcode was lowered to 25 - if (session.getUpstream().getProtocolVersion() >= Bedrock_v475.V475_CODEC.getProtocolVersion()) { - int remainingEmptyBiomes = 25 - chunkSize; - for (int i = 0; i < remainingEmptyBiomes; i++) { - // A header that says to carry on the biome data from the previous chunk - // This notably fixes biomes in the End + if (biomeYOffset >= (chunkSize + yOffset)) { + // This biome section goes above the height of the Java world + // The byte written here is a header that says to carry on the biome data from the previous chunk byteBuf.writeByte((127 << 1) | 1); + continue; } - } else { - int remainingEmptyBiomes = 32 - chunkSize; - for (int i = 0; i < remainingEmptyBiomes; i++) { - byteBuf.writeBytes(ChunkUtils.EMPTY_BIOME_DATA); - } + + BiomeTranslator.toNewBedrockBiome(session, javaBiomes[i + (dimensionOffset - yOffset)]).writeToNetwork(byteBuf); } byteBuf.writeByte(0); // Border blocks - Edu edition only 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 d861d0338..8fcfa381f 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,32 +25,26 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.event.BonemealGrowEventData; -import com.github.steveice10.mc.protocol.data.game.level.event.BreakBlockEventData; -import com.github.steveice10.mc.protocol.data.game.level.event.BreakPotionEventData; -import com.github.steveice10.mc.protocol.data.game.level.event.ComposterEventData; -import com.github.steveice10.mc.protocol.data.game.level.event.DragonFireballEventData; -import com.github.steveice10.mc.protocol.data.game.level.event.ParticleEvent; -import com.github.steveice10.mc.protocol.data.game.level.event.RecordEventData; -import com.github.steveice10.mc.protocol.data.game.level.event.SmokeEventData; +import com.github.steveice10.mc.protocol.data.game.entity.object.Direction; +import com.github.steveice10.mc.protocol.data.game.level.event.*; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import com.nukkitx.protocol.bedrock.packet.TextPacket; -import com.nukkitx.protocol.bedrock.v465.Bedrock_v465; +import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.MinecraftLocale; +import org.geysermc.geyser.translator.level.event.LevelEventTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.translator.level.event.LevelEventTranslator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.text.MinecraftLocale; import java.util.Collections; import java.util.Locale; +import java.util.Set; @Translator(packet = ClientboundLevelEventPacket.class) public class JavaLevelEventTranslator extends PacketTranslator { @@ -58,10 +52,11 @@ public class JavaLevelEventTranslator extends PacketTranslator { + effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + + ComposterEventData composterEventData = (ComposterEventData) packet.getData(); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + switch (composterEventData) { + case FILL -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL); + case FILL_SUCCESS -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL_LAYER); + } + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); } - GeyserImpl.getInstance().getLogger().debug("Unhandled sound event: " + soundEvent.name()); - } else if (packet.getEvent() instanceof ParticleEvent particleEvent) { - Vector3f pos = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f); + case BLOCK_LAVA_EXTINGUISH -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0.7f, -0.5f)); - LevelEventPacket effectPacket = new LevelEventPacket(); - effectPacket.setPosition(pos); - effectPacket.setData(0); - switch (particleEvent) { - case COMPOSTER -> { - effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case BLOCK_REDSTONE_TORCH_BURNOUT -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0, -0.5f)); - ComposterEventData composterEventData = (ComposterEventData) packet.getData(); - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - switch (composterEventData) { - case FILL -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL); - case FILL_SUCCESS -> soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL_LAYER); + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case BLOCK_END_PORTAL_FRAME_FILL -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); + effectPacket.setPosition(pos.add(-0.5f, 0.3125f, -0.5f)); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.BLOCK_END_PORTAL_FRAME_FILL); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case SMOKE -> { + effectPacket.setType(LevelEventType.PARTICLE_SHOOT); + + SmokeEventData smokeEventData = (SmokeEventData) packet.getData(); + int data = 0; + switch (smokeEventData) { + case DOWN -> { + data = 4; + pos = pos.add(0, -0.9f, 0); } - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BLOCK_LAVA_EXTINGUISH -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); - effectPacket.setPosition(pos.add(-0.5f, 0.7f, -0.5f)); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BLOCK_REDSTONE_TORCH_BURNOUT -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); - effectPacket.setPosition(pos.add(-0.5f, 0, -0.5f)); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BLOCK_END_PORTAL_FRAME_FILL -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE); - effectPacket.setPosition(pos.add(-0.5f, 0.3125f, -0.5f)); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.BLOCK_END_PORTAL_FRAME_FILL); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case SMOKE -> { - effectPacket.setType(LevelEventType.PARTICLE_SHOOT); - - SmokeEventData smokeEventData = (SmokeEventData) packet.getData(); - int data = 0; - switch (smokeEventData) { - case DOWN -> { - data = 4; - pos = pos.add(0, -0.9f, 0); - } - case UP -> { - data = 4; - pos = pos.add(0, 0.5f, 0); - } - case NORTH -> { - data = 1; - pos = pos.add(0, -0.2f, -0.7f); - } - case SOUTH -> { - data = 7; - pos = pos.add(0, -0.2f, 0.7f); - } - case WEST -> { - data = 3; - pos = pos.add(-0.7f, -0.2f, 0); - } - case EAST -> { - data = 5; - pos = pos.add(0.7f, -0.2f, 0); - } + case UP -> { + data = 4; + pos = pos.add(0, 0.5f, 0); } - effectPacket.setPosition(pos); - effectPacket.setData(data); - } - - //TODO: Block break particles when under fire - case BREAK_BLOCK -> { - effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); - - BreakBlockEventData breakBlockEventData = (BreakBlockEventData) packet.getData(); - effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakBlockEventData.getBlockState())); - } - case BREAK_SPLASH_POTION -> { - effectPacket.setType(LevelEventType.PARTICLE_POTION_SPLASH); - effectPacket.setPosition(pos.add(0, -0.5f, 0)); - - BreakPotionEventData splashPotionData = (BreakPotionEventData) packet.getData(); - effectPacket.setData(splashPotionData.getPotionId()); - - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.GLASS); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - } - case BREAK_EYE_OF_ENDER -> effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); - case MOB_SPAWN -> effectPacket.setType(LevelEventType.PARTICLE_MOB_BLOCK_SPAWN); // TODO: Check, but I don't think I really verified this ever went into effect on Java - case BONEMEAL_GROW_WITH_SOUND, BONEMEAL_GROW -> { - effectPacket.setType((particleEvent == ParticleEvent.BONEMEAL_GROW - && session.getUpstream().getProtocolVersion() >= Bedrock_v465.V465_CODEC.getProtocolVersion()) ? LevelEventType.PARTICLE_TURTLE_EGG : LevelEventType.PARTICLE_CROP_GROWTH); - - BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); - effectPacket.setData(growEventData.getParticleCount()); - } - case ENDERDRAGON_FIREBALL_EXPLODE -> { - effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); // TODO - - DragonFireballEventData fireballEventData = (DragonFireballEventData) packet.getData(); - if (fireballEventData == DragonFireballEventData.HAS_SOUND) { - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXPLODE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); + case NORTH -> { + data = 1; + pos = pos.add(0, -0.2f, -0.7f); + } + case SOUTH -> { + data = 7; + pos = pos.add(0, -0.2f, 0.7f); + } + case WEST -> { + data = 3; + pos = pos.add(-0.7f, -0.2f, 0); + } + case EAST -> { + data = 5; + pos = pos.add(0.7f, -0.2f, 0); } } - case EXPLOSION -> { - effectPacket.setType(LevelEventType.PARTICLE_GENERIC_SPAWN); - effectPacket.setData(61); - } - case EVAPORATE -> { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE_WATER); - effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); - } - case END_GATEWAY_SPAWN -> { - effectPacket.setType(LevelEventType.PARTICLE_EXPLOSION); + effectPacket.setPosition(pos); + effectPacket.setData(data); + } + //TODO: Block break particles when under fire + case BREAK_BLOCK -> { + effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); + + BreakBlockEventData breakBlockEventData = (BreakBlockEventData) packet.getData(); + effectPacket.setData(session.getBlockMappings().getBedrockBlockId(breakBlockEventData.getBlockState())); + } + case BREAK_SPLASH_POTION, BREAK_SPLASH_POTION2 -> { + effectPacket.setType(LevelEventType.PARTICLE_POTION_SPLASH); + effectPacket.setPosition(pos.add(0, -0.5f, 0)); + + BreakPotionEventData splashPotionData = (BreakPotionEventData) packet.getData(); + effectPacket.setData(splashPotionData.getPotionId()); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.GLASS); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case BREAK_EYE_OF_ENDER -> effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); + case MOB_SPAWN -> effectPacket.setType(LevelEventType.PARTICLE_MOB_BLOCK_SPAWN); // TODO: Check, but I don't think I really verified this ever went into effect on Java + case BONEMEAL_GROW_WITH_SOUND, BONEMEAL_GROW -> { + effectPacket.setType(packet.getEvent() == LevelEvent.BONEMEAL_GROW ? LevelEventType.PARTICLE_TURTLE_EGG : LevelEventType.PARTICLE_CROP_GROWTH); + + BonemealGrowEventData growEventData = (BonemealGrowEventData) packet.getData(); + effectPacket.setData(growEventData.getParticleCount()); + } + case ENDERDRAGON_FIREBALL_EXPLODE -> { + effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); // TODO + + DragonFireballEventData fireballEventData = (DragonFireballEventData) packet.getData(); + if (fireballEventData == DragonFireballEventData.HAS_SOUND) { LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); soundEventPacket.setSound(SoundEvent.EXPLODE); soundEventPacket.setPosition(pos); @@ -259,17 +232,110 @@ public class JavaLevelEventTranslator extends PacketTranslator effectPacket.setType(LevelEventType.PARTICLE_DRIPSTONE_DRIP); - case ELECTRIC_SPARK -> effectPacket.setType(LevelEventType.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java - case WAX_ON -> effectPacket.setType(LevelEventType.PARTICLE_WAX_ON); - case WAX_OFF -> effectPacket.setType(LevelEventType.PARTICLE_WAX_OFF); - case SCRAPE -> effectPacket.setType(LevelEventType.PARTICLE_SCRAPE); - default -> { - GeyserImpl.getInstance().getLogger().debug("Unhandled particle event: " + particleEvent.name()); - return; - } } - session.sendUpstreamPacket(effectPacket); + case EXPLOSION -> { + effectPacket.setType(LevelEventType.PARTICLE_GENERIC_SPAWN); + effectPacket.setData(61); + } + case EVAPORATE -> { + effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE_WATER); + effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); + } + case END_GATEWAY_SPAWN -> { + effectPacket.setType(LevelEventType.PARTICLE_EXPLOSION); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.EXPLODE); + soundEventPacket.setPosition(pos); + soundEventPacket.setIdentifier(""); + soundEventPacket.setExtraData(-1); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + } + case DRIPSTONE_DRIP -> effectPacket.setType(LevelEventType.PARTICLE_DRIPSTONE_DRIP); + case ELECTRIC_SPARK -> effectPacket.setType(LevelEventType.PARTICLE_ELECTRIC_SPARK); // Matches with a Bedrock server but doesn't seem to match up with Java + case WAX_ON -> effectPacket.setType(LevelEventType.PARTICLE_WAX_ON); + case WAX_OFF -> effectPacket.setType(LevelEventType.PARTICLE_WAX_OFF); + case SCRAPE -> effectPacket.setType(LevelEventType.PARTICLE_SCRAPE); + case SCULK_BLOCK_CHARGE -> { + SculkBlockChargeEventData eventData = (SculkBlockChargeEventData) packet.getData(); + LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); + // TODO add SCULK_BLOCK_CHARGE sound + if (eventData.getCharge() > 0) { + levelEventPacket.setEventId(2037); + levelEventPacket.setTag( + NbtMap.builder() + .putInt("x", packet.getPosition().getX()) + .putInt("y", packet.getPosition().getY()) + .putInt("z", packet.getPosition().getZ()) + .putShort("charge", (short) eventData.getCharge()) + .putShort("facing", encodeFacing(eventData.getBlockFaces())) // TODO check if this is actually correct + .build() + ); + } else { + levelEventPacket.setEventId(2038); + levelEventPacket.setTag( + NbtMap.builder() + .putInt("x", packet.getPosition().getX()) + .putInt("y", packet.getPosition().getY()) + .putInt("z", packet.getPosition().getZ()) + .build() + ); + } + session.sendUpstreamPacket(levelEventPacket); + return; + } + case SCULK_SHRIEKER_SHRIEK -> { + LevelEventGenericPacket levelEventPacket = new LevelEventGenericPacket(); + levelEventPacket.setEventId(2035); + levelEventPacket.setTag( + NbtMap.builder() + .putInt("originX", packet.getPosition().getX()) + .putInt("originY", packet.getPosition().getY()) + .putInt("originZ", packet.getPosition().getZ()) + .build() + ); + session.sendUpstreamPacket(levelEventPacket); + + LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); + soundEventPacket.setSound(SoundEvent.SCULK_SHRIEKER_SHRIEK); + soundEventPacket.setPosition(packet.getPosition().toFloat()); + soundEventPacket.setExtraData(-1); + soundEventPacket.setIdentifier(""); + soundEventPacket.setBabySound(false); + soundEventPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEventPacket); + return; + } + default -> { + GeyserImpl.getInstance().getLogger().debug("Unhandled level event: " + packet.getEvent()); + return; + } } + session.sendUpstreamPacket(effectPacket); + } + + private short encodeFacing(Set blockFaces) { + short facing = 0; + if (blockFaces.contains(Direction.DOWN)) { + facing |= 1; + } + if (blockFaces.contains(Direction.UP)) { + facing |= 1 << 1; + } + if (blockFaces.contains(Direction.SOUTH)) { + facing |= 1 << 2; + } + if (blockFaces.contains(Direction.WEST)) { + facing |= 1 << 3; + } + if (blockFaces.contains(Direction.NORTH)) { + facing |= 1 << 4; + } + if (blockFaces.contains(Direction.EAST)) { + facing |= 1 << 5; + } + return facing; } } \ No newline at end of file diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index 7cbdc2a4b..a413421a3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,13 +27,18 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.level.particle.*; +import com.github.steveice10.mc.protocol.data.game.level.particle.positionsource.BlockPositionSource; +import com.github.steveice10.mc.protocol.data.game.level.particle.positionsource.EntityPositionSource; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundLevelParticlesPacket; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.BedrockPacket; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.packet.LevelEventGenericPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import com.nukkitx.protocol.bedrock.packet.SpawnParticleEffectPacket; +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; @@ -42,6 +47,7 @@ import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.ParticleMapping; import org.geysermc.geyser.util.DimensionUtils; +import java.util.Optional; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import java.util.function.Function; @@ -130,6 +136,39 @@ public class JavaLevelParticlesTranslator extends PacketTranslator { + VibrationParticleData data = (VibrationParticleData) particle.getData(); + + Vector3f target; + if (data.getPositionSource() instanceof BlockPositionSource blockPositionSource) { + target = blockPositionSource.getPosition().toFloat().add(0.5f, 0.5f, 0.5f); + } else if (data.getPositionSource() instanceof EntityPositionSource entityPositionSource) { + Entity entity = session.getEntityCache().getEntityByJavaId(entityPositionSource.getEntityId()); + if (entity != null) { + target = entity.getPosition().up(entityPositionSource.getYOffset()); + } else { + session.getGeyser().getLogger().debug("Unable to find entity with Java Id: " + entityPositionSource.getEntityId() + " for vibration particle."); + return null; + } + } else { + session.getGeyser().getLogger().debug("Unknown position source " + data.getPositionSource() + " for vibration particle."); + return null; + } + + return (position) -> { + LevelEventGenericPacket packet = new LevelEventGenericPacket(); + packet.setEventId(2027); + packet.setTag( + NbtMap.builder() + .putCompound("origin", buildVec3PositionTag(position)) + .putCompound("target", buildVec3PositionTag(target)) // There is a way to target an entity but that takes an attachPos instead of a y offset + .putFloat("speed", 20f) + .putFloat("timeToLive", data.getArrivalTicks() / 20f) + .build() + ); + return packet; + }; + } default -> { ParticleMapping particleMapping = Registries.PARTICLES.get(particle.getType()); if (particleMapping == null) { //TODO ensure no particle can be null @@ -150,6 +189,7 @@ public class JavaLevelParticlesTranslator extends PacketTranslator= 0) { // Client thinks there is no daylight cycle but there is diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java index e9f9337aa..5b83ff551 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaSoundTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,78 +27,17 @@ package org.geysermc.geyser.translator.protocol.java.level; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.level.ClientboundSoundPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.util.SoundUtils; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; @Translator(packet = ClientboundSoundPacket.class) public class JavaSoundTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundSoundPacket packet) { - String packetSound = packet.getSound().getName(); - - SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); - if (soundMapping == null) { - session.getGeyser().getLogger().debug("[Builtin] Sound mapping " + packetSound + " not found - " + packet.toString()); - return; - } - - if (soundMapping.isLevelEvent()) { - LevelEventPacket levelEventPacket = new LevelEventPacket(); - levelEventPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - levelEventPacket.setData(0); - levelEventPacket.setType(LevelEventType.valueOf(soundMapping.getBedrock())); - session.sendUpstreamPacket(levelEventPacket); - return; - } - LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); - SoundEvent sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); - if (sound == null) { - sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); - } - if (sound == null) { - sound = SoundUtils.toSoundEvent(packetSound); - } - if (sound == null) { - session.getGeyser().getLogger().debug("[Builtin] Sound for original " + packetSound + " to mappings " + soundPacket - + " was not a playable level sound, or has yet to be mapped to an enum in " - + "NukkitX SoundEvent "); - return; - } - - soundPacket.setSound(sound); - soundPacket.setPosition(Vector3f.from(packet.getX(), packet.getY(), packet.getZ())); - soundPacket.setIdentifier(soundMapping.getIdentifier()); - if (sound == SoundEvent.NOTE) { - // Minecraft Wiki: 2^(x/12) = Java pitch where x is -12 to 12 - // Java sends the note value as above starting with -12 and ending at 12 - // Bedrock has a number for each type of note, then proceeds up the scale by adding to that number - soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(packet.getPitch()) / Math.log10(2)) * 12)) + 12); - } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { - if (!soundMapping.getIdentifier().equals(":")) { - soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId( - BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID))); - } else { - session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + packet.toString()); - } - soundPacket.setIdentifier(":"); - } else { - soundPacket.setExtraData(soundMapping.getExtraData()); - } - - - soundPacket.setBabySound(false); // might need to adjust this in the future - soundPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundPacket); + Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); + SoundUtils.playBuiltinSound(session, packet.getSound(), position, packet.getVolume(), packet.getPitch()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java index 75a99f0af..e5bc7999f 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaStopSoundTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,15 +25,12 @@ package org.geysermc.geyser.translator.protocol.java.level; -import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; -import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; import com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundStopSoundPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.util.SoundUtils; @Translator(packet = ClientboundStopSoundPacket.class) public class JavaStopSoundTranslator extends PacketTranslator { @@ -49,36 +46,11 @@ public class JavaStopSoundTranslator extends PacketTranslator " - + soundMapping + (soundMapping == null ? "[not found]" : "") - + " - " + packet.toString()); - String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { - // no mapping - session.getGeyser().getLogger() - .debug("[StopSound] Defaulting to sound server gave us."); - playsound = packetSound; - } else { - playsound = soundMapping.getPlaysound(); - } - StopSoundPacket stopSoundPacket = new StopSoundPacket(); - stopSoundPacket.setSoundName(playsound); - // packet not mapped in the library + stopSoundPacket.setSoundName(SoundUtils.translatePlaySound(packet.getSound())); stopSoundPacket.setStoppingAllSound(false); session.sendUpstreamPacket(stopSoundPacket); - session.getGeyser().getLogger().debug("[StopSound] Packet sent - " + packet.toString() + " --> " + stopSoundPacket); + session.getGeyser().getLogger().debug("[StopSound] Stopped " + packet.getSound() + " -> " + stopSoundPacket.getSoundName()); } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java index 1f7ea7657..133d361b7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaInitializeBorderTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java index 6895cf944..c98fc1636 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderCenterTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java index 3eae4b1f5..a41c90f04 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderLerpSizeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java index 076924735..51cd17278 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderSizeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java index b3104fb9a..912ca9a09 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDelayTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java index b4483b9a6..14badb565 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/border/JavaSetBorderWarningDistanceTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java index fe141486e..b34e54db6 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java index 79c0036ad..33da27a88 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetObjectiveTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java index 5a0773bbe..40129701d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java index 62f73114b..41e9a38a2 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetScoreTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java index f1f424f4a..67112833b 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/title/JavaClearTitlesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,11 +37,14 @@ public class JavaClearTitlesTranslator extends PacketTranslator { - - /** - * Handles the block interaction when a player - * right-clicks an entity. - * - * @param session the session interacting with the block - * @param position the position of the block - * @param entity the entity interacted with - */ - static void handleEntityInteraction(GeyserSession session, Vector3f position, Entity entity) { - // If we need to get the hand identifier, only get it once and save it to a variable - String handIdentifier = null; - - for (Map.Entry> interactionEntry : Registries.SOUND_TRANSLATORS.get().entrySet()) { - if (!(interactionEntry.getValue() instanceof EntitySoundInteractionTranslator)) { - continue; - } - if (interactionEntry.getKey().entities().length != 0) { - boolean contains = false; - for (String entityIdentifier : interactionEntry.getKey().entities()) { - if (entity.getDefinition().entityType().name().toLowerCase().contains(entityIdentifier)) { - contains = true; - break; - } - } - if (!contains) continue; - } - GeyserItemStack itemInHand = session.getPlayerInventory().getItemInHand(); - if (interactionEntry.getKey().items().length != 0) { - if (itemInHand.isEmpty()) { - continue; - } - if (handIdentifier == null) { - // Don't get the identifier unless we need it - handIdentifier = itemInHand.getMapping(session).getJavaIdentifier(); - } - boolean contains = false; - for (String itemIdentifier : interactionEntry.getKey().items()) { - if (handIdentifier.contains(itemIdentifier)) { - contains = true; - break; - } - } - if (!contains) continue; - } - if (session.isSneaking() && !interactionEntry.getKey().ignoreSneakingWhileHolding()) { - if (!itemInHand.isEmpty()) { - continue; - } - } - ((EntitySoundInteractionTranslator) interactionEntry.getValue()).translate(session, position, entity); - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/SoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/SoundInteractionTranslator.java index 7cccbb21d..536d5e188 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/SoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/SoundInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/SoundTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/SoundTranslator.java index be8257993..0146c534e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/SoundTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/SoundTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -54,17 +54,6 @@ public @interface SoundTranslator { */ String[] items() default {}; - /** - * The identifier(s) that the interacted entity must have. - * Leave empty to ignore. - * - * Only applies to interaction handlers that are an - * instance of {@link EntitySoundInteractionTranslator}. - * - * @return the value the item in the player's hand must contain - */ - String[] entities() default {}; - /** * Controls if the interaction should still be * called even if the player is sneaking while diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java index 1af30e658..2cbcd329a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/BucketSoundInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java index 8c10076d3..9256a8a62 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/ComparatorSoundInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java index 1115760eb..b03af4037 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/DoorSoundInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java index 09e86f461..6655c8163 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/FlintAndSteelInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java index 6c91b24a0..98f460dd7 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/GrassPathInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java index 799364498..0e1aae95c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/HoeInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java index a57d337b1..f4869bafa 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/sound/block/LeverSoundInteractionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/entity/FeedBabySoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/entity/FeedBabySoundInteractionTranslator.java deleted file mode 100644 index ea160538e..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/entity/FeedBabySoundInteractionTranslator.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.translator.sound.entity; - -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; -import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; -import org.geysermc.geyser.entity.type.living.animal.OcelotEntity; -import org.geysermc.geyser.entity.type.living.animal.tameable.CatEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.sound.EntitySoundInteractionTranslator; -import org.geysermc.geyser.translator.sound.SoundTranslator; - -@SoundTranslator -public class FeedBabySoundInteractionTranslator implements EntitySoundInteractionTranslator { - - @Override - public void translate(GeyserSession session, Vector3f position, Entity entity) { - if (entity instanceof AnimalEntity animalEntity && !(entity instanceof CatEntity || entity instanceof OcelotEntity)) { - String handIdentifier = session.getPlayerInventory().getItemInHand().getMapping(session).getJavaIdentifier(); - boolean isBaby = animalEntity.isBaby(); - if (isBaby && animalEntity.canEat(handIdentifier.replace("minecraft:", ""), - session.getPlayerInventory().getItemInHand().getMapping(session))) { - // Play the "feed child" effect - EntityEventPacket feedEvent = new EntityEventPacket(); - feedEvent.setRuntimeEntityId(entity.getGeyserId()); - feedEvent.setType(EntityEventType.BABY_ANIMAL_FEED); - session.sendUpstreamPacket(feedEvent); - } - } - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/sound/entity/MilkEntitySoundInteractionTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/sound/entity/MilkEntitySoundInteractionTranslator.java deleted file mode 100644 index e8698ff23..000000000 --- a/core/src/main/java/org/geysermc/geyser/translator/sound/entity/MilkEntitySoundInteractionTranslator.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019-2021 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.translator.sound.entity; - -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import org.geysermc.geyser.entity.type.Entity; -import org.geysermc.geyser.entity.type.living.animal.GoatEntity; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.sound.EntitySoundInteractionTranslator; -import org.geysermc.geyser.translator.sound.SoundTranslator; - -@SoundTranslator(entities = {"cow", "goat"}, items = "bucket") -public class MilkEntitySoundInteractionTranslator implements EntitySoundInteractionTranslator { - - @Override - public void translate(GeyserSession session, Vector3f position, Entity value) { - if (!session.getPlayerInventory().getItemInHand().getMapping(session).getJavaIdentifier().equals("minecraft:bucket")) { - return; - } - if (value.getFlag(EntityFlag.BABY)) { - return; - } - - SoundEvent milkSound; - if (value instanceof GoatEntity && ((GoatEntity) value).isScreamer()) { - milkSound = SoundEvent.MILK_SCREAMER; - } else { - milkSound = SoundEvent.MILK; - } - LevelSoundEventPacket levelSoundEventPacket = new LevelSoundEventPacket(); - levelSoundEventPacket.setPosition(position); - levelSoundEventPacket.setBabySound(false); - levelSoundEventPacket.setRelativeVolumeDisabled(false); - levelSoundEventPacket.setIdentifier(":"); - levelSoundEventPacket.setSound(milkSound); - levelSoundEventPacket.setExtraData(-1); - session.sendUpstreamPacket(levelSoundEventPacket); - } -} diff --git a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java index a34b2c63c..6f446f136 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/text/MessageTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -34,10 +34,7 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.text.ChatColor; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.text.GsonComponentSerializerWrapper; -import org.geysermc.geyser.text.MinecraftTranslationRegistry; +import org.geysermc.geyser.text.*; import java.util.EnumMap; import java.util.Map; @@ -85,8 +82,13 @@ public class MessageTranslator { TEAM_COLORS.put(TeamColor.STRIKETHROUGH, BASE + "m"); TEAM_COLORS.put(TeamColor.ITALIC, BASE + "o"); - // Temporary fix for https://github.com/KyoriPowered/adventure/issues/447 - GsonComponentSerializer source = DefaultComponentSerializer.get(); + // Temporary fix for https://github.com/KyoriPowered/adventure/issues/447 - TODO resolve properly + GsonComponentSerializer source = DefaultComponentSerializer.get() + .toBuilder() + // Use a custom legacy hover event deserializer since we don't use any of this data anyway, and + // fixes issues where legacy hover events throw deserialization errors + .legacyHoverEventSerializer(new DummyLegacyHoverEventSerializer()) + .build(); GSON_SERIALIZER = new GsonComponentSerializerWrapper(source); // Tell MCProtocolLib to use this serializer, too. DefaultComponentSerializer.set(GSON_SERIALIZER); diff --git a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java index 56ef71f91..2958de436 100644 --- a/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/AttributeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java index 6d4258d7e..af059cbdd 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,20 +25,19 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.level.block.BlockEntityType; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.geyser.translator.level.block.entity.FlowerPotBlockEntityTranslator; -import org.geysermc.geyser.registry.Registries; import javax.annotation.Nonnull; -import java.util.HashMap; +import java.util.List; +import java.util.Locale; import java.util.Map; public class BlockEntityUtils { @@ -46,27 +45,22 @@ public class BlockEntityUtils { * A list of all block entities that require the Java block state in order to fill out their block entity information. * This list will be smaller with cache sections on as we don't need to double-cache data */ - public static final ObjectArrayList BEDROCK_ONLY_BLOCK_ENTITIES = new ObjectArrayList<>(); + public static final List BEDROCK_ONLY_BLOCK_ENTITIES = List.of( + (BedrockOnlyBlockEntity) Registries.BLOCK_ENTITIES.get().get(BlockEntityType.CHEST), + new FlowerPotBlockEntityTranslator() + ); /** * Contains a list of irregular block entity name translations that can't be fit into the regex */ - public static final Map BLOCK_ENTITY_TRANSLATIONS = new HashMap<>() { - { + public static final Map BLOCK_ENTITY_TRANSLATIONS = Map.of( // Bedrock/Java differences - put(BlockEntityType.ENCHANTING_TABLE, "EnchantTable"); - put(BlockEntityType.JIGSAW, "JigsawBlock"); - put(BlockEntityType.PISTON, "PistonArm"); - put(BlockEntityType.TRAPPED_CHEST, "Chest"); + BlockEntityType.ENCHANTING_TABLE, "EnchantTable", + BlockEntityType.JIGSAW, "JigsawBlock", + BlockEntityType.PISTON, "PistonArm", + BlockEntityType.TRAPPED_CHEST, "Chest" // There are some legacy IDs sent but as far as I can tell they are not needed for things to work properly - } - }; - - static { - // Seeing as there are only two - and, hopefully, will only ever be two - we can hardcode this - BEDROCK_ONLY_BLOCK_ENTITIES.add((BedrockOnlyBlockEntity) Registries.BLOCK_ENTITIES.get().get(BlockEntityType.CHEST)); - BEDROCK_ONLY_BLOCK_ENTITIES.add(new FlowerPotBlockEntityTranslator()); - } + ); public static String getBedrockBlockEntityId(BlockEntityType type) { // These are the only exceptions when it comes to block entity ids @@ -77,9 +71,9 @@ public class BlockEntityUtils { String id = type.name(); // Split at every space or capital letter - for the latter, some legacy Java block entity tags are the correct format already - String[] words = id.split("_");; + String[] words = id.split("_"); for (int i = 0; i < words.length; i++) { - words[i] = words[i].substring(0, 1).toUpperCase() + words[i].substring(1).toLowerCase(); + words[i] = words[i].substring(0, 1).toUpperCase(Locale.ROOT) + words[i].substring(1).toLowerCase(Locale.ROOT); } return String.join("", words); @@ -89,10 +83,6 @@ public class BlockEntityUtils { return Registries.BLOCK_ENTITIES.get(type); } - public static void updateBlockEntity(GeyserSession session, @Nonnull NbtMap blockEntity, Position position) { - updateBlockEntity(session, blockEntity, Vector3i.from(position.getX(), position.getY(), position.getZ())); - } - public static void updateBlockEntity(GeyserSession session, @Nonnull NbtMap blockEntity, Vector3i position) { BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket(); blockEntityPacket.setBlockPosition(position); diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java index c43cc3311..7059c9a8b 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,23 +25,18 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3i; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.PlayerInventory; -import org.geysermc.geyser.session.GeyserSession; -import org.geysermc.geyser.translator.collision.BlockCollision; import org.geysermc.geyser.level.block.BlockStateValues; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.registry.type.BlockMapping; import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.translator.collision.BlockCollision; -public class BlockUtils { - /** - * A static constant of {@link Position} with all values being zero. - */ - public static final Position POSITION_ZERO = new Position(0, 0, 0); +public final class BlockUtils { private static boolean correctTool(GeyserSession session, BlockMapping blockMapping, String itemToolType) { switch (itemToolType) { @@ -241,4 +236,7 @@ public class BlockUtils { public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) { return getCollision(session.getGeyser().getWorldManager().getBlockAt(session, x, y, z)); } + + private BlockUtils() { + } } 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 cb80e209b..d1ee9f165 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ChunkUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,10 +25,6 @@ package org.geysermc.geyser.util; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.DoubleTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.nukkitx.math.vector.Vector2i; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; @@ -39,31 +35,21 @@ import io.netty.buffer.Unpooled; import it.unimi.dsi.fastutil.ints.IntLists; import lombok.experimental.UtilityClass; import org.geysermc.geyser.entity.type.ItemFrameEntity; -import org.geysermc.geyser.entity.type.player.SkullPlayerEntity; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.level.BedrockDimension; +import org.geysermc.geyser.level.JavaDimension; import org.geysermc.geyser.level.block.BlockStateValues; -import org.geysermc.geyser.text.GeyserLocale; -import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import org.geysermc.geyser.level.chunk.BlockStorage; import org.geysermc.geyser.level.chunk.GeyserChunkSection; import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.geyser.text.GeyserLocale; +import org.geysermc.geyser.translator.level.block.entity.BedrockOnlyBlockEntity; import static org.geysermc.geyser.level.block.BlockStateValues.JAVA_AIR_ID; @UtilityClass public class ChunkUtils { - /** - * The minimum height Bedrock Edition will accept. - */ - public static final int MINIMUM_ACCEPTED_HEIGHT = 0; - public static final int MINIMUM_ACCEPTED_HEIGHT_OVERWORLD = -64; - /** - * The maximum chunk height Bedrock Edition will accept, from the lowest point to the highest. - */ - public static final int MAXIMUM_ACCEPTED_HEIGHT = 256; - public static final int MAXIMUM_ACCEPTED_HEIGHT_OVERWORLD = 384; - /** * An empty subchunk. */ @@ -122,7 +108,7 @@ public class ChunkUtils { if (chunkPos == null || !chunkPos.equals(newChunkPos)) { NetworkChunkPublisherUpdatePacket chunkPublisherUpdatePacket = new NetworkChunkPublisherUpdatePacket(); chunkPublisherUpdatePacket.setPosition(position); - chunkPublisherUpdatePacket.setRadius(session.getRenderDistance() << 4); + chunkPublisherUpdatePacket.setRadius(session.getServerRenderDistance() << 4); session.sendUpstreamPacket(chunkPublisherUpdatePacket); session.setLastChunkPosition(newChunkPos); @@ -130,19 +116,7 @@ public class ChunkUtils { } /** - * Sends a block update to the Bedrock client. If chunk caching is enabled and the platform is not Spigot, this also - * adds that block to the cache. - * @param session the Bedrock session to send/register the block to - * @param blockState the Java block state of the block - * @param position the position of the block - */ - public static void updateBlock(GeyserSession session, int blockState, Position position) { - Vector3i pos = Vector3i.from(position.getX(), position.getY(), position.getZ()); - updateBlock(session, blockState, pos); - } - - /** - * Sends a block update to the Bedrock client. If chunk caching is enabled and the platform is not Spigot, this also + * Sends a block update to the Bedrock client. If the platform is not Spigot, this also * adds that block to the cache. * @param session the Bedrock session to send/register the block to * @param blockState the Java block state of the block @@ -161,10 +135,9 @@ public class ChunkUtils { // Otherwise, let's still store our reference to the item frame, but let the new block take precedence for now } - SkullPlayerEntity skull = session.getSkullCache().get(position); - if (skull != null && blockState != skull.getBlockState()) { + if (BlockStateValues.getSkullVariant(blockState) == -1) { // Skull is gone - skull.despawnEntity(position); + session.getSkullCache().removeSkull(position); } // Prevent moving_piston from being placed @@ -205,27 +178,31 @@ public class ChunkUtils { session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState); } + public static void sendEmptyChunk(GeyserSession session, int chunkX, int chunkZ, boolean forceUpdate) { + LevelChunkPacket data = new LevelChunkPacket(); + data.setChunkX(chunkX); + data.setChunkZ(chunkZ); + data.setSubChunksLength(0); + data.setData(EMPTY_CHUNK_DATA); + data.setCachingEnabled(false); + session.sendUpstreamPacket(data); + + if (forceUpdate) { + Vector3i pos = Vector3i.from(chunkX << 4, 80, chunkZ << 4); + UpdateBlockPacket blockPacket = new UpdateBlockPacket(); + blockPacket.setBlockPosition(pos); + blockPacket.setDataLayer(0); + blockPacket.setRuntimeId(1); + session.sendUpstreamPacket(blockPacket); + } + } + public static void sendEmptyChunks(GeyserSession session, Vector3i position, int radius, boolean forceUpdate) { int chunkX = position.getX() >> 4; int chunkZ = position.getZ() >> 4; for (int x = -radius; x <= radius; x++) { for (int z = -radius; z <= radius; z++) { - LevelChunkPacket data = new LevelChunkPacket(); - data.setChunkX(chunkX + x); - data.setChunkZ(chunkZ + z); - data.setSubChunksLength(0); - data.setData(EMPTY_CHUNK_DATA); - data.setCachingEnabled(false); - session.sendUpstreamPacket(data); - - if (forceUpdate) { - Vector3i pos = Vector3i.from(chunkX + x << 4, 80, chunkZ + z << 4); - UpdateBlockPacket blockPacket = new UpdateBlockPacket(); - blockPacket.setBlockPosition(pos); - blockPacket.setDataLayer(0); - blockPacket.setRuntimeId(1); - session.sendUpstreamPacket(blockPacket); - } + sendEmptyChunk(session, chunkX + x, chunkZ + z, forceUpdate); } } } @@ -234,10 +211,10 @@ public class ChunkUtils { * Process the minimum and maximum heights for this dimension, and processes the world coordinate scale. * This must be done after the player has switched dimensions so we know what their dimension is */ - public static void loadDimensionTag(GeyserSession session, CompoundTag dimensionTag) { - int minY = ((IntTag) dimensionTag.get("min_y")).getValue(); - int maxY = ((IntTag) dimensionTag.get("height")).getValue(); - // Logical height can be ignored probably - seems to be for artificial limits like the Nether. + public static void loadDimension(GeyserSession session) { + JavaDimension dimension = session.getDimensionType(); + int minY = dimension.minY(); + int maxY = dimension.maxY(); if (minY % 16 != 0) { throw new RuntimeException("Minimum Y must be a multiple of 16!"); @@ -246,25 +223,26 @@ public class ChunkUtils { throw new RuntimeException("Maximum Y must be a multiple of 16!"); } - int dimension = DimensionUtils.javaToBedrock(session.getDimension()); - boolean extendedHeight = dimension == 0; - session.getChunkCache().setExtendedHeight(extendedHeight); + BedrockDimension bedrockDimension = switch (session.getDimension()) { + case DimensionUtils.THE_END -> BedrockDimension.THE_END; + case DimensionUtils.NETHER -> DimensionUtils.isCustomBedrockNetherId() ? BedrockDimension.THE_END : BedrockDimension.THE_NETHER; + default -> BedrockDimension.OVERWORLD; + }; + session.getChunkCache().setBedrockDimension(bedrockDimension); // Yell in the console if the world height is too height in the current scenario // The constraints change depending on if the player is in the overworld or not, and if experimental height is enabled - if (minY < (extendedHeight ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT) - || maxY > (extendedHeight ? MAXIMUM_ACCEPTED_HEIGHT_OVERWORLD : MAXIMUM_ACCEPTED_HEIGHT)) { + // (Ignore this for the Nether. We can't change that at the moment without the workaround. :/ ) + if (minY < bedrockDimension.minY() || (bedrockDimension.doUpperHeightWarn() && maxY > bedrockDimension.height())) { session.getGeyser().getLogger().warning(GeyserLocale.getLocaleStringLog("geyser.network.translator.chunk.out_of_bounds", - extendedHeight ? MINIMUM_ACCEPTED_HEIGHT_OVERWORLD : MINIMUM_ACCEPTED_HEIGHT, - extendedHeight ? MAXIMUM_ACCEPTED_HEIGHT_OVERWORLD : MAXIMUM_ACCEPTED_HEIGHT, + String.valueOf(bedrockDimension.minY()), + String.valueOf(bedrockDimension.height()), session.getDimension())); } session.getChunkCache().setMinY(minY); session.getChunkCache().setHeightY(maxY); - // Load world coordinate scale for the world border - double coordinateScale = ((DoubleTag) dimensionTag.get("coordinate_scale")).getValue(); - session.getWorldBorder().setWorldCoordinateScale(coordinateScale); + session.getWorldBorder().setWorldCoordinateScale(dimension.worldCoordinateScale()); } } diff --git a/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java b/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java index c149996b8..23af2b709 100644 --- a/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/CooldownUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -57,8 +57,19 @@ public class CooldownUtils { if (sessionPreference == CooldownType.DISABLED) return; if (session.getAttackSpeed() == 0.0 || session.getAttackSpeed() > 20) return; // 0.0 usually happens on login and causes issues with visuals; anything above 20 means a plugin like OldCombatMechanics is being used - // Needs to be sent or no subtitle packet is recognized by the client + // Set the times to stay a bit with no fade in nor out SetTitlePacket titlePacket = new SetTitlePacket(); + titlePacket.setType(SetTitlePacket.Type.TIMES); + titlePacket.setStayTime(1000); + titlePacket.setText(""); + titlePacket.setXuid(""); + titlePacket.setPlatformOnlineId(""); + session.sendUpstreamPacket(titlePacket); + + session.getWorldCache().markTitleTimesAsIncorrect(); + + // Needs to be sent or no subtitle packet is recognized by the client + titlePacket = new SetTitlePacket(); titlePacket.setType(SetTitlePacket.Type.TITLE); titlePacket.setText(" "); titlePacket.setXuid(""); @@ -85,9 +96,6 @@ public class CooldownUtils { titlePacket.setType(SetTitlePacket.Type.SUBTITLE); } titlePacket.setText(getTitle(session)); - titlePacket.setFadeInTime(0); - titlePacket.setFadeOutTime(5); - titlePacket.setStayTime(2); titlePacket.setXuid(""); titlePacket.setPlatformOnlineId(""); session.sendUpstreamPacket(titlePacket); @@ -96,11 +104,7 @@ public class CooldownUtils { computeCooldown(session, sessionPreference, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 } else { SetTitlePacket removeTitlePacket = new SetTitlePacket(); - if (sessionPreference == CooldownType.ACTIONBAR) { - removeTitlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - } else { - removeTitlePacket.setType(SetTitlePacket.Type.SUBTITLE); - } + removeTitlePacket.setType(SetTitlePacket.Type.CLEAR); removeTitlePacket.setText(" "); removeTitlePacket.setXuid(""); removeTitlePacket.setPlatformOnlineId(""); diff --git a/core/src/main/java/org/geysermc/geyser/util/CpuUtils.java b/core/src/main/java/org/geysermc/geyser/util/CpuUtils.java new file mode 100644 index 000000000..622722e5a --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/CpuUtils.java @@ -0,0 +1,94 @@ +/* + * 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.util; + +import java.io.File; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; +import java.util.regex.Pattern; + +public final class CpuUtils { + + public static String tryGetProcessorName() { + try { + if (new File("/proc/cpuinfo").canRead()) { + return getLinuxProcessorName(); + } else { + return getWindowsProcessorName(); + } + } catch (Exception e) { + return e.getMessage(); + } + } + + /** + * Much of the code here was copied from the OSHI project. This is simply stripped down to only get the CPU model. + * https://github.com/oshi/oshi/ + */ + private static String getLinuxProcessorName() throws Exception { + List lines = Files.readAllLines(Paths.get("/proc/cpuinfo"), StandardCharsets.UTF_8); + Pattern whitespaceColonWhitespace = Pattern.compile("\\s+:\\s"); // From ParseUtil + for (String line : lines) { + String[] splitLine = whitespaceColonWhitespace.split(line); + if ("model name".equals(splitLine[0]) || "Processor".equals(splitLine[0])) { + return splitLine[1]; + } + } + return "unknown"; + } + + /** + * https://stackoverflow.com/a/6327663 + */ + private static String getWindowsProcessorName() throws Exception { + final String cpuNameCmd = "reg query \"HKLM\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\" /v ProcessorNameString"; + final String regstrToken = "REG_SZ"; + + Process process = Runtime.getRuntime().exec(cpuNameCmd); + process.waitFor(); + InputStream is = process.getInputStream(); + + StringBuilder sb = new StringBuilder(); + while (is.available() != 0) { + sb.append((char) is.read()); + } + + String result = sb.toString(); + int p = result.indexOf(regstrToken); + + if (p == -1) { + return null; + } + + return result.substring(p + regstrToken.length()).trim(); + } + + private CpuUtils() { + } +} diff --git a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java index b405914ed..fbc891131 100644 --- a/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/DimensionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,13 +26,10 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.entity.Effect; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.packet.ChangeDimensionPacket; import com.nukkitx.protocol.bedrock.packet.MobEffectPacket; import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; -import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.session.GeyserSession; @@ -109,7 +106,7 @@ public class DimensionUtils { // we check if the player is entering the nether and apply the nether fog to fake the fact that the client // thinks they are in the end dimension. if (BEDROCK_NETHER_ID == 2) { - if (bedrockDimension == BEDROCK_NETHER_ID) { + if (NETHER.equals(javaDimension)) { session.sendFog("minecraft:fog_hell"); } else if (previousDimension == BEDROCK_NETHER_ID) { session.removeFog("minecraft:fog_hell"); @@ -131,25 +128,6 @@ public class DimensionUtils { }; } - /** - * Determines the new dimension based on the {@link CompoundTag} sent by either the {@link com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundLoginPacket} - * or {@link com.github.steveice10.mc.protocol.packet.ingame.clientbound.ClientboundRespawnPacket}. - * - * @param dimensionTag the packet's dimension tag. - * @return the dimension identifier. - */ - public static String getNewDimension(CompoundTag dimensionTag) { - if (dimensionTag == null || dimensionTag.isEmpty()) { - GeyserImpl.getInstance().getLogger().debug("Dimension tag was null or empty."); - return OVERWORLD; - } - if (dimensionTag.getValue().get("effects") != null) { - return ((StringTag) dimensionTag.getValue().get("effects")).getValue(); - } - GeyserImpl.getInstance().getLogger().debug("Effects portion of the tag was null or empty."); - return OVERWORLD; - } - /** * The Nether dimension in Bedrock does not permit building above Y128 - the Bedrock above the dimension. * This workaround sets the Nether as the End dimension to ignore this limit. diff --git a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java index 4bcbf6e68..43ccff5e0 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,17 +26,26 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.entity.Effect; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.entity.EntityData; import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.entity.type.BoatEntity; +import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.living.ArmorStandEntity; import org.geysermc.geyser.entity.type.living.animal.AnimalEntity; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.session.GeyserSession; import java.util.Locale; public final class EntityUtils { + /** + * A constant array of the two hands that a player can interact with an entity. + */ + public static final Hand[] HANDS = Hand.values(); /** * @return a new String array of all known effect identifiers @@ -64,6 +73,7 @@ public final class EntityUtils { case SLOW_FALLING -> 27; case BAD_OMEN -> 28; case HERO_OF_THE_VILLAGE -> 29; + case DARKNESS -> 30; default -> effect.ordinal() + 1; }; } @@ -74,10 +84,10 @@ public final class EntityUtils { switch (mount.getDefinition().entityType()) { case CHICKEN, SPIDER -> mountedHeightOffset = height * 0.5f; case DONKEY, MULE -> mountedHeightOffset -= 0.25f; - case LLAMA -> mountedHeightOffset = height * 0.67f; + case TRADER_LLAMA, LLAMA -> mountedHeightOffset = height * 0.6f; case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, COMMAND_BLOCK_MINECART -> mountedHeightOffset = 0; - case BOAT -> mountedHeightOffset = -0.1f; + case BOAT, CHEST_BOAT -> mountedHeightOffset = -0.1f; case HOGLIN, ZOGLIN -> { boolean isBaby = mount.getFlag(EntityFlag.BABY); mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f); @@ -144,20 +154,23 @@ public final class EntityUtils { float yOffset = mountedHeightOffset + heightOffset; float zOffset = 0; switch (mount.getDefinition().entityType()) { - case BOAT: + case BOAT -> { // Without the X offset, more than one entity on a boat is stacked on top of each other if (rider && moreThanOneEntity) { xOffset = 0.2f; } else if (moreThanOneEntity) { xOffset = -0.6f; } - break; - case CHICKEN: - zOffset = -0.1f; - break; - case LLAMA: - zOffset = -0.3f; - break; + } + case CHEST_BOAT -> xOffset = 0.15F; + case CHICKEN -> zOffset = -0.1f; + case TRADER_LLAMA, LLAMA -> zOffset = -0.3f; + } + if (passenger.getDefinition().entityType() == EntityType.SHULKER) { + switch (mount.getDefinition().entityType()) { + case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, + COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset = 0.1875f; + } } /* * Bedrock Differences @@ -165,17 +178,53 @@ public final class EntityUtils { * Horses are tinier * Players, Minecarts, and Boats have different origins */ - if (passenger.getDefinition().entityType() == EntityType.PLAYER && mount.getDefinition().entityType() != EntityType.PLAYER) { - yOffset += EntityDefinitions.PLAYER.offset(); + if (passenger.getDefinition().entityType() == EntityType.PLAYER) { + if (mount.getDefinition().entityType() != EntityType.PLAYER && mount.getDefinition().entityType() != EntityType.AREA_EFFECT_CLOUD) { + yOffset += EntityDefinitions.PLAYER.offset(); + } } switch (mount.getDefinition().entityType()) { case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, - COMMAND_BLOCK_MINECART, BOAT -> yOffset -= mount.getDefinition().height() * 0.5f; + COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset -= mount.getDefinition().height() * 0.5f; } Vector3f offset = Vector3f.from(xOffset, yOffset, zOffset); passenger.setRiderSeatPosition(offset); } - passenger.updateBedrockMetadata(); + } + + public static void updateRiderRotationLock(Entity passenger, Entity mount, boolean isRiding) { + if (isRiding && mount instanceof BoatEntity) { + // Head rotation is locked while riding in a boat + passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 1); + passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 90f); + passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 1f); + passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, -90f); + } else { + passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0); + passenger.getDirtyMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f); + passenger.getDirtyMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f); + passenger.getDirtyMetadata().put(EntityData.RIDER_ROTATION_OFFSET, 0f); + } + } + + /** + * Determine if an action would result in a successful bucketing of the given entity. + */ + public static boolean attemptToBucket(GeyserSession session, GeyserItemStack itemInHand) { + return itemInHand.getJavaId() == session.getItemMappings().getStoredItems().waterBucket(); + } + + /** + * Attempt to determine the result of saddling the given entity. + */ + public static InteractionResult attemptToSaddle(GeyserSession session, Entity entityToSaddle, GeyserItemStack itemInHand) { + if (itemInHand.getJavaId() == session.getItemMappings().getStoredItems().saddle()) { + if (!entityToSaddle.getFlag(EntityFlag.SADDLED) && !entityToSaddle.getFlag(EntityFlag.BABY)) { + // Saddle + return InteractionResult.SUCCESS; + } + } + return InteractionResult.PASS; } private EntityUtils() { diff --git a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java index 691ebff44..6df9c2177 100644 --- a/core/src/main/java/org/geysermc/geyser/util/FileUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/FileUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -169,8 +169,8 @@ public class FileUtils { * @return The byte array of the file */ public static byte[] readAllBytes(File file) { - try (InputStream inputStream = new FileInputStream(file)) { - return readAllBytes(inputStream); + try (InputStream stream = new FileInputStream(file)) { + return stream.readAllBytes(); } catch (IOException e) { throw new RuntimeException("Cannot read " + file); } @@ -182,30 +182,12 @@ public class FileUtils { */ public static byte[] readAllBytes(String resource) { try (InputStream stream = GeyserImpl.getInstance().getBootstrap().getResource(resource)) { - return readAllBytes(stream); + return stream.readAllBytes(); } catch (IOException e) { throw new RuntimeException("Error while trying to read internal input stream!", e); } } - /** - * @param stream the InputStream to read off of - * @return the byte array of an InputStream - */ - public static byte[] readAllBytes(InputStream stream) { - try { - int size = stream.available(); - byte[] bytes = new byte[size]; - try (BufferedInputStream buf = new BufferedInputStream(stream)) { - //noinspection ResultOfMethodCallIgnored - buf.read(bytes, 0, bytes.length); - } - return bytes; - } catch (IOException e) { - throw new RuntimeException("Error while trying to read input stream!", e); - } - } - /** * Read the lines of a file and return it as a stream * diff --git a/core/src/main/java/org/geysermc/geyser/util/InteractionResult.java b/core/src/main/java/org/geysermc/geyser/util/InteractionResult.java new file mode 100644 index 000000000..fd13dd743 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/InteractionResult.java @@ -0,0 +1,55 @@ +/* + * 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.util; + +/** + * Used as a mirror of Java Edition's own interaction enum. + */ +public enum InteractionResult { + CONSUME(true), + /** + * Indicates that the action does nothing, or in rare cases is not a priority. + */ + PASS(false), + /** + * Indicates that the action does something, and don't try to find another action to process. + */ + SUCCESS(true); + + private final boolean consumesAction; + + InteractionResult(boolean consumesAction) { + this.consumesAction = consumesAction; + } + + public boolean consumesAction() { + return consumesAction; + } + + public boolean shouldSwing() { + return this == SUCCESS; + } +} diff --git a/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java b/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java new file mode 100644 index 000000000..9607ac61e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/InteractiveTag.java @@ -0,0 +1,92 @@ +/* + * 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.util; + +import lombok.Getter; + +import java.util.Locale; + +/** + * All interactive tags in enum form. For potential API usage. + */ +public enum InteractiveTag { + NONE((Void) null), + IGNITE_CREEPER("creeper"), + EDIT, + LEAVE_BOAT("exit.boat"), + FEED, + FISH("fishing"), + MILK, + MOOSHROOM_SHEAR("mooshear"), + MOOSHROOM_MILK_STEW("moostew"), + BOARD_BOAT("ride.boat"), + RIDE_MINECART("ride.minecart"), + RIDE_HORSE("ride.horse"), + RIDE_STRIDER("ride.strider"), + SHEAR, + SIT, + STAND, + TALK, + TAME, + DYE, + CURE, + OPEN_CONTAINER("opencontainer"), + CREATE_MAP("createMap"), + TAKE_PICTURE("takepicture"), + SADDLE, + MOUNT, + BOOST, + WRITE, + LEASH, + REMOVE_LEASH("unleash"), + NAME, + ATTACH_CHEST("attachchest"), + TRADE, + POSE_ARMOR_STAND("armorstand.pose"), + EQUIP_ARMOR_STAND("armorstand.equip"), + READ, + WAKE_VILLAGER("wakevillager"), + BARTER, + GIVE_ITEM_TO_ALLAY("allay"); + + /** + * The full string that should be passed on to the client. + */ + @Getter + private final String value; + + InteractiveTag(Void isNone) { + this.value = ""; + } + + InteractiveTag(String value) { + this.value = "action.interact." + value; + } + + InteractiveTag() { + this.value = "action.interact." + name().toLowerCase(Locale.ROOT); + } +} 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 6ab25a177..5c2905d93 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,6 +27,7 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; +import com.github.steveice10.mc.protocol.data.game.recipe.Ingredient; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundPickItemPacket; import com.github.steveice10.mc.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; @@ -41,15 +42,21 @@ import org.geysermc.geyser.inventory.Container; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.Inventory; import org.geysermc.geyser.inventory.PlayerInventory; +import org.geysermc.geyser.inventory.click.Click; +import org.geysermc.geyser.inventory.recipe.GeyserRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; +import org.geysermc.geyser.inventory.recipe.GeyserShapelessRecipe; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.inventory.InventoryTranslator; import org.geysermc.geyser.translator.inventory.LecternInventoryTranslator; import org.geysermc.geyser.translator.inventory.chest.DoubleChestInventoryTranslator; -import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.ItemMapping; +import javax.annotation.Nullable; +import java.util.Arrays; import java.util.Collections; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -155,6 +162,13 @@ public class InventoryUtils { return item1.equals(item2, false, true, true); } + /** + * Checks to see if an item stack represents air or has no count. + */ + public static boolean isEmpty(@Nullable ItemStack itemStack) { + return itemStack == null || itemStack.getId() == ItemMapping.AIR.getJavaId() || itemStack.getAmount() <= 0; + } + /** * Returns a barrier block with custom name and lore to explain why * part of the inventory is unusable. @@ -330,4 +344,130 @@ public class InventoryUtils { session.sendUpstreamPacket(hotbarPacket); // No need to send a Java packet as Bedrock sends a confirmation packet back that we translate } + + @Nullable + public static Click getClickForHotbarSwap(int slot) { + return switch (slot) { + case 0 -> Click.SWAP_TO_HOTBAR_1; + case 1 -> Click.SWAP_TO_HOTBAR_2; + case 2 -> Click.SWAP_TO_HOTBAR_3; + case 3 -> Click.SWAP_TO_HOTBAR_4; + case 4 -> Click.SWAP_TO_HOTBAR_5; + case 5 -> Click.SWAP_TO_HOTBAR_6; + case 6 -> Click.SWAP_TO_HOTBAR_7; + case 7 -> Click.SWAP_TO_HOTBAR_8; + case 8 -> Click.SWAP_TO_HOTBAR_9; + default -> null; + }; + } + + /** + * Test all known recipes to find a valid match + * + * @param output if not null, the recipe has to output this item + */ + @Nullable + public static GeyserRecipe getValidRecipe(final GeyserSession session, final @Nullable ItemStack output, final IntFunction inventoryGetter, + final int gridDimensions, final int firstRow, final int height, final int firstCol, final int width) { + int nonAirCount = 0; // Used for shapeless recipes for amount of items needed in recipe + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + if (!inventoryGetter.apply(col + (row * gridDimensions) + 1).isEmpty()) { + nonAirCount++; + } + } + } + + recipes: + for (GeyserRecipe recipe : session.getCraftingRecipes().values()) { + if (recipe.isShaped()) { + GeyserShapedRecipe shapedRecipe = (GeyserShapedRecipe) recipe; + if (output != null && !shapedRecipe.result().equals(output)) { + continue; + } + Ingredient[] ingredients = shapedRecipe.ingredients(); + if (shapedRecipe.width() != width || shapedRecipe.height() != height || width * height != ingredients.length) { + continue; + } + + if (!testShapedRecipe(ingredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { + Ingredient[] mirroredIngredients = new Ingredient[ingredients.length]; + for (int row = 0; row < height; row++) { + for (int col = 0; col < width; col++) { + mirroredIngredients[col + (row * width)] = ingredients[(width - 1 - col) + (row * width)]; + } + } + + if (Arrays.equals(ingredients, mirroredIngredients) || + !testShapedRecipe(mirroredIngredients, inventoryGetter, gridDimensions, firstRow, height, firstCol, width)) { + continue; + } + } + } else { + GeyserShapelessRecipe data = (GeyserShapelessRecipe) recipe; + if (output != null && !data.result().equals(output)) { + continue; + } + if (nonAirCount != data.ingredients().length) { + // There is an amount of items on the crafting table that is not the same as the ingredient count so this is invalid + continue; + } + for (int i = 0; i < data.ingredients().length; i++) { + Ingredient ingredient = data.ingredients()[i]; + for (ItemStack itemStack : ingredient.getOptions()) { + boolean inventoryHasItem = false; + // Iterate only over the crafting table to find this item + crafting: + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); + if (geyserItemStack.isEmpty()) { + inventoryHasItem = itemStack == null || itemStack.getId() == 0; + if (inventoryHasItem) { + break crafting; + } + } else if (itemStack.equals(geyserItemStack.getItemStack(1))) { + inventoryHasItem = true; + break crafting; + } + } + } + if (!inventoryHasItem) { + continue recipes; + } + } + } + } + return recipe; + } + return null; + } + + private static boolean testShapedRecipe(final Ingredient[] ingredients, final IntFunction inventoryGetter, + final int gridDimensions, final int firstRow, final int height, final int firstCol, final int width) { + int ingredientIndex = 0; + for (int row = firstRow; row < height + firstRow; row++) { + for (int col = firstCol; col < width + firstCol; col++) { + GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); + Ingredient ingredient = ingredients[ingredientIndex++]; + if (ingredient.getOptions().length == 0) { + if (!geyserItemStack.isEmpty()) { + return false; + } + } else { + boolean inventoryHasItem = false; + for (ItemStack item : ingredient.getOptions()) { + if (Objects.equals(geyserItemStack.getItemStack(1), item)) { + inventoryHasItem = true; + break; + } + } + if (!inventoryHasItem) { + return false; + } + } + } + } + return true; + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java index 0eed01613..37c4609fe 100644 --- a/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/ItemUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,22 +26,30 @@ package org.geysermc.geyser.util; import com.github.steveice10.opennbt.tag.builtin.*; +import it.unimi.dsi.fastutil.ints.Int2IntMap; import org.geysermc.geyser.session.GeyserSession; -public class ItemUtils { +import javax.annotation.Nullable; - public static int getEnchantmentLevel(CompoundTag itemNBTData, String enchantmentId) { - ListTag enchantments = (itemNBTData == null ? null : itemNBTData.get("Enchantments")); +public class ItemUtils { + private static Int2IntMap DYE_COLORS = null; + + public static int getEnchantmentLevel(@Nullable CompoundTag itemNBTData, String enchantmentId) { + if (itemNBTData == null) { + return 0; + } + ListTag enchantments = itemNBTData.get("Enchantments"); if (enchantments != null) { - int enchantmentLevel = 0; for (Tag tag : enchantments) { CompoundTag enchantment = (CompoundTag) tag; StringTag enchantId = enchantment.get("id"); if (enchantId.getValue().equals(enchantmentId)) { - enchantmentLevel = (int) ((ShortTag) enchantment.get("lvl")).getValue(); + Tag lvl = enchantment.get("lvl"); + if (lvl != null && lvl.getValue() instanceof Number number) { + return number.intValue(); + } } } - return enchantmentLevel; } return 0; } @@ -73,4 +81,19 @@ public class ItemUtils { } return null; } + + /** + * Return the dye color associated with this Java item ID, if any. Returns -1 if no dye color exists for this item. + */ + public static int dyeColorFor(int javaId) { + return DYE_COLORS.get(javaId); + } + + public static void setDyeColors(Int2IntMap dyeColors) { + if (DYE_COLORS != null) { + throw new RuntimeException(); + } + dyeColors.defaultReturnValue(-1); + DYE_COLORS = dyeColors; + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java b/core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java new file mode 100644 index 000000000..45be5bf99 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/util/JavaCodecEntry.java @@ -0,0 +1,61 @@ +/* + * 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.util; + +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 javax.annotation.Nonnull; +import java.util.Iterator; + +public record JavaCodecEntry() { + + /** + * Iterate over a Java Edition codec and return each entry as a CompoundTag + */ + public static Iterable iterateAsTag(CompoundTag tag) { + ListTag value = tag.get("value"); + Iterator originalIterator = value.iterator(); + return new Iterable<>() { + @Nonnull + @Override + public Iterator iterator() { + return new Iterator<>() { + @Override + public boolean hasNext() { + return originalIterator.hasNext(); + } + + @Override + public CompoundTag next() { + return (CompoundTag) originalIterator.next(); + } + }; + } + }; + } +} 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 e677798cd..ea1ff770a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/LoginEncryptionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -37,17 +37,18 @@ import com.nukkitx.network.util.Preconditions; import com.nukkitx.protocol.bedrock.packet.LoginPacket; import com.nukkitx.protocol.bedrock.packet.ServerToClientHandshakePacket; import com.nukkitx.protocol.bedrock.util.EncryptionUtils; +import org.geysermc.cumulus.form.CustomForm; +import org.geysermc.cumulus.form.ModalForm; +import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.response.SimpleFormResponse; +import org.geysermc.cumulus.response.result.FormResponseResult; +import org.geysermc.cumulus.response.result.ValidFormResponseResult; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.auth.AuthData; import org.geysermc.geyser.session.auth.BedrockClientData; -import org.geysermc.cumulus.CustomForm; -import org.geysermc.cumulus.ModalForm; -import org.geysermc.cumulus.SimpleForm; -import org.geysermc.cumulus.response.CustomFormResponse; -import org.geysermc.cumulus.response.ModalFormResponse; -import org.geysermc.cumulus.response.SimpleFormResponse; +import org.geysermc.geyser.text.ChatColor; import org.geysermc.geyser.text.GeyserLocale; import javax.crypto.SecretKey; @@ -60,6 +61,7 @@ import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; import java.util.Iterator; import java.util.UUID; +import java.util.function.BiConsumer; public class LoginEncryptionUtils { private static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); @@ -154,10 +156,11 @@ public class LoginEncryptionUtils { session.setAuthenticationData(new AuthData( extraData.get("displayName").asText(), UUID.fromString(extraData.get("identity").asText()), - extraData.get("XUID").asText(), - certChainData, clientData + extraData.get("XUID").asText() )); + session.setCertChainData(certChainData); + if (payload.get("identityPublicKey").getNodeType() != JsonNodeType.STRING) { throw new RuntimeException("Identity Public Key was not found!"); } @@ -168,6 +171,7 @@ public class LoginEncryptionUtils { JsonNode clientDataJson = JSON_MAPPER.readTree(clientJwt.getPayload().toBytes()); BedrockClientData data = JSON_MAPPER.convertValue(clientDataJson, BedrockClientData.class); + data.setOriginalString(clientData); session.setClientData(data); if (EncryptionUtils.canUseEncryption()) { @@ -232,28 +236,22 @@ public class LoginEncryptionUtils { .optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled) .button("geyser.auth.login.form.notice.btn_login.microsoft") .button("geyser.auth.login.form.notice.btn_disconnect") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowLoginWindow(session); - return; - } - - if (isPasswordAuthEnabled && response.getClickedButtonId() == 0) { + .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) + .validResultHandler((response) -> { + if (response.clickedButtonId() == 0) { session.setMicrosoftAccount(false); buildAndShowLoginDetailsWindow(session); return; } - if (isPasswordAuthEnabled && response.getClickedButtonId() == 1) { - session.setMicrosoftAccount(true); - buildAndShowMicrosoftAuthenticationWindow(session); - return; - } - - if (response.getClickedButtonId() == 0) { - // Just show the OAuth code - session.authenticateWithMicrosoftCode(); + if (response.clickedButtonId() == 1) { + if (isPasswordAuthEnabled) { + session.setMicrosoftAccount(true); + buildAndShowMicrosoftAuthenticationWindow(session); + } else { + // Just show the OAuth code + session.authenticateWithMicrosoftCode(); + } return; } @@ -261,6 +259,49 @@ public class LoginEncryptionUtils { })); } + /** + * Build a window that explains the user's credentials will be saved to the system. + */ + public static void buildAndShowConsentWindow(GeyserSession session) { + session.sendForm( + SimpleForm.builder() + .translator(LoginEncryptionUtils::translate, session.getLocale()) + .title("%gui.signIn") + .content(""" + geyser.auth.login.save_token.warning + + geyser.auth.login.save_token.proceed""") + .button("%gui.ok") + .button("%gui.decline") + .resultHandler(authenticateOrKickHandler(session)) + ); + } + + public static void buildAndShowTokenExpiredWindow(GeyserSession session) { + session.sendForm( + SimpleForm.builder() + .translator(LoginEncryptionUtils::translate, session.getLocale()) + .title("geyser.auth.login.form.expired") + .content(""" + geyser.auth.login.save_token.expired + + geyser.auth.login.save_token.proceed""") + .button("%gui.ok") + .resultHandler(authenticateOrKickHandler(session)) + ); + } + + private static BiConsumer> authenticateOrKickHandler(GeyserSession session) { + return (form, genericResult) -> { + if (genericResult instanceof ValidFormResponseResult result && + result.response().clickedButtonId() == 0) { + session.authenticateWithMicrosoftCode(true); + } else { + session.disconnect("%disconnect.quitting"); + } + }; + } + public static void buildAndShowLoginDetailsWindow(GeyserSession session) { session.sendForm( CustomForm.builder() @@ -269,15 +310,8 @@ public class LoginEncryptionUtils { .label("geyser.auth.login.form.details.desc") .input("geyser.auth.login.form.details.email", "account@geysermc.org", "") .input("geyser.auth.login.form.details.pass", "123456", "") - .responseHandler((form, responseData) -> { - CustomFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowLoginDetailsWindow(session); - return; - } - - session.authenticate(response.next(), response.next()); - })); + .closedOrInvalidResultHandler(() -> buildAndShowLoginDetailsWindow(session)) + .validResultHandler((response) -> session.authenticate(response.next(), response.next()))); } /** @@ -291,16 +325,11 @@ public class LoginEncryptionUtils { .button("geyser.auth.login.method.browser") .button("geyser.auth.login.method.password") .button("geyser.auth.login.form.notice.btn_disconnect") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowLoginWindow(session); - return; - } - - if (response.getClickedButtonId() == 0) { + .closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session)) + .validResultHandler((response) -> { + if (response.clickedButtonId() == 0) { session.authenticateWithMicrosoftCode(); - } else if (response.getClickedButtonId() == 1) { + } else if (response.clickedButtonId() == 1) { buildAndShowLoginDetailsWindow(session); } else { session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); @@ -312,23 +341,58 @@ public class LoginEncryptionUtils { * Shows the code that a user must input into their browser */ public static void buildAndShowMicrosoftCodeWindow(GeyserSession session, MsaAuthenticationService.MsCodeResponse msCode) { + StringBuilder message = new StringBuilder("%xbox.signin.website\n") + .append(ChatColor.AQUA) + .append("%xbox.signin.url") + .append(ChatColor.RESET) + .append("\n%xbox.signin.enterCode\n") + .append(ChatColor.GREEN) + .append(msCode.user_code); + int timeout = session.getGeyser().getConfig().getPendingAuthenticationTimeout(); + if (timeout != 0) { + message.append("\n\n") + .append(ChatColor.RESET) + .append(GeyserLocale.getPlayerLocaleString("geyser.auth.login.timeout", session.getLocale(), String.valueOf(timeout))); + } + session.sendForm( ModalForm.builder() .title("%xbox.signin") - .content("%xbox.signin.website\n%xbox.signin.url\n%xbox.signin.enterCode\n" + msCode.user_code) + .content(message.toString()) .button1("%gui.done") .button2("%menu.disconnect") - .responseHandler((form, responseData) -> { - ModalFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - buildAndShowMicrosoftAuthenticationWindow(session); - return; - } - - if (response.getClickedButtonId() == 1) { + .closedOrInvalidResultHandler(() -> buildAndShowMicrosoftAuthenticationWindow(session)) + .validResultHandler((response) -> { + if (response.clickedButtonId() == 1) { session.disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); } }) ); } + + /* + This checks per line if there is something to be translated, and it skips Bedrock translation keys (%) + */ + private static String translate(String key, String locale) { + StringBuilder newValue = new StringBuilder(); + int previousIndex = 0; + while (previousIndex < key.length()) { + int nextIndex = key.indexOf('\n', previousIndex); + int endIndex = nextIndex == -1 ? key.length() : nextIndex; + + // if there is more to this line than just a new line char + if (endIndex - previousIndex > 1) { + String substring = key.substring(previousIndex, endIndex); + if (key.charAt(previousIndex) != '%') { + newValue.append(GeyserLocale.getPlayerLocaleString(substring, locale)); + } else { + newValue.append(substring); + } + } + newValue.append('\n'); + + previousIndex = endIndex + 1; + } + return newValue.toString(); + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/MathUtils.java b/core/src/main/java/org/geysermc/geyser/util/MathUtils.java index 7619c7906..f1e262bc6 100644 --- a/core/src/main/java/org/geysermc/geyser/util/MathUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/MathUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,9 +26,26 @@ package org.geysermc.geyser.util; public class MathUtils { - public static final double SQRT_OF_TWO = Math.sqrt(2); + public static float wrapDegrees(float degrees) { + degrees = degrees % 360.0f; + if (degrees < -180.0f) { + degrees += 360.0f; + } else if (degrees >= 180.0f) { + degrees -= 360.0f; + } + return degrees; + } + + public static float wrapDegrees(double degrees) { + return wrapDegrees((float) degrees); + } + + public static int wrapDegreesToInt(float degrees) { + return (int) wrapDegrees(degrees); + } + /** * Round the given float to the next whole number * @@ -84,6 +101,25 @@ public class MathUtils { return num; } + /** + * Clamps the value between the low and high boundaries + * Copied from {@link com.nukkitx.math.GenericMath} with floats instead. + * + * @param value The value to clamp + * @param low The low bound of the clamp + * @param high The high bound of the clamp + * @return the clamped value + */ + public static float clamp(float value, float low, float high) { + if (value < low) { + return low; + } + if (value > high) { + return high; + } + return value; + } + /** * Ensures the resulting object is a byte. Java Edition does not care whether a byte is encoded as an integer or not; * it converts it into a byte anyway. diff --git a/core/src/main/java/org/geysermc/geyser/util/Metrics.java b/core/src/main/java/org/geysermc/geyser/util/Metrics.java index 37d3f81eb..e88d5a971 100644 --- a/core/src/main/java/org/geysermc/geyser/util/Metrics.java +++ b/core/src/main/java/org/geysermc/geyser/util/Metrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/NewsHandler.java b/core/src/main/java/org/geysermc/geyser/util/NewsHandler.java index df163f5b1..31e3116d5 100644 --- a/core/src/main/java/org/geysermc/geyser/util/NewsHandler.java +++ b/core/src/main/java/org/geysermc/geyser/util/NewsHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java b/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java index 75355c203..032dd2af7 100644 --- a/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/PluginMessageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -33,9 +33,7 @@ import org.geysermc.geyser.session.GeyserSession; import java.nio.ByteBuffer; public class PluginMessageUtils { - private static final String SKIN_CHANNEL = "floodgate:skin"; private static final byte[] GEYSER_BRAND_DATA; - private static final byte[] FLOODGATE_REGISTER_DATA; static { byte[] data = GeyserImpl.NAME.getBytes(Charsets.UTF_8); @@ -44,8 +42,6 @@ public class PluginMessageUtils { .put(writeVarInt(data.length)) .put(data) .array(); - - FLOODGATE_REGISTER_DATA = (SKIN_CHANNEL + "\0floodgate:form\0floodgate:transfer\0floodgate:packet").getBytes(Charsets.UTF_8); } /** @@ -57,22 +53,6 @@ public class PluginMessageUtils { return GEYSER_BRAND_DATA; } - /** - * Get the prebuilt register data as a byte array - * - * @return the register data of the Floodgate channels - */ - public static byte[] getFloodgateRegisterData() { - return FLOODGATE_REGISTER_DATA; - } - - /** - * Returns the skin channel used in Floodgate - */ - public static String getSkinChannel() { - return SKIN_CHANNEL; - } - public static void sendMessage(GeyserSession session, String channel, byte[] data) { session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, data)); } diff --git a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java index 28fb53ab1..10c4b863c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SettingsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -27,13 +27,12 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; +import org.geysermc.cumulus.component.DropdownComponent; +import org.geysermc.cumulus.form.CustomForm; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.level.GameRule; -import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.level.WorldManager; -import org.geysermc.cumulus.CustomForm; -import org.geysermc.cumulus.component.DropdownComponent; -import org.geysermc.cumulus.response.CustomFormResponse; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -62,7 +61,7 @@ public class SettingsUtils { // Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config. if (session.getPreferencesCache().isAllowShowCoordinates()) { - builder.toggle("geyser.settings.option.coordinates", session.getPreferencesCache().isPrefersShowCoordinates()); + builder.toggle("%createWorldScreen.showCoordinates", session.getPreferencesCache().isPrefersShowCoordinates()); } if (CooldownUtils.getDefaultShowCooldown() != CooldownUtils.CooldownType.DISABLED) { @@ -115,12 +114,7 @@ public class SettingsUtils { } } - builder.responseHandler((form, responseData) -> { - CustomFormResponse response = form.parseResponse(responseData); - if (response.isClosed() || response.isInvalid()) { - return; - } - + builder.validResultHandler((response) -> { if (showClientSettings) { // Client can only see its coordinates if reducedDebugInfo is disabled and coordinates are enabled in geyser config. if (session.getPreferencesCache().isAllowShowCoordinates()) { @@ -175,6 +169,10 @@ public class SettingsUtils { } private static String translateEntry(String key, String locale) { + if (key.startsWith("%")) { + // Bedrock will translate + return key; + } if (key.startsWith("geyser.")) { return GeyserLocale.getPlayerLocaleString(key, locale); } diff --git a/core/src/main/java/org/geysermc/geyser/util/SignUtils.java b/core/src/main/java/org/geysermc/geyser/util/SignUtils.java index 3d3c23f7d..82030b8f5 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SignUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SignUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java index 6c4697a8b..15348939c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -25,9 +25,25 @@ package org.geysermc.geyser.util; +import com.github.steveice10.mc.protocol.data.game.level.sound.BuiltinSound; +import com.github.steveice10.mc.protocol.data.game.level.sound.CustomSound; +import com.github.steveice10.mc.protocol.data.game.level.sound.Sound; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; +import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; +import org.geysermc.geyser.GeyserImpl; +import org.geysermc.geyser.level.block.BlockStateValues; +import org.geysermc.geyser.registry.BlockRegistries; +import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.session.GeyserSession; -public class SoundUtils { +import java.util.Locale; + +public final class SoundUtils { /** * Maps a sound name to a sound event, null if one @@ -36,11 +52,118 @@ public class SoundUtils { * @param sound the sound name * @return a sound event from the given sound */ - public static SoundEvent toSoundEvent(String sound) { + private static SoundEvent toSoundEvent(String sound) { try { - return SoundEvent.valueOf(sound.toUpperCase().replaceAll("\\.", "_")); + return SoundEvent.valueOf(sound.toUpperCase(Locale.ROOT).replace(".", "_")); } catch (Exception ex) { return null; } } + + /** + * Translates a Java Custom or Builtin Sound to its Bedrock equivalent + * + * @param sound the sound to translate + * @return a Bedrock sound + */ + public static String translatePlaySound(Sound sound) { + String packetSound; + if (sound instanceof BuiltinSound builtinSound) { + packetSound = builtinSound.getName(); + } else if (sound instanceof CustomSound customSound) { + packetSound = customSound.getName(); + } else { + GeyserImpl.getInstance().getLogger().debug("Unknown sound, we were unable to map this. " + sound); + return ""; + } + + // Drop the Minecraft namespace if applicable + if (packetSound.startsWith("minecraft:")) { + packetSound = packetSound.substring("minecraft:".length()); + } + + SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); + if (soundMapping == null || soundMapping.getPlaysound() == null) { + // no mapping + GeyserImpl.getInstance().getLogger().debug("[PlaySound] Defaulting to sound server gave us for " + sound); + return packetSound; + } + return soundMapping.getPlaysound(); + } + + /** + * Translates and plays a Java Builtin Sound for a Bedrock client + * + * @param session the Bedrock client session. + * @param javaSound the builtin sound to play + * @param position the position + * @param pitch the pitch + */ + public static void playBuiltinSound(GeyserSession session, BuiltinSound javaSound, Vector3f position, float volume, float pitch) { + String packetSound = javaSound.getName(); + + SoundMapping soundMapping = Registries.SOUNDS.get(packetSound); + if (soundMapping == null) { + session.getGeyser().getLogger().debug("[Builtin] Sound mapping for " + packetSound + " not found"); + return; + } + + if (soundMapping.getPlaysound() != null) { + // We always prefer the PlaySound mapping because we can control volume and pitch + PlaySoundPacket playSoundPacket = new PlaySoundPacket(); + playSoundPacket.setSound(soundMapping.getPlaysound()); + playSoundPacket.setPosition(position); + playSoundPacket.setVolume(volume); + playSoundPacket.setPitch(pitch); + session.sendUpstreamPacket(playSoundPacket); + return; + } + + if (soundMapping.isLevelEvent()) { + LevelEventPacket levelEventPacket = new LevelEventPacket(); + levelEventPacket.setPosition(position); + levelEventPacket.setData(0); + levelEventPacket.setType(LevelEventType.valueOf(soundMapping.getBedrock())); + session.sendUpstreamPacket(levelEventPacket); + return; + } + + LevelSoundEventPacket soundPacket = new LevelSoundEventPacket(); + SoundEvent sound = SoundUtils.toSoundEvent(soundMapping.getBedrock()); + if (sound == null) { + sound = SoundUtils.toSoundEvent(packetSound); + } + if (sound == null) { + session.getGeyser().getLogger().debug("[Builtin] Sound for original '" + packetSound + "' to mappings '" + soundMapping.getBedrock() + + "' was not a playable level sound, or has yet to be mapped to an enum in SoundEvent."); + return; + } + + soundPacket.setSound(sound); + soundPacket.setPosition(position); + soundPacket.setIdentifier(soundMapping.getIdentifier()); + if (sound == SoundEvent.NOTE) { + // Minecraft Wiki: 2^(x/12) = Java pitch where x is -12 to 12 + // Java sends the note value as above starting with -12 and ending at 12 + // Bedrock has a number for each type of note, then proceeds up the scale by adding to that number + soundPacket.setExtraData(soundMapping.getExtraData() + (int)(Math.round((Math.log10(pitch) / Math.log10(2)) * 12)) + 12); + } else if (sound == SoundEvent.PLACE && soundMapping.getExtraData() == -1) { + if (!soundMapping.getIdentifier().equals(":")) { + int javaId = BlockRegistries.JAVA_IDENTIFIERS.getOrDefault(soundMapping.getIdentifier(), BlockStateValues.JAVA_AIR_ID); + soundPacket.setExtraData(session.getBlockMappings().getBedrockBlockId(javaId)); + } else { + session.getGeyser().getLogger().debug("PLACE sound mapping identifier was invalid! Please report: " + soundMapping); + } + soundPacket.setIdentifier(":"); + } else { + soundPacket.setExtraData(soundMapping.getExtraData()); + } + + soundPacket.setBabySound(false); // might need to adjust this in the future + soundPacket.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundPacket); + } + + private SoundUtils() { + } } diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java b/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java index f8f12fe79..7e1f6e7b7 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticFormatters.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 6a03495db..149656fd9 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -26,12 +26,11 @@ package org.geysermc.geyser.util; import com.github.steveice10.mc.protocol.data.game.statistic.*; -import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.cumulus.form.SimpleForm; +import org.geysermc.cumulus.util.FormImage; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.type.ItemMappings; -import org.geysermc.cumulus.SimpleForm; -import org.geysermc.cumulus.response.SimpleFormResponse; -import org.geysermc.cumulus.util.FormImage; +import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; @@ -68,12 +67,7 @@ public class StatisticsUtils { .button("stat.itemsButton - stat_type.minecraft.dropped", FormImage.Type.PATH, "textures/ui/trash_default") .button("stat.mobsButton - geyser.statistics.killed", FormImage.Type.PATH, "textures/items/diamond_sword") .button("stat.mobsButton - geyser.statistics.killed_by", FormImage.Type.PATH, "textures/ui/wither_heart_flash") - .responseHandler((form, responseData) -> { - SimpleFormResponse response = form.parseResponse(responseData); - if (!response.isCorrect()) { - return; - } - + .validResultHandler((response) -> { SimpleForm.Builder builder = SimpleForm.builder() .translator(StatisticsUtils::translate, language); @@ -81,7 +75,7 @@ public class StatisticsUtils { List content = new ArrayList<>(); ItemMappings mappings = session.getItemMappings(); - switch (response.getClickedButtonId()) { + switch (response.clickedButtonId()) { case 0: builder.title("stat.generalButton"); @@ -202,12 +196,7 @@ public class StatisticsUtils { session.sendForm( builder.content(assembledContent.toString()) .button("gui.back", FormImage.Type.PATH, "textures/gui/newgui/undo") - .responseHandler((form1, subFormResponseData) -> { - SimpleFormResponse response1 = form.parseResponse(subFormResponseData); - if (response1.isCorrect()) { - buildAndSendStatisticsMenu(session); - } - })); + .validResultHandler((response1) -> buildAndSendStatisticsMenu(session))); })); } 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 786d5fc6e..934680ce1 100644 --- a/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/VersionCheckUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 a70971cb2..fe479363f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 @@ -52,6 +52,8 @@ public class WebUtils { HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); // Otherwise Java 8 fails on checking updates + con.setConnectTimeout(10000); + con.setReadTimeout(10000); return connectionToString(con); } catch (Exception e) { diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java index ba30da927..832a7bcae 100644 --- a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java +++ b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2BooleanMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java index 65deeaca6..ee37d612f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java +++ b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2ByteMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java index 9c30edd01..f5bd89d64 100644 --- a/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java +++ b/core/src/main/java/org/geysermc/geyser/util/collection/FixedInt2IntMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 aaa780ed5..73cb68df1 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 efd292a83..ceb2333bd 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java b/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java index a4c188001..e17a38877 100644 --- a/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java +++ b/core/src/main/java/org/geysermc/geyser/util/collection/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/core/src/main/resources/bedrock/biome_definitions.dat b/core/src/main/resources/bedrock/biome_definitions.dat index 8fe3b95a5..0520c61e2 100644 Binary files a/core/src/main/resources/bedrock/biome_definitions.dat and b/core/src/main/resources/bedrock/biome_definitions.dat differ diff --git a/core/src/main/resources/bedrock/block_palette.1_17_30.nbt b/core/src/main/resources/bedrock/block_palette.1_17_30.nbt deleted file mode 100644 index fde145ca5..000000000 Binary files a/core/src/main/resources/bedrock/block_palette.1_17_30.nbt and /dev/null differ diff --git a/core/src/main/resources/bedrock/block_palette.1_17_40.nbt b/core/src/main/resources/bedrock/block_palette.1_17_40.nbt deleted file mode 100644 index 0415c135a..000000000 Binary files a/core/src/main/resources/bedrock/block_palette.1_17_40.nbt and /dev/null differ diff --git a/core/src/main/resources/bedrock/block_palette.1_19_0.nbt b/core/src/main/resources/bedrock/block_palette.1_19_0.nbt new file mode 100644 index 000000000..8c095ad02 Binary files /dev/null and b/core/src/main/resources/bedrock/block_palette.1_19_0.nbt differ diff --git a/core/src/main/resources/bedrock/creative_items.1_17_30.json b/core/src/main/resources/bedrock/creative_items.1_17_30.json deleted file mode 100644 index bb73854dc..000000000 --- a/core/src/main/resources/bedrock/creative_items.1_17_30.json +++ /dev/null @@ -1,5207 +0,0 @@ -{ - "items" : [ - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5794 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5795 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5796 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5797 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5798 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5799 - }, - { - "id" : "minecraft:crimson_planks", - "blockRuntimeId" : 3839 - }, - { - "id" : "minecraft:warped_planks", - "blockRuntimeId" : 7594 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1318 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1319 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1320 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1321 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1322 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1323 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1330 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1325 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1326 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1324 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1327 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1331 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1328 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1329 - }, - { - "id" : "minecraft:blackstone_wall", - "blockRuntimeId" : 507 - }, - { - "id" : "minecraft:polished_blackstone_wall", - "blockRuntimeId" : 6038 - }, - { - "id" : "minecraft:polished_blackstone_brick_wall", - "blockRuntimeId" : 5835 - }, - { - "id" : "minecraft:cobbled_deepslate_wall", - "blockRuntimeId" : 1155 - }, - { - "id" : "minecraft:deepslate_tile_wall", - "blockRuntimeId" : 4297 - }, - { - "id" : "minecraft:polished_deepslate_wall", - "blockRuntimeId" : 6213 - }, - { - "id" : "minecraft:deepslate_brick_wall", - "blockRuntimeId" : 4114 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4773 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4774 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4775 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4776 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4777 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4778 - }, - { - "id" : "minecraft:nether_brick_fence", - "blockRuntimeId" : 5686 - }, - { - "id" : "minecraft:crimson_fence", - "blockRuntimeId" : 3817 - }, - { - "id" : "minecraft:warped_fence", - "blockRuntimeId" : 7572 - }, - { - "id" : "minecraft:fence_gate", - "blockRuntimeId" : 4779 - }, - { - "id" : "minecraft:spruce_fence_gate", - "blockRuntimeId" : 7006 - }, - { - "id" : "minecraft:birch_fence_gate", - "blockRuntimeId" : 400 - }, - { - "id" : "minecraft:jungle_fence_gate", - "blockRuntimeId" : 5252 - }, - { - "id" : "minecraft:acacia_fence_gate", - "blockRuntimeId" : 44 - }, - { - "id" : "minecraft:dark_oak_fence_gate", - "blockRuntimeId" : 3980 - }, - { - "id" : "minecraft:crimson_fence_gate", - "blockRuntimeId" : 3818 - }, - { - "id" : "minecraft:warped_fence_gate", - "blockRuntimeId" : 7573 - }, - { - "id" : "minecraft:normal_stone_stairs", - "blockRuntimeId" : 5705 - }, - { - "id" : "minecraft:stone_stairs", - "blockRuntimeId" : 7277 - }, - { - "id" : "minecraft:mossy_cobblestone_stairs", - "blockRuntimeId" : 5667 - }, - { - "id" : "minecraft:oak_stairs", - "blockRuntimeId" : 5714 - }, - { - "id" : "minecraft:spruce_stairs", - "blockRuntimeId" : 7038 - }, - { - "id" : "minecraft:birch_stairs", - "blockRuntimeId" : 432 - }, - { - "id" : "minecraft:jungle_stairs", - "blockRuntimeId" : 5284 - }, - { - "id" : "minecraft:acacia_stairs", - "blockRuntimeId" : 76 - }, - { - "id" : "minecraft:dark_oak_stairs", - "blockRuntimeId" : 4012 - }, - { - "id" : "minecraft:stone_brick_stairs", - "blockRuntimeId" : 7183 - }, - { - "id" : "minecraft:mossy_stone_brick_stairs", - "blockRuntimeId" : 5675 - }, - { - "id" : "minecraft:sandstone_stairs", - "blockRuntimeId" : 6707 - }, - { - "id" : "minecraft:smooth_sandstone_stairs", - "blockRuntimeId" : 6899 - }, - { - "id" : "minecraft:red_sandstone_stairs", - "blockRuntimeId" : 6634 - }, - { - "id" : "minecraft:smooth_red_sandstone_stairs", - "blockRuntimeId" : 6891 - }, - { - "id" : "minecraft:granite_stairs", - "blockRuntimeId" : 4988 - }, - { - "id" : "minecraft:polished_granite_stairs", - "blockRuntimeId" : 6383 - }, - { - "id" : "minecraft:diorite_stairs", - "blockRuntimeId" : 4475 - }, - { - "id" : "minecraft:polished_diorite_stairs", - "blockRuntimeId" : 6375 - }, - { - "id" : "minecraft:andesite_stairs", - "blockRuntimeId" : 144 - }, - { - "id" : "minecraft:polished_andesite_stairs", - "blockRuntimeId" : 5811 - }, - { - "id" : "minecraft:brick_stairs", - "blockRuntimeId" : 876 - }, - { - "id" : "minecraft:nether_brick_stairs", - "blockRuntimeId" : 5687 - }, - { - "id" : "minecraft:red_nether_brick_stairs", - "blockRuntimeId" : 6622 - }, - { - "id" : "minecraft:end_brick_stairs", - "blockRuntimeId" : 4719 - }, - { - "id" : "minecraft:quartz_stairs", - "blockRuntimeId" : 6556 - }, - { - "id" : "minecraft:smooth_quartz_stairs", - "blockRuntimeId" : 6883 - }, - { - "id" : "minecraft:purpur_stairs", - "blockRuntimeId" : 6534 - }, - { - "id" : "minecraft:prismarine_stairs", - "blockRuntimeId" : 6446 - }, - { - "id" : "minecraft:dark_prismarine_stairs", - "blockRuntimeId" : 4036 - }, - { - "id" : "minecraft:prismarine_bricks_stairs", - "blockRuntimeId" : 6438 - }, - { - "id" : "minecraft:crimson_stairs", - "blockRuntimeId" : 3859 - }, - { - "id" : "minecraft:warped_stairs", - "blockRuntimeId" : 7614 - }, - { - "id" : "minecraft:blackstone_stairs", - "blockRuntimeId" : 499 - }, - { - "id" : "minecraft:polished_blackstone_stairs", - "blockRuntimeId" : 6030 - }, - { - "id" : "minecraft:polished_blackstone_brick_stairs", - "blockRuntimeId" : 5827 - }, - { - "id" : "minecraft:cut_copper_stairs", - "blockRuntimeId" : 3912 - }, - { - "id" : "minecraft:exposed_cut_copper_stairs", - "blockRuntimeId" : 4755 - }, - { - "id" : "minecraft:weathered_cut_copper_stairs", - "blockRuntimeId" : 7741 - }, - { - "id" : "minecraft:oxidized_cut_copper_stairs", - "blockRuntimeId" : 5755 - }, - { - "id" : "minecraft:waxed_cut_copper_stairs", - "blockRuntimeId" : 7685 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_stairs", - "blockRuntimeId" : 7699 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_stairs", - "blockRuntimeId" : 7727 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_stairs", - "blockRuntimeId" : 7713 - }, - { - "id" : "minecraft:cobbled_deepslate_stairs", - "blockRuntimeId" : 1147 - }, - { - "id" : "minecraft:deepslate_tile_stairs", - "blockRuntimeId" : 4289 - }, - { - "id" : "minecraft:polished_deepslate_stairs", - "blockRuntimeId" : 6205 - }, - { - "id" : "minecraft:deepslate_brick_stairs", - "blockRuntimeId" : 4106 - }, - { - "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:iron_door" - }, - { - "id" : "minecraft:crimson_door" - }, - { - "id" : "minecraft:warped_door" - }, - { - "id" : "minecraft:trapdoor", - "blockRuntimeId" : 7359 - }, - { - "id" : "minecraft:spruce_trapdoor", - "blockRuntimeId" : 7062 - }, - { - "id" : "minecraft:birch_trapdoor", - "blockRuntimeId" : 456 - }, - { - "id" : "minecraft:jungle_trapdoor", - "blockRuntimeId" : 5308 - }, - { - "id" : "minecraft:acacia_trapdoor", - "blockRuntimeId" : 100 - }, - { - "id" : "minecraft:dark_oak_trapdoor", - "blockRuntimeId" : 4020 - }, - { - "id" : "minecraft:iron_trapdoor", - "blockRuntimeId" : 5167 - }, - { - "id" : "minecraft:crimson_trapdoor", - "blockRuntimeId" : 3886 - }, - { - "id" : "minecraft:warped_trapdoor", - "blockRuntimeId" : 7641 - }, - { - "id" : "minecraft:iron_bars", - "blockRuntimeId" : 5132 - }, - { - "id" : "minecraft:glass", - "blockRuntimeId" : 4882 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7084 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7092 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7091 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7099 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7096 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7098 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7085 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7088 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7089 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7097 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7093 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7087 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7095 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7094 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7086 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7090 - }, - { - "id" : "minecraft:tinted_glass", - "blockRuntimeId" : 7348 - }, - { - "id" : "minecraft:glass_pane", - "blockRuntimeId" : 4883 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7100 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7108 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7107 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7115 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7112 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7114 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7101 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7104 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7105 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7113 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7109 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7103 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7111 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7110 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7102 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7106 - }, - { - "id" : "minecraft:ladder", - "blockRuntimeId" : 5356 - }, - { - "id" : "minecraft:scaffolding", - "blockRuntimeId" : 6727 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7219 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7269 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7222 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7240 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7899 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7900 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7901 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7902 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7903 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7904 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7224 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7267 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7220 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7270 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7241 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7235 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7271 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7252 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7257 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7258 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7255 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7256 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7254 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7253 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7223 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7226 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7242 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7251 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7225 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7268 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7236 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7237 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7238 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7239 - }, - { - "id" : "minecraft:crimson_slab", - "blockRuntimeId" : 3857 - }, - { - "id" : "minecraft:warped_slab", - "blockRuntimeId" : 7612 - }, - { - "id" : "minecraft:blackstone_slab", - "blockRuntimeId" : 497 - }, - { - "id" : "minecraft:polished_blackstone_slab", - "blockRuntimeId" : 6028 - }, - { - "id" : "minecraft:polished_blackstone_brick_slab", - "blockRuntimeId" : 5825 - }, - { - "id" : "minecraft:cut_copper_slab", - "blockRuntimeId" : 3910 - }, - { - "id" : "minecraft:exposed_cut_copper_slab", - "blockRuntimeId" : 4753 - }, - { - "id" : "minecraft:weathered_cut_copper_slab", - "blockRuntimeId" : 7739 - }, - { - "id" : "minecraft:oxidized_cut_copper_slab", - "blockRuntimeId" : 5753 - }, - { - "id" : "minecraft:waxed_cut_copper_slab", - "blockRuntimeId" : 7683 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_slab", - "blockRuntimeId" : 7697 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_slab", - "blockRuntimeId" : 7725 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_slab", - "blockRuntimeId" : 7711 - }, - { - "id" : "minecraft:cobbled_deepslate_slab", - "blockRuntimeId" : 1145 - }, - { - "id" : "minecraft:polished_deepslate_slab", - "blockRuntimeId" : 6203 - }, - { - "id" : "minecraft:deepslate_tile_slab", - "blockRuntimeId" : 4287 - }, - { - "id" : "minecraft:deepslate_brick_slab", - "blockRuntimeId" : 4104 - }, - { - "id" : "minecraft:brick_block", - "blockRuntimeId" : 875 - }, - { - "id" : "minecraft:chiseled_nether_bricks", - "blockRuntimeId" : 1130 - }, - { - "id" : "minecraft:cracked_nether_bricks", - "blockRuntimeId" : 3768 - }, - { - "id" : "minecraft:quartz_bricks", - "blockRuntimeId" : 6554 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7285 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7286 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7287 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7288 - }, - { - "id" : "minecraft:end_bricks", - "blockRuntimeId" : 4727 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6437 - }, - { - "id" : "minecraft:polished_blackstone_bricks", - "blockRuntimeId" : 5997 - }, - { - "id" : "minecraft:cracked_polished_blackstone_bricks", - "blockRuntimeId" : 3769 - }, - { - "id" : "minecraft:gilded_blackstone", - "blockRuntimeId" : 4881 - }, - { - "id" : "minecraft:chiseled_polished_blackstone", - "blockRuntimeId" : 1131 - }, - { - "id" : "minecraft:deepslate_tiles", - "blockRuntimeId" : 4459 - }, - { - "id" : "minecraft:cracked_deepslate_tiles", - "blockRuntimeId" : 3767 - }, - { - "id" : "minecraft:deepslate_bricks", - "blockRuntimeId" : 4276 - }, - { - "id" : "minecraft:cracked_deepslate_bricks", - "blockRuntimeId" : 3766 - }, - { - "id" : "minecraft:chiseled_deepslate", - "blockRuntimeId" : 1129 - }, - { - "id" : "minecraft:cobblestone", - "blockRuntimeId" : 1317 - }, - { - "id" : "minecraft:mossy_cobblestone", - "blockRuntimeId" : 5666 - }, - { - "id" : "minecraft:cobbled_deepslate", - "blockRuntimeId" : 1142 - }, - { - "id" : "minecraft:smooth_stone", - "blockRuntimeId" : 6907 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6703 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6704 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6705 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6706 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6630 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6631 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6632 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6633 - }, - { - "id" : "minecraft:coal_block", - "blockRuntimeId" : 1140 - }, - { - "id" : "minecraft:dried_kelp_block", - "blockRuntimeId" : 4583 - }, - { - "id" : "minecraft:gold_block", - "blockRuntimeId" : 4974 - }, - { - "id" : "minecraft:iron_block", - "blockRuntimeId" : 5133 - }, - { - "id" : "minecraft:copper_block", - "blockRuntimeId" : 3676 - }, - { - "id" : "minecraft:exposed_copper", - "blockRuntimeId" : 4751 - }, - { - "id" : "minecraft:weathered_copper", - "blockRuntimeId" : 7737 - }, - { - "id" : "minecraft:oxidized_copper", - "blockRuntimeId" : 5751 - }, - { - "id" : "minecraft:waxed_copper", - "blockRuntimeId" : 7681 - }, - { - "id" : "minecraft:waxed_exposed_copper", - "blockRuntimeId" : 7695 - }, - { - "id" : "minecraft:waxed_weathered_copper", - "blockRuntimeId" : 7723 - }, - { - "id" : "minecraft:waxed_oxidized_copper", - "blockRuntimeId" : 7709 - }, - { - "id" : "minecraft:cut_copper", - "blockRuntimeId" : 3909 - }, - { - "id" : "minecraft:exposed_cut_copper", - "blockRuntimeId" : 4752 - }, - { - "id" : "minecraft:weathered_cut_copper", - "blockRuntimeId" : 7738 - }, - { - "id" : "minecraft:oxidized_cut_copper", - "blockRuntimeId" : 5752 - }, - { - "id" : "minecraft:waxed_cut_copper", - "blockRuntimeId" : 7682 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper", - "blockRuntimeId" : 7696 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper", - "blockRuntimeId" : 7724 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper", - "blockRuntimeId" : 7710 - }, - { - "id" : "minecraft:emerald_block", - "blockRuntimeId" : 4716 - }, - { - "id" : "minecraft:diamond_block", - "blockRuntimeId" : 4473 - }, - { - "id" : "minecraft:lapis_block", - "blockRuntimeId" : 5364 - }, - { - "id" : "minecraft:raw_iron_block", - "blockRuntimeId" : 6576 - }, - { - "id" : "minecraft:raw_copper_block", - "blockRuntimeId" : 6574 - }, - { - "id" : "minecraft:raw_gold_block", - "blockRuntimeId" : 6575 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6542 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6544 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6543 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6545 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6435 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6436 - }, - { - "id" : "minecraft:slime", - "blockRuntimeId" : 6860 - }, - { - "id" : "minecraft:honey_block", - "blockRuntimeId" : 5111 - }, - { - "id" : "minecraft:honeycomb_block", - "blockRuntimeId" : 5112 - }, - { - "id" : "minecraft:hay_block", - "blockRuntimeId" : 5083 - }, - { - "id" : "minecraft:bone_block", - "blockRuntimeId" : 692 - }, - { - "id" : "minecraft:nether_brick", - "blockRuntimeId" : 5685 - }, - { - "id" : "minecraft:red_nether_brick", - "blockRuntimeId" : 6621 - }, - { - "id" : "minecraft:netherite_block", - "blockRuntimeId" : 5702 - }, - { - "id" : "minecraft:lodestone", - "blockRuntimeId" : 5562 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7911 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7919 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7918 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7926 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7923 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7925 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7912 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7915 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7916 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7924 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7920 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7914 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7922 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7921 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7913 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7917 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 963 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 971 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 970 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 978 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 975 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 977 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 964 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 967 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 968 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 976 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 972 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 966 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 974 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 973 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 965 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 969 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3659 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3667 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3666 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3674 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3671 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3673 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3660 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3663 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3664 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3672 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3668 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3662 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3670 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3669 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3661 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3665 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3643 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3651 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3650 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3658 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3655 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3657 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3644 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3647 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3648 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3656 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3652 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3646 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3654 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3653 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3645 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3649 - }, - { - "id" : "minecraft:clay", - "blockRuntimeId" : 1139 - }, - { - "id" : "minecraft:hardened_clay", - "blockRuntimeId" : 5082 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7116 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7124 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7123 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7131 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7128 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7130 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7117 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7120 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7121 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7129 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7125 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7119 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7127 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7126 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7118 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7122 - }, - { - "id" : "minecraft:white_glazed_terracotta", - "blockRuntimeId" : 7796 - }, - { - "id" : "minecraft:silver_glazed_terracotta", - "blockRuntimeId" : 6842 - }, - { - "id" : "minecraft:gray_glazed_terracotta", - "blockRuntimeId" : 5009 - }, - { - "id" : "minecraft:black_glazed_terracotta", - "blockRuntimeId" : 488 - }, - { - "id" : "minecraft:brown_glazed_terracotta", - "blockRuntimeId" : 894 - }, - { - "id" : "minecraft:red_glazed_terracotta", - "blockRuntimeId" : 6598 - }, - { - "id" : "minecraft:orange_glazed_terracotta", - "blockRuntimeId" : 5745 - }, - { - "id" : "minecraft:yellow_glazed_terracotta", - "blockRuntimeId" : 7938 - }, - { - "id" : "minecraft:lime_glazed_terracotta", - "blockRuntimeId" : 5531 - }, - { - "id" : "minecraft:green_glazed_terracotta", - "blockRuntimeId" : 5025 - }, - { - "id" : "minecraft:cyan_glazed_terracotta", - "blockRuntimeId" : 3930 - }, - { - "id" : "minecraft:light_blue_glazed_terracotta", - "blockRuntimeId" : 5483 - }, - { - "id" : "minecraft:blue_glazed_terracotta", - "blockRuntimeId" : 685 - }, - { - "id" : "minecraft:purple_glazed_terracotta", - "blockRuntimeId" : 6516 - }, - { - "id" : "minecraft:magenta_glazed_terracotta", - "blockRuntimeId" : 5595 - }, - { - "id" : "minecraft:pink_glazed_terracotta", - "blockRuntimeId" : 5776 - }, - { - "id" : "minecraft:purpur_block", - "blockRuntimeId" : 6522 - }, - { - "id" : "minecraft:purpur_block", - "blockRuntimeId" : 6524 - }, - { - "id" : "minecraft:nether_wart_block", - "blockRuntimeId" : 5701 - }, - { - "id" : "minecraft:warped_wart_block", - "blockRuntimeId" : 7663 - }, - { - "id" : "minecraft:shroomlight", - "blockRuntimeId" : 6825 - }, - { - "id" : "minecraft:crimson_nylium", - "blockRuntimeId" : 3838 - }, - { - "id" : "minecraft:warped_nylium", - "blockRuntimeId" : 7593 - }, - { - "id" : "minecraft:basalt", - "blockRuntimeId" : 214 - }, - { - "id" : "minecraft:polished_basalt", - "blockRuntimeId" : 5819 - }, - { - "id" : "minecraft:smooth_basalt", - "blockRuntimeId" : 6882 - }, - { - "id" : "minecraft:soul_soil", - "blockRuntimeId" : 6952 - }, - { - "id" : "minecraft:dirt", - "blockRuntimeId" : 4483 - }, - { - "id" : "minecraft:dirt", - "blockRuntimeId" : 4484 - }, - { - "id" : "minecraft:farmland", - "blockRuntimeId" : 4765 - }, - { - "id" : "minecraft:grass", - "blockRuntimeId" : 4996 - }, - { - "id" : "minecraft:grass_path", - "blockRuntimeId" : 4997 - }, - { - "id" : "minecraft:podzol", - "blockRuntimeId" : 5800 - }, - { - "id" : "minecraft:mycelium", - "blockRuntimeId" : 5684 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7176 - }, - { - "id" : "minecraft:iron_ore", - "blockRuntimeId" : 5166 - }, - { - "id" : "minecraft:gold_ore", - "blockRuntimeId" : 4975 - }, - { - "id" : "minecraft:diamond_ore", - "blockRuntimeId" : 4474 - }, - { - "id" : "minecraft:lapis_ore", - "blockRuntimeId" : 5365 - }, - { - "id" : "minecraft:redstone_ore", - "blockRuntimeId" : 6644 - }, - { - "id" : "minecraft:coal_ore", - "blockRuntimeId" : 1141 - }, - { - "id" : "minecraft:copper_ore", - "blockRuntimeId" : 3677 - }, - { - "id" : "minecraft:emerald_ore", - "blockRuntimeId" : 4717 - }, - { - "id" : "minecraft:quartz_ore", - "blockRuntimeId" : 6555 - }, - { - "id" : "minecraft:nether_gold_ore", - "blockRuntimeId" : 5695 - }, - { - "id" : "minecraft:ancient_debris", - "blockRuntimeId" : 143 - }, - { - "id" : "minecraft:deepslate_iron_ore", - "blockRuntimeId" : 4282 - }, - { - "id" : "minecraft:deepslate_gold_ore", - "blockRuntimeId" : 4281 - }, - { - "id" : "minecraft:deepslate_diamond_ore", - "blockRuntimeId" : 4279 - }, - { - "id" : "minecraft:deepslate_lapis_ore", - "blockRuntimeId" : 4283 - }, - { - "id" : "minecraft:deepslate_redstone_ore", - "blockRuntimeId" : 4284 - }, - { - "id" : "minecraft:deepslate_emerald_ore", - "blockRuntimeId" : 4280 - }, - { - "id" : "minecraft:deepslate_coal_ore", - "blockRuntimeId" : 4277 - }, - { - "id" : "minecraft:deepslate_copper_ore", - "blockRuntimeId" : 4278 - }, - { - "id" : "minecraft:gravel", - "blockRuntimeId" : 4998 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7177 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7179 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7181 - }, - { - "id" : "minecraft:blackstone", - "blockRuntimeId" : 494 - }, - { - "id" : "minecraft:deepslate", - "blockRuntimeId" : 4099 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7178 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7180 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7182 - }, - { - "id" : "minecraft:polished_blackstone", - "blockRuntimeId" : 5822 - }, - { - "id" : "minecraft:polished_deepslate", - "blockRuntimeId" : 6200 - }, - { - "id" : "minecraft:sand", - "blockRuntimeId" : 6701 - }, - { - "id" : "minecraft:sand", - "blockRuntimeId" : 6702 - }, - { - "id" : "minecraft:cactus", - "blockRuntimeId" : 920 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5563 - }, - { - "id" : "minecraft:stripped_oak_log", - "blockRuntimeId" : 7315 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5564 - }, - { - "id" : "minecraft:stripped_spruce_log", - "blockRuntimeId" : 7318 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5565 - }, - { - "id" : "minecraft:stripped_birch_log", - "blockRuntimeId" : 7300 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5566 - }, - { - "id" : "minecraft:stripped_jungle_log", - "blockRuntimeId" : 7312 - }, - { - "id" : "minecraft:log2", - "blockRuntimeId" : 5575 - }, - { - "id" : "minecraft:stripped_acacia_log", - "blockRuntimeId" : 7297 - }, - { - "id" : "minecraft:log2", - "blockRuntimeId" : 5576 - }, - { - "id" : "minecraft:stripped_dark_oak_log", - "blockRuntimeId" : 7309 - }, - { - "id" : "minecraft:crimson_stem", - "blockRuntimeId" : 3883 - }, - { - "id" : "minecraft:stripped_crimson_stem", - "blockRuntimeId" : 7306 - }, - { - "id" : "minecraft:warped_stem", - "blockRuntimeId" : 7638 - }, - { - "id" : "minecraft:stripped_warped_stem", - "blockRuntimeId" : 7324 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7803 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7809 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7804 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7810 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7805 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7811 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7806 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7812 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7807 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7813 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7808 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7814 - }, - { - "id" : "minecraft:crimson_hyphae", - "blockRuntimeId" : 3835 - }, - { - "id" : "minecraft:stripped_crimson_hyphae", - "blockRuntimeId" : 7303 - }, - { - "id" : "minecraft:warped_hyphae", - "blockRuntimeId" : 7590 - }, - { - "id" : "minecraft:stripped_warped_hyphae", - "blockRuntimeId" : 7321 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5409 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5410 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5411 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5412 - }, - { - "id" : "minecraft:leaves2", - "blockRuntimeId" : 5425 - }, - { - "id" : "minecraft:leaves2", - "blockRuntimeId" : 5426 - }, - { - "id" : "minecraft:azalea_leaves", - "blockRuntimeId" : 169 - }, - { - "id" : "minecraft:azalea_leaves_flowered", - "blockRuntimeId" : 173 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6715 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6716 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6717 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6718 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6719 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6720 - }, - { - "id" : "minecraft:bee_nest", - "blockRuntimeId" : 236 - }, - { - "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" : 5608 - }, - { - "id" : "minecraft:melon_slice" - }, - { - "id" : "minecraft:glistering_melon_slice" - }, - { - "id" : "minecraft:sweet_berries" - }, - { - "id" : "minecraft:glow_berries" - }, - { - "id" : "minecraft:pumpkin", - "blockRuntimeId" : 6454 - }, - { - "id" : "minecraft:carved_pumpkin", - "blockRuntimeId" : 988 - }, - { - "id" : "minecraft:lit_pumpkin", - "blockRuntimeId" : 5550 - }, - { - "id" : "minecraft:honeycomb" - }, - { - "id" : "minecraft:tallgrass", - "blockRuntimeId" : 7345 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4503 - }, - { - "id" : "minecraft:tallgrass", - "blockRuntimeId" : 7344 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4502 - }, - { - "id" : "minecraft:nether_sprouts" - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3681 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3679 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3680 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3678 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3682 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3686 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3684 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3685 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3683 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3687 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3701 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3699 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3700 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3698 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3702 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3711 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3709 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3710 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3708 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3712 - }, - { - "id" : "minecraft:kelp" - }, - { - "id" : "minecraft:seagrass", - "blockRuntimeId" : 6821 - }, - { - "id" : "minecraft:crimson_roots", - "blockRuntimeId" : 3856 - }, - { - "id" : "minecraft:warped_roots", - "blockRuntimeId" : 7611 - }, - { - "id" : "minecraft:yellow_flower", - "blockRuntimeId" : 7937 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6587 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6588 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6589 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6590 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6591 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6592 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6593 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6594 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6595 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6596 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6597 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4500 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4501 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4504 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4505 - }, - { - "id" : "minecraft:wither_rose", - "blockRuntimeId" : 7802 - }, - { - "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" : 7498 - }, - { - "id" : "minecraft:weeping_vines", - "blockRuntimeId" : 7752 - }, - { - "id" : "minecraft:twisting_vines", - "blockRuntimeId" : 7426 - }, - { - "id" : "minecraft:waterlily", - "blockRuntimeId" : 7680 - }, - { - "id" : "minecraft:deadbush", - "blockRuntimeId" : 4098 - }, - { - "id" : "minecraft:bamboo", - "blockRuntimeId" : 177 - }, - { - "id" : "minecraft:snow", - "blockRuntimeId" : 6908 - }, - { - "id" : "minecraft:ice", - "blockRuntimeId" : 5125 - }, - { - "id" : "minecraft:packed_ice", - "blockRuntimeId" : 5765 - }, - { - "id" : "minecraft:blue_ice", - "blockRuntimeId" : 691 - }, - { - "id" : "minecraft:snow_layer", - "blockRuntimeId" : 6909 - }, - { - "id" : "minecraft:pointed_dripstone", - "blockRuntimeId" : 5806 - }, - { - "id" : "minecraft:sculk_sensor", - "blockRuntimeId" : 6745 - }, - { - "id" : "minecraft:dripstone_block", - "blockRuntimeId" : 4584 - }, - { - "id" : "minecraft:moss_carpet", - "blockRuntimeId" : 5665 - }, - { - "id" : "minecraft:moss_block", - "blockRuntimeId" : 5664 - }, - { - "id" : "minecraft:dirt_with_roots", - "blockRuntimeId" : 4485 - }, - { - "id" : "minecraft:hanging_roots", - "blockRuntimeId" : 5047 - }, - { - "id" : "minecraft:big_dripleaf", - "blockRuntimeId" : 328 - }, - { - "id" : "minecraft:small_dripleaf_block", - "blockRuntimeId" : 6874 - }, - { - "id" : "minecraft:spore_blossom", - "blockRuntimeId" : 6961 - }, - { - "id" : "minecraft:azalea", - "blockRuntimeId" : 168 - }, - { - "id" : "minecraft:flowering_azalea", - "blockRuntimeId" : 4814 - }, - { - "id" : "minecraft:glow_lichen", - "blockRuntimeId" : 4971 - }, - { - "id" : "minecraft:amethyst_block", - "blockRuntimeId" : 136 - }, - { - "id" : "minecraft:budding_amethyst", - "blockRuntimeId" : 919 - }, - { - "id" : "minecraft:amethyst_cluster", - "blockRuntimeId" : 137 - }, - { - "id" : "minecraft:large_amethyst_bud", - "blockRuntimeId" : 5366 - }, - { - "id" : "minecraft:medium_amethyst_bud", - "blockRuntimeId" : 5602 - }, - { - "id" : "minecraft:small_amethyst_bud", - "blockRuntimeId" : 6861 - }, - { - "id" : "minecraft:tuff", - "blockRuntimeId" : 7413 - }, - { - "id" : "minecraft:calcite", - "blockRuntimeId" : 943 - }, - { - "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" : 900 - }, - { - "id" : "minecraft:red_mushroom", - "blockRuntimeId" : 6604 - }, - { - "id" : "minecraft:crimson_fungus", - "blockRuntimeId" : 3834 - }, - { - "id" : "minecraft:warped_fungus", - "blockRuntimeId" : 7589 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 915 - }, - { - "id" : "minecraft:red_mushroom_block", - "blockRuntimeId" : 6619 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 916 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 901 - }, - { - "id" : "minecraft:egg" - }, - { - "id" : "minecraft:sugar_cane" - }, - { - "id" : "minecraft:sugar" - }, - { - "id" : "minecraft:rotten_flesh" - }, - { - "id" : "minecraft:bone" - }, - { - "id" : "minecraft:web", - "blockRuntimeId" : 7751 - }, - { - "id" : "minecraft:spider_eye" - }, - { - "id" : "minecraft:mob_spawner", - "blockRuntimeId" : 5657 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5658 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5659 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5660 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5661 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5662 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5663 - }, - { - "id" : "minecraft:infested_deepslate", - "blockRuntimeId" : 5126 - }, - { - "id" : "minecraft:dragon_egg", - "blockRuntimeId" : 4582 - }, - { - "id" : "minecraft:turtle_egg", - "blockRuntimeId" : 7414 - }, - { - "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: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:obsidian", - "blockRuntimeId" : 5734 - }, - { - "id" : "minecraft:crying_obsidian", - "blockRuntimeId" : 3908 - }, - { - "id" : "minecraft:bedrock", - "blockRuntimeId" : 234 - }, - { - "id" : "minecraft:soul_sand", - "blockRuntimeId" : 6951 - }, - { - "id" : "minecraft:netherrack", - "blockRuntimeId" : 5703 - }, - { - "id" : "minecraft:magma", - "blockRuntimeId" : 5601 - }, - { - "id" : "minecraft:nether_wart" - }, - { - "id" : "minecraft:end_stone", - "blockRuntimeId" : 4744 - }, - { - "id" : "minecraft:chorus_flower", - "blockRuntimeId" : 1132 - }, - { - "id" : "minecraft:chorus_plant", - "blockRuntimeId" : 1138 - }, - { - "id" : "minecraft:chorus_fruit" - }, - { - "id" : "minecraft:popped_chorus_fruit" - }, - { - "id" : "minecraft:sponge", - "blockRuntimeId" : 6959 - }, - { - "id" : "minecraft:sponge", - "blockRuntimeId" : 6960 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3688 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3689 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3690 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3691 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3692 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3693 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3694 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3695 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3696 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3697 - }, - { - "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: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" : 7353 - }, - { - "id" : "minecraft:soul_torch", - "blockRuntimeId" : 6953 - }, - { - "id" : "minecraft:sea_pickle", - "blockRuntimeId" : 6813 - }, - { - "id" : "minecraft:lantern", - "blockRuntimeId" : 5362 - }, - { - "id" : "minecraft:soul_lantern", - "blockRuntimeId" : 6949 - }, - { - "id" : "minecraft:candle", - "blockRuntimeId" : 953 - }, - { - "id" : "minecraft:white_candle", - "blockRuntimeId" : 7786 - }, - { - "id" : "minecraft:orange_candle", - "blockRuntimeId" : 5735 - }, - { - "id" : "minecraft:magenta_candle", - "blockRuntimeId" : 5585 - }, - { - "id" : "minecraft:light_blue_candle", - "blockRuntimeId" : 5473 - }, - { - "id" : "minecraft:yellow_candle", - "blockRuntimeId" : 7927 - }, - { - "id" : "minecraft:lime_candle", - "blockRuntimeId" : 5521 - }, - { - "id" : "minecraft:pink_candle", - "blockRuntimeId" : 5766 - }, - { - "id" : "minecraft:gray_candle", - "blockRuntimeId" : 4999 - }, - { - "id" : "minecraft:light_gray_candle", - "blockRuntimeId" : 5489 - }, - { - "id" : "minecraft:cyan_candle", - "blockRuntimeId" : 3920 - }, - { - "id" : "minecraft:purple_candle", - "blockRuntimeId" : 6506 - }, - { - "id" : "minecraft:blue_candle", - "blockRuntimeId" : 675 - }, - { - "id" : "minecraft:brown_candle", - "blockRuntimeId" : 884 - }, - { - "id" : "minecraft:green_candle", - "blockRuntimeId" : 5015 - }, - { - "id" : "minecraft:red_candle", - "blockRuntimeId" : 6577 - }, - { - "id" : "minecraft:black_candle", - "blockRuntimeId" : 478 - }, - { - "id" : "minecraft:crafting_table", - "blockRuntimeId" : 3770 - }, - { - "id" : "minecraft:cartography_table", - "blockRuntimeId" : 987 - }, - { - "id" : "minecraft:fletching_table", - "blockRuntimeId" : 4811 - }, - { - "id" : "minecraft:smithing_table", - "blockRuntimeId" : 6875 - }, - { - "id" : "minecraft:beehive", - "blockRuntimeId" : 260 - }, - { - "id" : "minecraft:campfire" - }, - { - "id" : "minecraft:soul_campfire" - }, - { - "id" : "minecraft:furnace", - "blockRuntimeId" : 4875 - }, - { - "id" : "minecraft:blast_furnace", - "blockRuntimeId" : 669 - }, - { - "id" : "minecraft:smoker", - "blockRuntimeId" : 6876 - }, - { - "id" : "minecraft:respawn_anchor", - "blockRuntimeId" : 6696 - }, - { - "id" : "minecraft:brewing_stand" - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 152 - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 156 - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 160 - }, - { - "id" : "minecraft:grindstone", - "blockRuntimeId" : 5031 - }, - { - "id" : "minecraft:enchanting_table", - "blockRuntimeId" : 4718 - }, - { - "id" : "minecraft:bookshelf", - "blockRuntimeId" : 704 - }, - { - "id" : "minecraft:lectern", - "blockRuntimeId" : 5433 - }, - { - "id" : "minecraft:cauldron" - }, - { - "id" : "minecraft:composter", - "blockRuntimeId" : 3634 - }, - { - "id" : "minecraft:chest", - "blockRuntimeId" : 1123 - }, - { - "id" : "minecraft:trapped_chest", - "blockRuntimeId" : 7375 - }, - { - "id" : "minecraft:ender_chest", - "blockRuntimeId" : 4745 - }, - { - "id" : "minecraft:barrel", - "blockRuntimeId" : 201 - }, - { - "id" : "minecraft:undyed_shulker_box", - "blockRuntimeId" : 7458 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6826 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6834 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6833 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6841 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6838 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6840 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6827 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6830 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6831 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6839 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6835 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6829 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6837 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6836 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6828 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6832 - }, - { - "id" : "minecraft:armor_stand" - }, - { - "id" : "minecraft:noteblock", - "blockRuntimeId" : 5713 - }, - { - "id" : "minecraft:jukebox", - "blockRuntimeId" : 5207 - }, - { - "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_pigstep" - }, - { - "id" : "minecraft:glowstone_dust" - }, - { - "id" : "minecraft:glowstone", - "blockRuntimeId" : 4973 - }, - { - "id" : "minecraft:redstone_lamp", - "blockRuntimeId" : 6643 - }, - { - "id" : "minecraft:sealantern", - "blockRuntimeId" : 6824 - }, - { - "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: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: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" : 217 - }, - { - "id" : "minecraft:bell", - "blockRuntimeId" : 292 - }, - { - "id" : "minecraft:conduit", - "blockRuntimeId" : 3675 - }, - { - "id" : "minecraft:stonecutter_block", - "blockRuntimeId" : 7291 - }, - { - "id" : "minecraft:end_portal_frame", - "blockRuntimeId" : 4730 - }, - { - "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: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" : 4738 - }, - { - "id" : "minecraft:lightning_rod", - "blockRuntimeId" : 5515 - }, - { - "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: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:rail", - "blockRuntimeId" : 6564 - }, - { - "id" : "minecraft:golden_rail", - "blockRuntimeId" : 4976 - }, - { - "id" : "minecraft:detector_rail", - "blockRuntimeId" : 4461 - }, - { - "id" : "minecraft:activator_rail", - "blockRuntimeId" : 122 - }, - { - "id" : "minecraft:minecart" - }, - { - "id" : "minecraft:chest_minecart" - }, - { - "id" : "minecraft:hopper_minecart" - }, - { - "id" : "minecraft:tnt_minecart" - }, - { - "id" : "minecraft:redstone" - }, - { - "id" : "minecraft:redstone_block", - "blockRuntimeId" : 6642 - }, - { - "id" : "minecraft:redstone_torch", - "blockRuntimeId" : 6645 - }, - { - "id" : "minecraft:lever", - "blockRuntimeId" : 5441 - }, - { - "id" : "minecraft:wooden_button", - "blockRuntimeId" : 7839 - }, - { - "id" : "minecraft:spruce_button", - "blockRuntimeId" : 6962 - }, - { - "id" : "minecraft:birch_button", - "blockRuntimeId" : 356 - }, - { - "id" : "minecraft:jungle_button", - "blockRuntimeId" : 5208 - }, - { - "id" : "minecraft:acacia_button" - }, - { - "id" : "minecraft:dark_oak_button", - "blockRuntimeId" : 3936 - }, - { - "id" : "minecraft:stone_button", - "blockRuntimeId" : 7191 - }, - { - "id" : "minecraft:crimson_button", - "blockRuntimeId" : 3771 - }, - { - "id" : "minecraft:warped_button", - "blockRuntimeId" : 7526 - }, - { - "id" : "minecraft:polished_blackstone_button", - "blockRuntimeId" : 5998 - }, - { - "id" : "minecraft:tripwire_hook", - "blockRuntimeId" : 7397 - }, - { - "id" : "minecraft:wooden_pressure_plate", - "blockRuntimeId" : 7883 - }, - { - "id" : "minecraft:spruce_pressure_plate", - "blockRuntimeId" : 7022 - }, - { - "id" : "minecraft:birch_pressure_plate", - "blockRuntimeId" : 416 - }, - { - "id" : "minecraft:jungle_pressure_plate", - "blockRuntimeId" : 5268 - }, - { - "id" : "minecraft:acacia_pressure_plate", - "blockRuntimeId" : 60 - }, - { - "id" : "minecraft:dark_oak_pressure_plate", - "blockRuntimeId" : 3996 - }, - { - "id" : "minecraft:crimson_pressure_plate", - "blockRuntimeId" : 3840 - }, - { - "id" : "minecraft:warped_pressure_plate", - "blockRuntimeId" : 7595 - }, - { - "id" : "minecraft:stone_pressure_plate", - "blockRuntimeId" : 7203 - }, - { - "id" : "minecraft:light_weighted_pressure_plate", - "blockRuntimeId" : 5499 - }, - { - "id" : "minecraft:heavy_weighted_pressure_plate", - "blockRuntimeId" : 5095 - }, - { - "id" : "minecraft:polished_blackstone_pressure_plate", - "blockRuntimeId" : 6012 - }, - { - "id" : "minecraft:observer", - "blockRuntimeId" : 5722 - }, - { - "id" : "minecraft:daylight_detector", - "blockRuntimeId" : 4066 - }, - { - "id" : "minecraft:repeater" - }, - { - "id" : "minecraft:comparator" - }, - { - "id" : "minecraft:hopper" - }, - { - "id" : "minecraft:dropper", - "blockRuntimeId" : 4588 - }, - { - "id" : "minecraft:dispenser", - "blockRuntimeId" : 4489 - }, - { - "id" : "minecraft:piston", - "blockRuntimeId" : 5783 - }, - { - "id" : "minecraft:sticky_piston", - "blockRuntimeId" : 7165 - }, - { - "id" : "minecraft:tnt", - "blockRuntimeId" : 7349 - }, - { - "id" : "minecraft:name_tag" - }, - { - "id" : "minecraft:loom", - "blockRuntimeId" : 5581 - }, - { - "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: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" : 7347 - }, - { - "id" : "minecraft:lodestone_compass" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/creative_items.1_17_40.json b/core/src/main/resources/bedrock/creative_items.1_17_40.json deleted file mode 100644 index 0bc7f91ea..000000000 --- a/core/src/main/resources/bedrock/creative_items.1_17_40.json +++ /dev/null @@ -1,5206 +0,0 @@ -{ - "items" : [ - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5797 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5798 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5799 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5800 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5801 - }, - { - "id" : "minecraft:planks", - "blockRuntimeId" : 5802 - }, - { - "id" : "minecraft:crimson_planks", - "blockRuntimeId" : 3840 - }, - { - "id" : "minecraft:warped_planks", - "blockRuntimeId" : 7598 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1319 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1320 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1321 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1322 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1323 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1324 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1331 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1326 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1327 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1325 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1328 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1332 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1329 - }, - { - "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1330 - }, - { - "id" : "minecraft:blackstone_wall", - "blockRuntimeId" : 507 - }, - { - "id" : "minecraft:polished_blackstone_wall", - "blockRuntimeId" : 6041 - }, - { - "id" : "minecraft:polished_blackstone_brick_wall", - "blockRuntimeId" : 5838 - }, - { - "id" : "minecraft:cobbled_deepslate_wall", - "blockRuntimeId" : 1156 - }, - { - "id" : "minecraft:deepslate_tile_wall", - "blockRuntimeId" : 4298 - }, - { - "id" : "minecraft:polished_deepslate_wall", - "blockRuntimeId" : 6216 - }, - { - "id" : "minecraft:deepslate_brick_wall", - "blockRuntimeId" : 4115 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4774 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4775 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4776 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4777 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4778 - }, - { - "id" : "minecraft:fence", - "blockRuntimeId" : 4779 - }, - { - "id" : "minecraft:nether_brick_fence", - "blockRuntimeId" : 5689 - }, - { - "id" : "minecraft:crimson_fence", - "blockRuntimeId" : 3818 - }, - { - "id" : "minecraft:warped_fence", - "blockRuntimeId" : 7576 - }, - { - "id" : "minecraft:fence_gate", - "blockRuntimeId" : 4780 - }, - { - "id" : "minecraft:spruce_fence_gate", - "blockRuntimeId" : 7010 - }, - { - "id" : "minecraft:birch_fence_gate", - "blockRuntimeId" : 400 - }, - { - "id" : "minecraft:jungle_fence_gate", - "blockRuntimeId" : 5253 - }, - { - "id" : "minecraft:acacia_fence_gate", - "blockRuntimeId" : 44 - }, - { - "id" : "minecraft:dark_oak_fence_gate", - "blockRuntimeId" : 3981 - }, - { - "id" : "minecraft:crimson_fence_gate", - "blockRuntimeId" : 3819 - }, - { - "id" : "minecraft:warped_fence_gate", - "blockRuntimeId" : 7577 - }, - { - "id" : "minecraft:normal_stone_stairs", - "blockRuntimeId" : 5708 - }, - { - "id" : "minecraft:stone_stairs", - "blockRuntimeId" : 7281 - }, - { - "id" : "minecraft:mossy_cobblestone_stairs", - "blockRuntimeId" : 5668 - }, - { - "id" : "minecraft:oak_stairs", - "blockRuntimeId" : 5717 - }, - { - "id" : "minecraft:spruce_stairs", - "blockRuntimeId" : 7042 - }, - { - "id" : "minecraft:birch_stairs", - "blockRuntimeId" : 432 - }, - { - "id" : "minecraft:jungle_stairs", - "blockRuntimeId" : 5285 - }, - { - "id" : "minecraft:acacia_stairs", - "blockRuntimeId" : 76 - }, - { - "id" : "minecraft:dark_oak_stairs", - "blockRuntimeId" : 4013 - }, - { - "id" : "minecraft:stone_brick_stairs", - "blockRuntimeId" : 7187 - }, - { - "id" : "minecraft:mossy_stone_brick_stairs", - "blockRuntimeId" : 5676 - }, - { - "id" : "minecraft:sandstone_stairs", - "blockRuntimeId" : 6710 - }, - { - "id" : "minecraft:smooth_sandstone_stairs", - "blockRuntimeId" : 6903 - }, - { - "id" : "minecraft:red_sandstone_stairs", - "blockRuntimeId" : 6637 - }, - { - "id" : "minecraft:smooth_red_sandstone_stairs", - "blockRuntimeId" : 6895 - }, - { - "id" : "minecraft:granite_stairs", - "blockRuntimeId" : 4989 - }, - { - "id" : "minecraft:polished_granite_stairs", - "blockRuntimeId" : 6386 - }, - { - "id" : "minecraft:diorite_stairs", - "blockRuntimeId" : 4476 - }, - { - "id" : "minecraft:polished_diorite_stairs", - "blockRuntimeId" : 6378 - }, - { - "id" : "minecraft:andesite_stairs", - "blockRuntimeId" : 144 - }, - { - "id" : "minecraft:polished_andesite_stairs", - "blockRuntimeId" : 5814 - }, - { - "id" : "minecraft:brick_stairs", - "blockRuntimeId" : 876 - }, - { - "id" : "minecraft:nether_brick_stairs", - "blockRuntimeId" : 5690 - }, - { - "id" : "minecraft:red_nether_brick_stairs", - "blockRuntimeId" : 6625 - }, - { - "id" : "minecraft:end_brick_stairs", - "blockRuntimeId" : 4720 - }, - { - "id" : "minecraft:quartz_stairs", - "blockRuntimeId" : 6559 - }, - { - "id" : "minecraft:smooth_quartz_stairs", - "blockRuntimeId" : 6887 - }, - { - "id" : "minecraft:purpur_stairs", - "blockRuntimeId" : 6537 - }, - { - "id" : "minecraft:prismarine_stairs", - "blockRuntimeId" : 6449 - }, - { - "id" : "minecraft:dark_prismarine_stairs", - "blockRuntimeId" : 4037 - }, - { - "id" : "minecraft:prismarine_bricks_stairs", - "blockRuntimeId" : 6441 - }, - { - "id" : "minecraft:crimson_stairs", - "blockRuntimeId" : 3860 - }, - { - "id" : "minecraft:warped_stairs", - "blockRuntimeId" : 7618 - }, - { - "id" : "minecraft:blackstone_stairs", - "blockRuntimeId" : 499 - }, - { - "id" : "minecraft:polished_blackstone_stairs", - "blockRuntimeId" : 6033 - }, - { - "id" : "minecraft:polished_blackstone_brick_stairs", - "blockRuntimeId" : 5830 - }, - { - "id" : "minecraft:cut_copper_stairs", - "blockRuntimeId" : 3913 - }, - { - "id" : "minecraft:exposed_cut_copper_stairs", - "blockRuntimeId" : 4756 - }, - { - "id" : "minecraft:weathered_cut_copper_stairs", - "blockRuntimeId" : 7745 - }, - { - "id" : "minecraft:oxidized_cut_copper_stairs", - "blockRuntimeId" : 5758 - }, - { - "id" : "minecraft:waxed_cut_copper_stairs", - "blockRuntimeId" : 7689 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_stairs", - "blockRuntimeId" : 7703 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_stairs", - "blockRuntimeId" : 7731 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_stairs", - "blockRuntimeId" : 7717 - }, - { - "id" : "minecraft:cobbled_deepslate_stairs", - "blockRuntimeId" : 1148 - }, - { - "id" : "minecraft:deepslate_tile_stairs", - "blockRuntimeId" : 4290 - }, - { - "id" : "minecraft:polished_deepslate_stairs", - "blockRuntimeId" : 6208 - }, - { - "id" : "minecraft:deepslate_brick_stairs", - "blockRuntimeId" : 4107 - }, - { - "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:iron_door" - }, - { - "id" : "minecraft:crimson_door" - }, - { - "id" : "minecraft:warped_door" - }, - { - "id" : "minecraft:trapdoor", - "blockRuntimeId" : 7363 - }, - { - "id" : "minecraft:spruce_trapdoor", - "blockRuntimeId" : 7066 - }, - { - "id" : "minecraft:birch_trapdoor", - "blockRuntimeId" : 456 - }, - { - "id" : "minecraft:jungle_trapdoor", - "blockRuntimeId" : 5309 - }, - { - "id" : "minecraft:acacia_trapdoor", - "blockRuntimeId" : 100 - }, - { - "id" : "minecraft:dark_oak_trapdoor", - "blockRuntimeId" : 4021 - }, - { - "id" : "minecraft:iron_trapdoor", - "blockRuntimeId" : 5168 - }, - { - "id" : "minecraft:crimson_trapdoor", - "blockRuntimeId" : 3887 - }, - { - "id" : "minecraft:warped_trapdoor", - "blockRuntimeId" : 7645 - }, - { - "id" : "minecraft:iron_bars", - "blockRuntimeId" : 5133 - }, - { - "id" : "minecraft:glass", - "blockRuntimeId" : 4883 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7088 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7096 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7095 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7103 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7100 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7102 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7089 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7092 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7093 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7101 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7097 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7091 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7099 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7098 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7090 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7094 - }, - { - "id" : "minecraft:tinted_glass", - "blockRuntimeId" : 7352 - }, - { - "id" : "minecraft:glass_pane", - "blockRuntimeId" : 4884 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7104 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7112 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7111 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7119 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7116 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7118 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7105 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7108 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7109 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7117 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7113 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7107 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7115 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7114 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7106 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7110 - }, - { - "id" : "minecraft:ladder", - "blockRuntimeId" : 5357 - }, - { - "id" : "minecraft:scaffolding", - "blockRuntimeId" : 6730 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7223 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7273 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7226 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7244 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7903 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7904 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7905 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7906 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7907 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7908 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7228 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7271 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7224 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7274 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7245 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7239 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7275 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7256 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7261 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7262 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7259 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7260 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7258 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7257 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7227 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7230 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7246 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7255 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7229 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7272 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7240 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7241 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7242 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7243 - }, - { - "id" : "minecraft:crimson_slab", - "blockRuntimeId" : 3858 - }, - { - "id" : "minecraft:warped_slab", - "blockRuntimeId" : 7616 - }, - { - "id" : "minecraft:blackstone_slab", - "blockRuntimeId" : 497 - }, - { - "id" : "minecraft:polished_blackstone_slab", - "blockRuntimeId" : 6031 - }, - { - "id" : "minecraft:polished_blackstone_brick_slab", - "blockRuntimeId" : 5828 - }, - { - "id" : "minecraft:cut_copper_slab", - "blockRuntimeId" : 3911 - }, - { - "id" : "minecraft:exposed_cut_copper_slab", - "blockRuntimeId" : 4754 - }, - { - "id" : "minecraft:weathered_cut_copper_slab", - "blockRuntimeId" : 7743 - }, - { - "id" : "minecraft:oxidized_cut_copper_slab", - "blockRuntimeId" : 5756 - }, - { - "id" : "minecraft:waxed_cut_copper_slab", - "blockRuntimeId" : 7687 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_slab", - "blockRuntimeId" : 7701 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_slab", - "blockRuntimeId" : 7729 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_slab", - "blockRuntimeId" : 7715 - }, - { - "id" : "minecraft:cobbled_deepslate_slab", - "blockRuntimeId" : 1146 - }, - { - "id" : "minecraft:polished_deepslate_slab", - "blockRuntimeId" : 6206 - }, - { - "id" : "minecraft:deepslate_tile_slab", - "blockRuntimeId" : 4288 - }, - { - "id" : "minecraft:deepslate_brick_slab", - "blockRuntimeId" : 4105 - }, - { - "id" : "minecraft:brick_block", - "blockRuntimeId" : 875 - }, - { - "id" : "minecraft:chiseled_nether_bricks", - "blockRuntimeId" : 1130 - }, - { - "id" : "minecraft:cracked_nether_bricks", - "blockRuntimeId" : 3769 - }, - { - "id" : "minecraft:quartz_bricks", - "blockRuntimeId" : 6557 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7289 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7290 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7291 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7292 - }, - { - "id" : "minecraft:end_bricks", - "blockRuntimeId" : 4728 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6440 - }, - { - "id" : "minecraft:polished_blackstone_bricks", - "blockRuntimeId" : 6000 - }, - { - "id" : "minecraft:cracked_polished_blackstone_bricks", - "blockRuntimeId" : 3770 - }, - { - "id" : "minecraft:gilded_blackstone", - "blockRuntimeId" : 4882 - }, - { - "id" : "minecraft:chiseled_polished_blackstone", - "blockRuntimeId" : 1131 - }, - { - "id" : "minecraft:deepslate_tiles", - "blockRuntimeId" : 4460 - }, - { - "id" : "minecraft:cracked_deepslate_tiles", - "blockRuntimeId" : 3768 - }, - { - "id" : "minecraft:deepslate_bricks", - "blockRuntimeId" : 4277 - }, - { - "id" : "minecraft:cracked_deepslate_bricks", - "blockRuntimeId" : 3767 - }, - { - "id" : "minecraft:chiseled_deepslate", - "blockRuntimeId" : 1129 - }, - { - "id" : "minecraft:cobblestone", - "blockRuntimeId" : 1318 - }, - { - "id" : "minecraft:mossy_cobblestone", - "blockRuntimeId" : 5667 - }, - { - "id" : "minecraft:cobbled_deepslate", - "blockRuntimeId" : 1143 - }, - { - "id" : "minecraft:smooth_stone", - "blockRuntimeId" : 6911 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6706 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6707 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6708 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6709 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6633 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6634 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6635 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6636 - }, - { - "id" : "minecraft:coal_block", - "blockRuntimeId" : 1141 - }, - { - "id" : "minecraft:dried_kelp_block", - "blockRuntimeId" : 4584 - }, - { - "id" : "minecraft:gold_block", - "blockRuntimeId" : 4975 - }, - { - "id" : "minecraft:iron_block", - "blockRuntimeId" : 5134 - }, - { - "id" : "minecraft:copper_block", - "blockRuntimeId" : 3677 - }, - { - "id" : "minecraft:exposed_copper", - "blockRuntimeId" : 4752 - }, - { - "id" : "minecraft:weathered_copper", - "blockRuntimeId" : 7741 - }, - { - "id" : "minecraft:oxidized_copper", - "blockRuntimeId" : 5754 - }, - { - "id" : "minecraft:waxed_copper", - "blockRuntimeId" : 7685 - }, - { - "id" : "minecraft:waxed_exposed_copper", - "blockRuntimeId" : 7699 - }, - { - "id" : "minecraft:waxed_weathered_copper", - "blockRuntimeId" : 7727 - }, - { - "id" : "minecraft:waxed_oxidized_copper", - "blockRuntimeId" : 7713 - }, - { - "id" : "minecraft:cut_copper", - "blockRuntimeId" : 3910 - }, - { - "id" : "minecraft:exposed_cut_copper", - "blockRuntimeId" : 4753 - }, - { - "id" : "minecraft:weathered_cut_copper", - "blockRuntimeId" : 7742 - }, - { - "id" : "minecraft:oxidized_cut_copper", - "blockRuntimeId" : 5755 - }, - { - "id" : "minecraft:waxed_cut_copper", - "blockRuntimeId" : 7686 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper", - "blockRuntimeId" : 7700 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper", - "blockRuntimeId" : 7728 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper", - "blockRuntimeId" : 7714 - }, - { - "id" : "minecraft:emerald_block", - "blockRuntimeId" : 4717 - }, - { - "id" : "minecraft:diamond_block", - "blockRuntimeId" : 4474 - }, - { - "id" : "minecraft:lapis_block", - "blockRuntimeId" : 5365 - }, - { - "id" : "minecraft:raw_iron_block", - "blockRuntimeId" : 6579 - }, - { - "id" : "minecraft:raw_copper_block", - "blockRuntimeId" : 6577 - }, - { - "id" : "minecraft:raw_gold_block", - "blockRuntimeId" : 6578 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6545 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6547 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6546 - }, - { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6548 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6438 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6439 - }, - { - "id" : "minecraft:slime", - "blockRuntimeId" : 6864 - }, - { - "id" : "minecraft:honey_block", - "blockRuntimeId" : 5112 - }, - { - "id" : "minecraft:honeycomb_block", - "blockRuntimeId" : 5113 - }, - { - "id" : "minecraft:hay_block", - "blockRuntimeId" : 5084 - }, - { - "id" : "minecraft:bone_block", - "blockRuntimeId" : 692 - }, - { - "id" : "minecraft:nether_brick", - "blockRuntimeId" : 5688 - }, - { - "id" : "minecraft:red_nether_brick", - "blockRuntimeId" : 6624 - }, - { - "id" : "minecraft:netherite_block", - "blockRuntimeId" : 5705 - }, - { - "id" : "minecraft:lodestone", - "blockRuntimeId" : 5563 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7915 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7923 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7922 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7930 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7927 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7929 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7916 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7919 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7920 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7928 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7924 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7918 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7926 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7925 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7917 - }, - { - "id" : "minecraft:wool", - "blockRuntimeId" : 7921 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 963 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 971 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 970 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 978 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 975 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 977 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 964 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 967 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 968 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 976 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 972 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 966 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 974 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 973 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 965 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 969 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3660 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3668 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3667 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3675 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3672 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3674 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3661 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3664 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3665 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3673 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3669 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3663 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3671 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3670 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3662 - }, - { - "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3666 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3644 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3652 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3651 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3659 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3656 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3658 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3645 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3648 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3649 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3657 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3653 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3647 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3655 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3654 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3646 - }, - { - "id" : "minecraft:concrete", - "blockRuntimeId" : 3650 - }, - { - "id" : "minecraft:clay", - "blockRuntimeId" : 1139 - }, - { - "id" : "minecraft:hardened_clay", - "blockRuntimeId" : 5083 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7120 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7128 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7127 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7135 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7132 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7134 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7121 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7124 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7125 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7133 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7129 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7123 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7131 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7130 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7122 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7126 - }, - { - "id" : "minecraft:white_glazed_terracotta", - "blockRuntimeId" : 7800 - }, - { - "id" : "minecraft:silver_glazed_terracotta", - "blockRuntimeId" : 6846 - }, - { - "id" : "minecraft:gray_glazed_terracotta", - "blockRuntimeId" : 5010 - }, - { - "id" : "minecraft:black_glazed_terracotta", - "blockRuntimeId" : 488 - }, - { - "id" : "minecraft:brown_glazed_terracotta", - "blockRuntimeId" : 894 - }, - { - "id" : "minecraft:red_glazed_terracotta", - "blockRuntimeId" : 6601 - }, - { - "id" : "minecraft:orange_glazed_terracotta", - "blockRuntimeId" : 5748 - }, - { - "id" : "minecraft:yellow_glazed_terracotta", - "blockRuntimeId" : 7942 - }, - { - "id" : "minecraft:lime_glazed_terracotta", - "blockRuntimeId" : 5532 - }, - { - "id" : "minecraft:green_glazed_terracotta", - "blockRuntimeId" : 5026 - }, - { - "id" : "minecraft:cyan_glazed_terracotta", - "blockRuntimeId" : 3931 - }, - { - "id" : "minecraft:light_blue_glazed_terracotta", - "blockRuntimeId" : 5484 - }, - { - "id" : "minecraft:blue_glazed_terracotta", - "blockRuntimeId" : 685 - }, - { - "id" : "minecraft:purple_glazed_terracotta", - "blockRuntimeId" : 6519 - }, - { - "id" : "minecraft:magenta_glazed_terracotta", - "blockRuntimeId" : 5596 - }, - { - "id" : "minecraft:pink_glazed_terracotta", - "blockRuntimeId" : 5779 - }, - { - "id" : "minecraft:purpur_block", - "blockRuntimeId" : 6525 - }, - { - "id" : "minecraft:purpur_block", - "blockRuntimeId" : 6527 - }, - { - "id" : "minecraft:nether_wart_block", - "blockRuntimeId" : 5704 - }, - { - "id" : "minecraft:warped_wart_block", - "blockRuntimeId" : 7667 - }, - { - "id" : "minecraft:shroomlight", - "blockRuntimeId" : 6829 - }, - { - "id" : "minecraft:crimson_nylium", - "blockRuntimeId" : 3839 - }, - { - "id" : "minecraft:warped_nylium", - "blockRuntimeId" : 7597 - }, - { - "id" : "minecraft:basalt", - "blockRuntimeId" : 214 - }, - { - "id" : "minecraft:polished_basalt", - "blockRuntimeId" : 5822 - }, - { - "id" : "minecraft:smooth_basalt", - "blockRuntimeId" : 6886 - }, - { - "id" : "minecraft:soul_soil", - "blockRuntimeId" : 6956 - }, - { - "id" : "minecraft:dirt", - "blockRuntimeId" : 4484 - }, - { - "id" : "minecraft:dirt", - "blockRuntimeId" : 4485 - }, - { - "id" : "minecraft:farmland", - "blockRuntimeId" : 4766 - }, - { - "id" : "minecraft:grass", - "blockRuntimeId" : 4997 - }, - { - "id" : "minecraft:grass_path", - "blockRuntimeId" : 4998 - }, - { - "id" : "minecraft:podzol", - "blockRuntimeId" : 5803 - }, - { - "id" : "minecraft:mycelium", - "blockRuntimeId" : 5685 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7180 - }, - { - "id" : "minecraft:iron_ore", - "blockRuntimeId" : 5167 - }, - { - "id" : "minecraft:gold_ore", - "blockRuntimeId" : 4976 - }, - { - "id" : "minecraft:diamond_ore", - "blockRuntimeId" : 4475 - }, - { - "id" : "minecraft:lapis_ore", - "blockRuntimeId" : 5366 - }, - { - "id" : "minecraft:redstone_ore", - "blockRuntimeId" : 6647 - }, - { - "id" : "minecraft:coal_ore", - "blockRuntimeId" : 1142 - }, - { - "id" : "minecraft:copper_ore", - "blockRuntimeId" : 3678 - }, - { - "id" : "minecraft:emerald_ore", - "blockRuntimeId" : 4718 - }, - { - "id" : "minecraft:quartz_ore", - "blockRuntimeId" : 6558 - }, - { - "id" : "minecraft:nether_gold_ore", - "blockRuntimeId" : 5698 - }, - { - "id" : "minecraft:ancient_debris", - "blockRuntimeId" : 143 - }, - { - "id" : "minecraft:deepslate_iron_ore", - "blockRuntimeId" : 4283 - }, - { - "id" : "minecraft:deepslate_gold_ore", - "blockRuntimeId" : 4282 - }, - { - "id" : "minecraft:deepslate_diamond_ore", - "blockRuntimeId" : 4280 - }, - { - "id" : "minecraft:deepslate_lapis_ore", - "blockRuntimeId" : 4284 - }, - { - "id" : "minecraft:deepslate_redstone_ore", - "blockRuntimeId" : 4285 - }, - { - "id" : "minecraft:deepslate_emerald_ore", - "blockRuntimeId" : 4281 - }, - { - "id" : "minecraft:deepslate_coal_ore", - "blockRuntimeId" : 4278 - }, - { - "id" : "minecraft:deepslate_copper_ore", - "blockRuntimeId" : 4279 - }, - { - "id" : "minecraft:gravel", - "blockRuntimeId" : 4999 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7181 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7183 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7185 - }, - { - "id" : "minecraft:blackstone", - "blockRuntimeId" : 494 - }, - { - "id" : "minecraft:deepslate", - "blockRuntimeId" : 4100 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7182 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7184 - }, - { - "id" : "minecraft:stone", - "blockRuntimeId" : 7186 - }, - { - "id" : "minecraft:polished_blackstone", - "blockRuntimeId" : 5825 - }, - { - "id" : "minecraft:polished_deepslate", - "blockRuntimeId" : 6203 - }, - { - "id" : "minecraft:sand", - "blockRuntimeId" : 6704 - }, - { - "id" : "minecraft:sand", - "blockRuntimeId" : 6705 - }, - { - "id" : "minecraft:cactus", - "blockRuntimeId" : 920 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5564 - }, - { - "id" : "minecraft:stripped_oak_log", - "blockRuntimeId" : 7319 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5565 - }, - { - "id" : "minecraft:stripped_spruce_log", - "blockRuntimeId" : 7322 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5566 - }, - { - "id" : "minecraft:stripped_birch_log", - "blockRuntimeId" : 7304 - }, - { - "id" : "minecraft:log", - "blockRuntimeId" : 5567 - }, - { - "id" : "minecraft:stripped_jungle_log", - "blockRuntimeId" : 7316 - }, - { - "id" : "minecraft:log2", - "blockRuntimeId" : 5576 - }, - { - "id" : "minecraft:stripped_acacia_log", - "blockRuntimeId" : 7301 - }, - { - "id" : "minecraft:log2", - "blockRuntimeId" : 5577 - }, - { - "id" : "minecraft:stripped_dark_oak_log", - "blockRuntimeId" : 7313 - }, - { - "id" : "minecraft:crimson_stem", - "blockRuntimeId" : 3884 - }, - { - "id" : "minecraft:stripped_crimson_stem", - "blockRuntimeId" : 7310 - }, - { - "id" : "minecraft:warped_stem", - "blockRuntimeId" : 7642 - }, - { - "id" : "minecraft:stripped_warped_stem", - "blockRuntimeId" : 7328 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7807 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7813 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7808 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7814 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7809 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7815 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7810 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7816 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7811 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7817 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7812 - }, - { - "id" : "minecraft:wood", - "blockRuntimeId" : 7818 - }, - { - "id" : "minecraft:crimson_hyphae", - "blockRuntimeId" : 3836 - }, - { - "id" : "minecraft:stripped_crimson_hyphae", - "blockRuntimeId" : 7307 - }, - { - "id" : "minecraft:warped_hyphae", - "blockRuntimeId" : 7594 - }, - { - "id" : "minecraft:stripped_warped_hyphae", - "blockRuntimeId" : 7325 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5410 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5411 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5412 - }, - { - "id" : "minecraft:leaves", - "blockRuntimeId" : 5413 - }, - { - "id" : "minecraft:leaves2", - "blockRuntimeId" : 5426 - }, - { - "id" : "minecraft:leaves2", - "blockRuntimeId" : 5427 - }, - { - "id" : "minecraft:azalea_leaves", - "blockRuntimeId" : 169 - }, - { - "id" : "minecraft:azalea_leaves_flowered", - "blockRuntimeId" : 173 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6718 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6719 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6720 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6721 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6722 - }, - { - "id" : "minecraft:sapling", - "blockRuntimeId" : 6723 - }, - { - "id" : "minecraft:bee_nest", - "blockRuntimeId" : 236 - }, - { - "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" : 5609 - }, - { - "id" : "minecraft:melon_slice" - }, - { - "id" : "minecraft:glistering_melon_slice" - }, - { - "id" : "minecraft:sweet_berries" - }, - { - "id" : "minecraft:glow_berries" - }, - { - "id" : "minecraft:pumpkin", - "blockRuntimeId" : 6457 - }, - { - "id" : "minecraft:carved_pumpkin", - "blockRuntimeId" : 988 - }, - { - "id" : "minecraft:lit_pumpkin", - "blockRuntimeId" : 5551 - }, - { - "id" : "minecraft:honeycomb" - }, - { - "id" : "minecraft:tallgrass", - "blockRuntimeId" : 7349 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4504 - }, - { - "id" : "minecraft:tallgrass", - "blockRuntimeId" : 7348 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4503 - }, - { - "id" : "minecraft:nether_sprouts" - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3682 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3680 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3681 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3679 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3683 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3687 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3685 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3686 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3684 - }, - { - "id" : "minecraft:coral", - "blockRuntimeId" : 3688 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3702 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3700 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3701 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3699 - }, - { - "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3703 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3712 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3710 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3711 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3709 - }, - { - "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3713 - }, - { - "id" : "minecraft:kelp" - }, - { - "id" : "minecraft:seagrass", - "blockRuntimeId" : 6825 - }, - { - "id" : "minecraft:crimson_roots", - "blockRuntimeId" : 3857 - }, - { - "id" : "minecraft:warped_roots", - "blockRuntimeId" : 7615 - }, - { - "id" : "minecraft:yellow_flower", - "blockRuntimeId" : 7941 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6590 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6591 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6592 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6593 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6594 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6595 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6596 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6597 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6598 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6599 - }, - { - "id" : "minecraft:red_flower", - "blockRuntimeId" : 6600 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4501 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4502 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4505 - }, - { - "id" : "minecraft:double_plant", - "blockRuntimeId" : 4506 - }, - { - "id" : "minecraft:wither_rose", - "blockRuntimeId" : 7806 - }, - { - "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" : 7502 - }, - { - "id" : "minecraft:weeping_vines", - "blockRuntimeId" : 7756 - }, - { - "id" : "minecraft:twisting_vines", - "blockRuntimeId" : 7430 - }, - { - "id" : "minecraft:waterlily", - "blockRuntimeId" : 7684 - }, - { - "id" : "minecraft:deadbush", - "blockRuntimeId" : 4099 - }, - { - "id" : "minecraft:bamboo", - "blockRuntimeId" : 177 - }, - { - "id" : "minecraft:snow", - "blockRuntimeId" : 6912 - }, - { - "id" : "minecraft:ice", - "blockRuntimeId" : 5126 - }, - { - "id" : "minecraft:packed_ice", - "blockRuntimeId" : 5768 - }, - { - "id" : "minecraft:blue_ice", - "blockRuntimeId" : 691 - }, - { - "id" : "minecraft:snow_layer", - "blockRuntimeId" : 6913 - }, - { - "id" : "minecraft:pointed_dripstone", - "blockRuntimeId" : 5809 - }, - { - "id" : "minecraft:dripstone_block", - "blockRuntimeId" : 4585 - }, - { - "id" : "minecraft:moss_carpet", - "blockRuntimeId" : 5666 - }, - { - "id" : "minecraft:moss_block", - "blockRuntimeId" : 5665 - }, - { - "id" : "minecraft:dirt_with_roots", - "blockRuntimeId" : 4486 - }, - { - "id" : "minecraft:hanging_roots", - "blockRuntimeId" : 5048 - }, - { - "id" : "minecraft:big_dripleaf", - "blockRuntimeId" : 328 - }, - { - "id" : "minecraft:small_dripleaf_block", - "blockRuntimeId" : 6878 - }, - { - "id" : "minecraft:spore_blossom", - "blockRuntimeId" : 6965 - }, - { - "id" : "minecraft:azalea", - "blockRuntimeId" : 168 - }, - { - "id" : "minecraft:flowering_azalea", - "blockRuntimeId" : 4815 - }, - { - "id" : "minecraft:glow_lichen", - "blockRuntimeId" : 4972 - }, - { - "id" : "minecraft:amethyst_block", - "blockRuntimeId" : 136 - }, - { - "id" : "minecraft:budding_amethyst", - "blockRuntimeId" : 919 - }, - { - "id" : "minecraft:amethyst_cluster", - "blockRuntimeId" : 137 - }, - { - "id" : "minecraft:large_amethyst_bud", - "blockRuntimeId" : 5367 - }, - { - "id" : "minecraft:medium_amethyst_bud", - "blockRuntimeId" : 5603 - }, - { - "id" : "minecraft:small_amethyst_bud", - "blockRuntimeId" : 6865 - }, - { - "id" : "minecraft:tuff", - "blockRuntimeId" : 7417 - }, - { - "id" : "minecraft:calcite", - "blockRuntimeId" : 943 - }, - { - "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" : 900 - }, - { - "id" : "minecraft:red_mushroom", - "blockRuntimeId" : 6607 - }, - { - "id" : "minecraft:crimson_fungus", - "blockRuntimeId" : 3835 - }, - { - "id" : "minecraft:warped_fungus", - "blockRuntimeId" : 7593 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 915 - }, - { - "id" : "minecraft:red_mushroom_block", - "blockRuntimeId" : 6622 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 916 - }, - { - "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 901 - }, - { - "id" : "minecraft:egg" - }, - { - "id" : "minecraft:sugar_cane" - }, - { - "id" : "minecraft:sugar" - }, - { - "id" : "minecraft:rotten_flesh" - }, - { - "id" : "minecraft:bone" - }, - { - "id" : "minecraft:web", - "blockRuntimeId" : 7755 - }, - { - "id" : "minecraft:spider_eye" - }, - { - "id" : "minecraft:mob_spawner", - "blockRuntimeId" : 5658 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5659 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5660 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5661 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5662 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5663 - }, - { - "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5664 - }, - { - "id" : "minecraft:infested_deepslate", - "blockRuntimeId" : 5127 - }, - { - "id" : "minecraft:dragon_egg", - "blockRuntimeId" : 4583 - }, - { - "id" : "minecraft:turtle_egg", - "blockRuntimeId" : 7418 - }, - { - "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: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:obsidian", - "blockRuntimeId" : 5737 - }, - { - "id" : "minecraft:crying_obsidian", - "blockRuntimeId" : 3909 - }, - { - "id" : "minecraft:bedrock", - "blockRuntimeId" : 234 - }, - { - "id" : "minecraft:soul_sand", - "blockRuntimeId" : 6955 - }, - { - "id" : "minecraft:netherrack", - "blockRuntimeId" : 5706 - }, - { - "id" : "minecraft:magma", - "blockRuntimeId" : 5602 - }, - { - "id" : "minecraft:nether_wart" - }, - { - "id" : "minecraft:end_stone", - "blockRuntimeId" : 4745 - }, - { - "id" : "minecraft:chorus_flower", - "blockRuntimeId" : 1132 - }, - { - "id" : "minecraft:chorus_plant", - "blockRuntimeId" : 1138 - }, - { - "id" : "minecraft:chorus_fruit" - }, - { - "id" : "minecraft:popped_chorus_fruit" - }, - { - "id" : "minecraft:sponge", - "blockRuntimeId" : 6963 - }, - { - "id" : "minecraft:sponge", - "blockRuntimeId" : 6964 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3689 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3690 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3691 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3692 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3693 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3694 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3695 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3696 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3697 - }, - { - "id" : "minecraft:coral_block", - "blockRuntimeId" : 3698 - }, - { - "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: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" : 7357 - }, - { - "id" : "minecraft:soul_torch", - "blockRuntimeId" : 6957 - }, - { - "id" : "minecraft:sea_pickle", - "blockRuntimeId" : 6817 - }, - { - "id" : "minecraft:lantern", - "blockRuntimeId" : 5363 - }, - { - "id" : "minecraft:soul_lantern", - "blockRuntimeId" : 6953 - }, - { - "id" : "minecraft:candle", - "blockRuntimeId" : 953 - }, - { - "id" : "minecraft:white_candle", - "blockRuntimeId" : 7790 - }, - { - "id" : "minecraft:orange_candle", - "blockRuntimeId" : 5738 - }, - { - "id" : "minecraft:magenta_candle", - "blockRuntimeId" : 5586 - }, - { - "id" : "minecraft:light_blue_candle", - "blockRuntimeId" : 5474 - }, - { - "id" : "minecraft:yellow_candle", - "blockRuntimeId" : 7931 - }, - { - "id" : "minecraft:lime_candle", - "blockRuntimeId" : 5522 - }, - { - "id" : "minecraft:pink_candle", - "blockRuntimeId" : 5769 - }, - { - "id" : "minecraft:gray_candle", - "blockRuntimeId" : 5000 - }, - { - "id" : "minecraft:light_gray_candle", - "blockRuntimeId" : 5490 - }, - { - "id" : "minecraft:cyan_candle", - "blockRuntimeId" : 3921 - }, - { - "id" : "minecraft:purple_candle", - "blockRuntimeId" : 6509 - }, - { - "id" : "minecraft:blue_candle", - "blockRuntimeId" : 675 - }, - { - "id" : "minecraft:brown_candle", - "blockRuntimeId" : 884 - }, - { - "id" : "minecraft:green_candle", - "blockRuntimeId" : 5016 - }, - { - "id" : "minecraft:red_candle", - "blockRuntimeId" : 6580 - }, - { - "id" : "minecraft:black_candle", - "blockRuntimeId" : 478 - }, - { - "id" : "minecraft:crafting_table", - "blockRuntimeId" : 3771 - }, - { - "id" : "minecraft:cartography_table", - "blockRuntimeId" : 987 - }, - { - "id" : "minecraft:fletching_table", - "blockRuntimeId" : 4812 - }, - { - "id" : "minecraft:smithing_table", - "blockRuntimeId" : 6879 - }, - { - "id" : "minecraft:beehive", - "blockRuntimeId" : 260 - }, - { - "id" : "minecraft:campfire" - }, - { - "id" : "minecraft:soul_campfire" - }, - { - "id" : "minecraft:furnace", - "blockRuntimeId" : 4876 - }, - { - "id" : "minecraft:blast_furnace", - "blockRuntimeId" : 669 - }, - { - "id" : "minecraft:smoker", - "blockRuntimeId" : 6880 - }, - { - "id" : "minecraft:respawn_anchor", - "blockRuntimeId" : 6699 - }, - { - "id" : "minecraft:brewing_stand" - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 152 - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 156 - }, - { - "id" : "minecraft:anvil", - "blockRuntimeId" : 160 - }, - { - "id" : "minecraft:grindstone", - "blockRuntimeId" : 5032 - }, - { - "id" : "minecraft:enchanting_table", - "blockRuntimeId" : 4719 - }, - { - "id" : "minecraft:bookshelf", - "blockRuntimeId" : 704 - }, - { - "id" : "minecraft:lectern", - "blockRuntimeId" : 5434 - }, - { - "id" : "minecraft:cauldron" - }, - { - "id" : "minecraft:composter", - "blockRuntimeId" : 3635 - }, - { - "id" : "minecraft:chest", - "blockRuntimeId" : 1123 - }, - { - "id" : "minecraft:trapped_chest", - "blockRuntimeId" : 7379 - }, - { - "id" : "minecraft:ender_chest", - "blockRuntimeId" : 4746 - }, - { - "id" : "minecraft:barrel", - "blockRuntimeId" : 201 - }, - { - "id" : "minecraft:undyed_shulker_box", - "blockRuntimeId" : 7462 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6830 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6838 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6837 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6845 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6842 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6844 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6831 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6834 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6835 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6843 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6839 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6833 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6841 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6840 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6832 - }, - { - "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6836 - }, - { - "id" : "minecraft:armor_stand" - }, - { - "id" : "minecraft:noteblock", - "blockRuntimeId" : 5716 - }, - { - "id" : "minecraft:jukebox", - "blockRuntimeId" : 5208 - }, - { - "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_pigstep" - }, - { - "id" : "minecraft:glowstone_dust" - }, - { - "id" : "minecraft:glowstone", - "blockRuntimeId" : 4974 - }, - { - "id" : "minecraft:redstone_lamp", - "blockRuntimeId" : 6646 - }, - { - "id" : "minecraft:sealantern", - "blockRuntimeId" : 6828 - }, - { - "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: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: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" : 217 - }, - { - "id" : "minecraft:bell", - "blockRuntimeId" : 292 - }, - { - "id" : "minecraft:conduit", - "blockRuntimeId" : 3676 - }, - { - "id" : "minecraft:stonecutter_block", - "blockRuntimeId" : 7295 - }, - { - "id" : "minecraft:end_portal_frame", - "blockRuntimeId" : 4731 - }, - { - "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: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" : 4739 - }, - { - "id" : "minecraft:lightning_rod", - "blockRuntimeId" : 5516 - }, - { - "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: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:rail", - "blockRuntimeId" : 6567 - }, - { - "id" : "minecraft:golden_rail", - "blockRuntimeId" : 4977 - }, - { - "id" : "minecraft:detector_rail", - "blockRuntimeId" : 4462 - }, - { - "id" : "minecraft:activator_rail", - "blockRuntimeId" : 122 - }, - { - "id" : "minecraft:minecart" - }, - { - "id" : "minecraft:chest_minecart" - }, - { - "id" : "minecraft:hopper_minecart" - }, - { - "id" : "minecraft:tnt_minecart" - }, - { - "id" : "minecraft:redstone" - }, - { - "id" : "minecraft:redstone_block", - "blockRuntimeId" : 6645 - }, - { - "id" : "minecraft:redstone_torch", - "blockRuntimeId" : 6648 - }, - { - "id" : "minecraft:lever", - "blockRuntimeId" : 5442 - }, - { - "id" : "minecraft:wooden_button", - "blockRuntimeId" : 7843 - }, - { - "id" : "minecraft:spruce_button", - "blockRuntimeId" : 6966 - }, - { - "id" : "minecraft:birch_button", - "blockRuntimeId" : 356 - }, - { - "id" : "minecraft:jungle_button", - "blockRuntimeId" : 5209 - }, - { - "id" : "minecraft:acacia_button" - }, - { - "id" : "minecraft:dark_oak_button", - "blockRuntimeId" : 3937 - }, - { - "id" : "minecraft:stone_button", - "blockRuntimeId" : 7195 - }, - { - "id" : "minecraft:crimson_button", - "blockRuntimeId" : 3772 - }, - { - "id" : "minecraft:warped_button", - "blockRuntimeId" : 7530 - }, - { - "id" : "minecraft:polished_blackstone_button", - "blockRuntimeId" : 6001 - }, - { - "id" : "minecraft:tripwire_hook", - "blockRuntimeId" : 7401 - }, - { - "id" : "minecraft:wooden_pressure_plate", - "blockRuntimeId" : 7887 - }, - { - "id" : "minecraft:spruce_pressure_plate", - "blockRuntimeId" : 7026 - }, - { - "id" : "minecraft:birch_pressure_plate", - "blockRuntimeId" : 416 - }, - { - "id" : "minecraft:jungle_pressure_plate", - "blockRuntimeId" : 5269 - }, - { - "id" : "minecraft:acacia_pressure_plate", - "blockRuntimeId" : 60 - }, - { - "id" : "minecraft:dark_oak_pressure_plate", - "blockRuntimeId" : 3997 - }, - { - "id" : "minecraft:crimson_pressure_plate", - "blockRuntimeId" : 3841 - }, - { - "id" : "minecraft:warped_pressure_plate", - "blockRuntimeId" : 7599 - }, - { - "id" : "minecraft:stone_pressure_plate", - "blockRuntimeId" : 7207 - }, - { - "id" : "minecraft:light_weighted_pressure_plate", - "blockRuntimeId" : 5500 - }, - { - "id" : "minecraft:heavy_weighted_pressure_plate", - "blockRuntimeId" : 5096 - }, - { - "id" : "minecraft:polished_blackstone_pressure_plate", - "blockRuntimeId" : 6015 - }, - { - "id" : "minecraft:observer", - "blockRuntimeId" : 5725 - }, - { - "id" : "minecraft:daylight_detector", - "blockRuntimeId" : 4067 - }, - { - "id" : "minecraft:repeater" - }, - { - "id" : "minecraft:comparator" - }, - { - "id" : "minecraft:hopper" - }, - { - "id" : "minecraft:dropper", - "blockRuntimeId" : 4589 - }, - { - "id" : "minecraft:dispenser", - "blockRuntimeId" : 4490 - }, - { - "id" : "minecraft:piston", - "blockRuntimeId" : 5786 - }, - { - "id" : "minecraft:sticky_piston", - "blockRuntimeId" : 7169 - }, - { - "id" : "minecraft:tnt", - "blockRuntimeId" : 7353 - }, - { - "id" : "minecraft:name_tag" - }, - { - "id" : "minecraft:loom", - "blockRuntimeId" : 5582 - }, - { - "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: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" : 7351 - }, - { - "id" : "minecraft:lodestone_compass" - }, - { - "id" : "minecraft:debug_stick" - } - ] -} \ No newline at end of file diff --git a/core/src/main/resources/bedrock/creative_items.1_18_0.json b/core/src/main/resources/bedrock/creative_items.1_19_0.json similarity index 79% rename from core/src/main/resources/bedrock/creative_items.1_18_0.json rename to core/src/main/resources/bedrock/creative_items.1_19_0.json index d32ba0cbf..3a356a802 100644 --- a/core/src/main/resources/bedrock/creative_items.1_18_0.json +++ b/core/src/main/resources/bedrock/creative_items.1_19_0.json @@ -2,379 +2,403 @@ "items" : [ { "id" : "minecraft:planks", - "blockRuntimeId" : 5797 + "blockRuntimeId" : 6071 }, { "id" : "minecraft:planks", - "blockRuntimeId" : 5798 + "blockRuntimeId" : 6072 }, { "id" : "minecraft:planks", - "blockRuntimeId" : 5799 + "blockRuntimeId" : 6073 }, { "id" : "minecraft:planks", - "blockRuntimeId" : 5800 + "blockRuntimeId" : 6074 }, { "id" : "minecraft:planks", - "blockRuntimeId" : 5801 + "blockRuntimeId" : 6075 }, { "id" : "minecraft:planks", - "blockRuntimeId" : 5802 + "blockRuntimeId" : 6076 + }, + { + "id" : "minecraft:mangrove_planks", + "blockRuntimeId" : 947 }, { "id" : "minecraft:crimson_planks", - "blockRuntimeId" : 3840 + "blockRuntimeId" : 4850 }, { "id" : "minecraft:warped_planks", - "blockRuntimeId" : 7598 + "blockRuntimeId" : 920 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1319 + "blockRuntimeId" : 1182 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1320 + "blockRuntimeId" : 1183 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1321 + "blockRuntimeId" : 1184 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1322 + "blockRuntimeId" : 1185 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1323 + "blockRuntimeId" : 1186 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1324 + "blockRuntimeId" : 1187 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1331 + "blockRuntimeId" : 1194 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1326 + "blockRuntimeId" : 1189 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1327 + "blockRuntimeId" : 1190 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1325 + "blockRuntimeId" : 1188 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1328 + "blockRuntimeId" : 1191 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1332 + "blockRuntimeId" : 1195 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1329 + "blockRuntimeId" : 1192 }, { "id" : "minecraft:cobblestone_wall", - "blockRuntimeId" : 1330 + "blockRuntimeId" : 1193 }, { "id" : "minecraft:blackstone_wall", - "blockRuntimeId" : 507 + "blockRuntimeId" : 3930 }, { "id" : "minecraft:polished_blackstone_wall", - "blockRuntimeId" : 6041 + "blockRuntimeId" : 6724 }, { "id" : "minecraft:polished_blackstone_brick_wall", - "blockRuntimeId" : 5838 + "blockRuntimeId" : 971 }, { "id" : "minecraft:cobbled_deepslate_wall", - "blockRuntimeId" : 1156 + "blockRuntimeId" : 8082 }, { "id" : "minecraft:deepslate_tile_wall", - "blockRuntimeId" : 4298 + "blockRuntimeId" : 5071 }, { "id" : "minecraft:polished_deepslate_wall", - "blockRuntimeId" : 6216 + "blockRuntimeId" : 7817 }, { "id" : "minecraft:deepslate_brick_wall", - "blockRuntimeId" : 4115 + "blockRuntimeId" : 429 + }, + { + "id" : "minecraft:mud_brick_wall", + "blockRuntimeId" : 730 }, { "id" : "minecraft:fence", - "blockRuntimeId" : 4774 + "blockRuntimeId" : 7364 }, { "id" : "minecraft:fence", - "blockRuntimeId" : 4775 + "blockRuntimeId" : 7365 }, { "id" : "minecraft:fence", - "blockRuntimeId" : 4776 + "blockRuntimeId" : 7366 }, { "id" : "minecraft:fence", - "blockRuntimeId" : 4777 + "blockRuntimeId" : 7367 }, { "id" : "minecraft:fence", - "blockRuntimeId" : 4778 + "blockRuntimeId" : 7368 }, { "id" : "minecraft:fence", - "blockRuntimeId" : 4779 + "blockRuntimeId" : 7369 + }, + { + "id" : "minecraft:mangrove_fence", + "blockRuntimeId" : 6633 }, { "id" : "minecraft:nether_brick_fence", - "blockRuntimeId" : 5689 - }, - { - "id" : "minecraft:crimson_fence", - "blockRuntimeId" : 3818 - }, - { - "id" : "minecraft:warped_fence", - "blockRuntimeId" : 7576 - }, - { - "id" : "minecraft:fence_gate", - "blockRuntimeId" : 4780 - }, - { - "id" : "minecraft:spruce_fence_gate", - "blockRuntimeId" : 7010 - }, - { - "id" : "minecraft:birch_fence_gate", - "blockRuntimeId" : 400 - }, - { - "id" : "minecraft:jungle_fence_gate", - "blockRuntimeId" : 5253 - }, - { - "id" : "minecraft:acacia_fence_gate", - "blockRuntimeId" : 44 - }, - { - "id" : "minecraft:dark_oak_fence_gate", - "blockRuntimeId" : 3981 - }, - { - "id" : "minecraft:crimson_fence_gate", - "blockRuntimeId" : 3819 - }, - { - "id" : "minecraft:warped_fence_gate", - "blockRuntimeId" : 7577 - }, - { - "id" : "minecraft:normal_stone_stairs", - "blockRuntimeId" : 5708 - }, - { - "id" : "minecraft:stone_stairs", - "blockRuntimeId" : 7281 - }, - { - "id" : "minecraft:mossy_cobblestone_stairs", - "blockRuntimeId" : 5668 - }, - { - "id" : "minecraft:oak_stairs", - "blockRuntimeId" : 5717 - }, - { - "id" : "minecraft:spruce_stairs", - "blockRuntimeId" : 7042 - }, - { - "id" : "minecraft:birch_stairs", - "blockRuntimeId" : 432 - }, - { - "id" : "minecraft:jungle_stairs", - "blockRuntimeId" : 5285 - }, - { - "id" : "minecraft:acacia_stairs", - "blockRuntimeId" : 76 - }, - { - "id" : "minecraft:dark_oak_stairs", - "blockRuntimeId" : 4013 - }, - { - "id" : "minecraft:stone_brick_stairs", - "blockRuntimeId" : 7187 - }, - { - "id" : "minecraft:mossy_stone_brick_stairs", - "blockRuntimeId" : 5676 - }, - { - "id" : "minecraft:sandstone_stairs", - "blockRuntimeId" : 6710 - }, - { - "id" : "minecraft:smooth_sandstone_stairs", - "blockRuntimeId" : 6903 - }, - { - "id" : "minecraft:red_sandstone_stairs", - "blockRuntimeId" : 6637 - }, - { - "id" : "minecraft:smooth_red_sandstone_stairs", - "blockRuntimeId" : 6895 - }, - { - "id" : "minecraft:granite_stairs", - "blockRuntimeId" : 4989 - }, - { - "id" : "minecraft:polished_granite_stairs", - "blockRuntimeId" : 6386 - }, - { - "id" : "minecraft:diorite_stairs", - "blockRuntimeId" : 4476 - }, - { - "id" : "minecraft:polished_diorite_stairs", - "blockRuntimeId" : 6378 - }, - { - "id" : "minecraft:andesite_stairs", - "blockRuntimeId" : 144 - }, - { - "id" : "minecraft:polished_andesite_stairs", - "blockRuntimeId" : 5814 - }, - { - "id" : "minecraft:brick_stairs", - "blockRuntimeId" : 876 - }, - { - "id" : "minecraft:nether_brick_stairs", - "blockRuntimeId" : 5690 - }, - { - "id" : "minecraft:red_nether_brick_stairs", - "blockRuntimeId" : 6625 - }, - { - "id" : "minecraft:end_brick_stairs", - "blockRuntimeId" : 4720 - }, - { - "id" : "minecraft:quartz_stairs", - "blockRuntimeId" : 6559 - }, - { - "id" : "minecraft:smooth_quartz_stairs", - "blockRuntimeId" : 6887 - }, - { - "id" : "minecraft:purpur_stairs", - "blockRuntimeId" : 6537 - }, - { - "id" : "minecraft:prismarine_stairs", - "blockRuntimeId" : 6449 - }, - { - "id" : "minecraft:dark_prismarine_stairs", - "blockRuntimeId" : 4037 - }, - { - "id" : "minecraft:prismarine_bricks_stairs", - "blockRuntimeId" : 6441 - }, - { - "id" : "minecraft:crimson_stairs", - "blockRuntimeId" : 3860 - }, - { - "id" : "minecraft:warped_stairs", - "blockRuntimeId" : 7618 - }, - { - "id" : "minecraft:blackstone_stairs", - "blockRuntimeId" : 499 - }, - { - "id" : "minecraft:polished_blackstone_stairs", - "blockRuntimeId" : 6033 - }, - { - "id" : "minecraft:polished_blackstone_brick_stairs", - "blockRuntimeId" : 5830 - }, - { - "id" : "minecraft:cut_copper_stairs", - "blockRuntimeId" : 3913 - }, - { - "id" : "minecraft:exposed_cut_copper_stairs", - "blockRuntimeId" : 4756 - }, - { - "id" : "minecraft:weathered_cut_copper_stairs", - "blockRuntimeId" : 7745 - }, - { - "id" : "minecraft:oxidized_cut_copper_stairs", - "blockRuntimeId" : 5758 - }, - { - "id" : "minecraft:waxed_cut_copper_stairs", - "blockRuntimeId" : 7689 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_stairs", - "blockRuntimeId" : 7703 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_stairs", - "blockRuntimeId" : 7731 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_stairs", - "blockRuntimeId" : 7717 - }, - { - "id" : "minecraft:cobbled_deepslate_stairs", - "blockRuntimeId" : 1148 - }, - { - "id" : "minecraft:deepslate_tile_stairs", "blockRuntimeId" : 4290 }, + { + "id" : "minecraft:crimson_fence", + "blockRuntimeId" : 7996 + }, + { + "id" : "minecraft:warped_fence", + "blockRuntimeId" : 5853 + }, + { + "id" : "minecraft:fence_gate", + "blockRuntimeId" : 76 + }, + { + "id" : "minecraft:spruce_fence_gate", + "blockRuntimeId" : 6584 + }, + { + "id" : "minecraft:birch_fence_gate", + "blockRuntimeId" : 3777 + }, + { + "id" : "minecraft:jungle_fence_gate", + "blockRuntimeId" : 5365 + }, + { + "id" : "minecraft:acacia_fence_gate", + "blockRuntimeId" : 7586 + }, + { + "id" : "minecraft:dark_oak_fence_gate", + "blockRuntimeId" : 4173 + }, + { + "id" : "minecraft:mangrove_fence_gate", + "blockRuntimeId" : 4625 + }, + { + "id" : "minecraft:crimson_fence_gate", + "blockRuntimeId" : 4661 + }, + { + "id" : "minecraft:warped_fence_gate", + "blockRuntimeId" : 5399 + }, + { + "id" : "minecraft:normal_stone_stairs", + "blockRuntimeId" : 633 + }, + { + "id" : "minecraft:stone_stairs", + "blockRuntimeId" : 3708 + }, + { + "id" : "minecraft:mossy_cobblestone_stairs", + "blockRuntimeId" : 4092 + }, + { + "id" : "minecraft:oak_stairs", + "blockRuntimeId" : 273 + }, + { + "id" : "minecraft:spruce_stairs", + "blockRuntimeId" : 128 + }, + { + "id" : "minecraft:birch_stairs", + "blockRuntimeId" : 7003 + }, + { + "id" : "minecraft:jungle_stairs", + "blockRuntimeId" : 6967 + }, + { + "id" : "minecraft:acacia_stairs", + "blockRuntimeId" : 6200 + }, + { + "id" : "minecraft:dark_oak_stairs", + "blockRuntimeId" : 5063 + }, + { + "id" : "minecraft:mangrove_stairs", + "blockRuntimeId" : 4595 + }, + { + "id" : "minecraft:stone_brick_stairs", + "blockRuntimeId" : 931 + }, + { + "id" : "minecraft:mossy_stone_brick_stairs", + "blockRuntimeId" : 5883 + }, + { + "id" : "minecraft:sandstone_stairs", + "blockRuntimeId" : 3587 + }, + { + "id" : "minecraft:smooth_sandstone_stairs", + "blockRuntimeId" : 3627 + }, + { + "id" : "minecraft:red_sandstone_stairs", + "blockRuntimeId" : 5350 + }, + { + "id" : "minecraft:smooth_red_sandstone_stairs", + "blockRuntimeId" : 5546 + }, + { + "id" : "minecraft:granite_stairs", + "blockRuntimeId" : 3537 + }, + { + "id" : "minecraft:polished_granite_stairs", + "blockRuntimeId" : 4150 + }, + { + "id" : "minecraft:diorite_stairs", + "blockRuntimeId" : 4391 + }, + { + "id" : "minecraft:polished_diorite_stairs", + "blockRuntimeId" : 6714 + }, + { + "id" : "minecraft:andesite_stairs", + "blockRuntimeId" : 5308 + }, + { + "id" : "minecraft:polished_andesite_stairs", + "blockRuntimeId" : 7028 + }, + { + "id" : "minecraft:brick_stairs", + "blockRuntimeId" : 6530 + }, + { + "id" : "minecraft:nether_brick_stairs", + "blockRuntimeId" : 106 + }, + { + "id" : "minecraft:red_nether_brick_stairs", + "blockRuntimeId" : 6602 + }, + { + "id" : "minecraft:end_brick_stairs", + "blockRuntimeId" : 6382 + }, + { + "id" : "minecraft:quartz_stairs", + "blockRuntimeId" : 4767 + }, + { + "id" : "minecraft:smooth_quartz_stairs", + "blockRuntimeId" : 7700 + }, + { + "id" : "minecraft:purpur_stairs", + "blockRuntimeId" : 7755 + }, + { + "id" : "minecraft:prismarine_stairs", + "blockRuntimeId" : 7263 + }, + { + "id" : "minecraft:dark_prismarine_stairs", + "blockRuntimeId" : 7430 + }, + { + "id" : "minecraft:prismarine_bricks_stairs", + "blockRuntimeId" : 206 + }, + { + "id" : "minecraft:crimson_stairs", + "blockRuntimeId" : 6280 + }, + { + "id" : "minecraft:warped_stairs", + "blockRuntimeId" : 3718 + }, + { + "id" : "minecraft:blackstone_stairs", + "blockRuntimeId" : 7019 + }, + { + "id" : "minecraft:polished_blackstone_stairs", + "blockRuntimeId" : 4297 + }, + { + "id" : "minecraft:polished_blackstone_brick_stairs", + "blockRuntimeId" : 4477 + }, + { + "id" : "minecraft:cut_copper_stairs", + "blockRuntimeId" : 4604 + }, + { + "id" : "minecraft:exposed_cut_copper_stairs", + "blockRuntimeId" : 4587 + }, + { + "id" : "minecraft:weathered_cut_copper_stairs", + "blockRuntimeId" : 4305 + }, + { + "id" : "minecraft:oxidized_cut_copper_stairs", + "blockRuntimeId" : 351 + }, + { + "id" : "minecraft:waxed_cut_copper_stairs", + "blockRuntimeId" : 393 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_stairs", + "blockRuntimeId" : 3902 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_stairs", + "blockRuntimeId" : 6167 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper_stairs", + "blockRuntimeId" : 5840 + }, + { + "id" : "minecraft:cobbled_deepslate_stairs", + "blockRuntimeId" : 147 + }, + { + "id" : "minecraft:deepslate_tile_stairs", + "blockRuntimeId" : 4653 + }, { "id" : "minecraft:polished_deepslate_stairs", - "blockRuntimeId" : 6208 + "blockRuntimeId" : 294 }, { "id" : "minecraft:deepslate_brick_stairs", - "blockRuntimeId" : 4107 + "blockRuntimeId" : 7422 + }, + { + "id" : "minecraft:mud_brick_stairs", + "blockRuntimeId" : 5522 }, { "id" : "minecraft:wooden_door" @@ -394,6 +418,9 @@ { "id" : "minecraft:dark_oak_door" }, + { + "id" : "minecraft:mangrove_door" + }, { "id" : "minecraft:iron_door" }, @@ -405,771 +432,771 @@ }, { "id" : "minecraft:trapdoor", - "blockRuntimeId" : 7363 + "blockRuntimeId" : 229 }, { "id" : "minecraft:spruce_trapdoor", - "blockRuntimeId" : 7066 + "blockRuntimeId" : 6552 }, { "id" : "minecraft:birch_trapdoor", - "blockRuntimeId" : 456 + "blockRuntimeId" : 6650 }, { "id" : "minecraft:jungle_trapdoor", - "blockRuntimeId" : 5309 + "blockRuntimeId" : 5381 }, { "id" : "minecraft:acacia_trapdoor", - "blockRuntimeId" : 100 + "blockRuntimeId" : 5589 }, { "id" : "minecraft:dark_oak_trapdoor", - "blockRuntimeId" : 4021 + "blockRuntimeId" : 7502 + }, + { + "id" : "minecraft:mangrove_trapdoor", + "blockRuntimeId" : 4485 }, { "id" : "minecraft:iron_trapdoor", - "blockRuntimeId" : 5168 + "blockRuntimeId" : 321 }, { "id" : "minecraft:crimson_trapdoor", - "blockRuntimeId" : 3887 + "blockRuntimeId" : 4333 }, { "id" : "minecraft:warped_trapdoor", - "blockRuntimeId" : 7645 + "blockRuntimeId" : 4733 }, { "id" : "minecraft:iron_bars", - "blockRuntimeId" : 5133 + "blockRuntimeId" : 4801 }, { "id" : "minecraft:glass", - "blockRuntimeId" : 4883 + "blockRuntimeId" : 6164 }, { "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7088 + "blockRuntimeId" : 1133 }, { "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7096 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7095 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7103 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7100 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7102 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7089 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7092 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7093 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7101 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7097 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7091 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7099 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7098 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7090 - }, - { - "id" : "minecraft:stained_glass", - "blockRuntimeId" : 7094 - }, - { - "id" : "minecraft:tinted_glass", - "blockRuntimeId" : 7352 - }, - { - "id" : "minecraft:glass_pane", - "blockRuntimeId" : 4884 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7104 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7112 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7111 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7119 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7116 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7118 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7105 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7108 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7109 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7117 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7113 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7107 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7115 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7114 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7106 - }, - { - "id" : "minecraft:stained_glass_pane", - "blockRuntimeId" : 7110 - }, - { - "id" : "minecraft:ladder", - "blockRuntimeId" : 5357 - }, - { - "id" : "minecraft:scaffolding", - "blockRuntimeId" : 6730 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7223 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7273 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7226 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7244 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7903 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7904 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7905 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7906 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7907 - }, - { - "id" : "minecraft:wooden_slab", - "blockRuntimeId" : 7908 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7228 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7271 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7224 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7274 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7245 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7239 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7275 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7256 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7261 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7262 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7259 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7260 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7258 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7257 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7227 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7230 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7246 - }, - { - "id" : "minecraft:double_stone_slab3", - "blockRuntimeId" : 7255 - }, - { - "id" : "minecraft:double_stone_slab", - "blockRuntimeId" : 7229 - }, - { - "id" : "minecraft:double_stone_slab4", - "blockRuntimeId" : 7272 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7240 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7241 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7242 - }, - { - "id" : "minecraft:double_stone_slab2", - "blockRuntimeId" : 7243 - }, - { - "id" : "minecraft:crimson_slab", - "blockRuntimeId" : 3858 - }, - { - "id" : "minecraft:warped_slab", - "blockRuntimeId" : 7616 - }, - { - "id" : "minecraft:blackstone_slab", - "blockRuntimeId" : 497 - }, - { - "id" : "minecraft:polished_blackstone_slab", - "blockRuntimeId" : 6031 - }, - { - "id" : "minecraft:polished_blackstone_brick_slab", - "blockRuntimeId" : 5828 - }, - { - "id" : "minecraft:cut_copper_slab", - "blockRuntimeId" : 3911 - }, - { - "id" : "minecraft:exposed_cut_copper_slab", - "blockRuntimeId" : 4754 - }, - { - "id" : "minecraft:weathered_cut_copper_slab", - "blockRuntimeId" : 7743 - }, - { - "id" : "minecraft:oxidized_cut_copper_slab", - "blockRuntimeId" : 5756 - }, - { - "id" : "minecraft:waxed_cut_copper_slab", - "blockRuntimeId" : 7687 - }, - { - "id" : "minecraft:waxed_exposed_cut_copper_slab", - "blockRuntimeId" : 7701 - }, - { - "id" : "minecraft:waxed_weathered_cut_copper_slab", - "blockRuntimeId" : 7729 - }, - { - "id" : "minecraft:waxed_oxidized_cut_copper_slab", - "blockRuntimeId" : 7715 - }, - { - "id" : "minecraft:cobbled_deepslate_slab", - "blockRuntimeId" : 1146 - }, - { - "id" : "minecraft:polished_deepslate_slab", - "blockRuntimeId" : 6206 - }, - { - "id" : "minecraft:deepslate_tile_slab", - "blockRuntimeId" : 4288 - }, - { - "id" : "minecraft:deepslate_brick_slab", - "blockRuntimeId" : 4105 - }, - { - "id" : "minecraft:brick_block", - "blockRuntimeId" : 875 - }, - { - "id" : "minecraft:chiseled_nether_bricks", - "blockRuntimeId" : 1130 - }, - { - "id" : "minecraft:cracked_nether_bricks", - "blockRuntimeId" : 3769 - }, - { - "id" : "minecraft:quartz_bricks", - "blockRuntimeId" : 6557 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7289 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7290 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7291 - }, - { - "id" : "minecraft:stonebrick", - "blockRuntimeId" : 7292 - }, - { - "id" : "minecraft:end_bricks", - "blockRuntimeId" : 4728 - }, - { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6440 - }, - { - "id" : "minecraft:polished_blackstone_bricks", - "blockRuntimeId" : 6000 - }, - { - "id" : "minecraft:cracked_polished_blackstone_bricks", - "blockRuntimeId" : 3770 - }, - { - "id" : "minecraft:gilded_blackstone", - "blockRuntimeId" : 4882 - }, - { - "id" : "minecraft:chiseled_polished_blackstone", - "blockRuntimeId" : 1131 - }, - { - "id" : "minecraft:deepslate_tiles", - "blockRuntimeId" : 4460 - }, - { - "id" : "minecraft:cracked_deepslate_tiles", - "blockRuntimeId" : 3768 - }, - { - "id" : "minecraft:deepslate_bricks", - "blockRuntimeId" : 4277 - }, - { - "id" : "minecraft:cracked_deepslate_bricks", - "blockRuntimeId" : 3767 - }, - { - "id" : "minecraft:chiseled_deepslate", - "blockRuntimeId" : 1129 - }, - { - "id" : "minecraft:cobblestone", - "blockRuntimeId" : 1318 - }, - { - "id" : "minecraft:mossy_cobblestone", - "blockRuntimeId" : 5667 - }, - { - "id" : "minecraft:cobbled_deepslate", - "blockRuntimeId" : 1143 - }, - { - "id" : "minecraft:smooth_stone", - "blockRuntimeId" : 6911 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6706 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6707 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6708 - }, - { - "id" : "minecraft:sandstone", - "blockRuntimeId" : 6709 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6633 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6634 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6635 - }, - { - "id" : "minecraft:red_sandstone", - "blockRuntimeId" : 6636 - }, - { - "id" : "minecraft:coal_block", "blockRuntimeId" : 1141 }, { - "id" : "minecraft:dried_kelp_block", - "blockRuntimeId" : 4584 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1140 }, { - "id" : "minecraft:gold_block", - "blockRuntimeId" : 4975 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1148 }, { - "id" : "minecraft:iron_block", - "blockRuntimeId" : 5134 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1145 }, { - "id" : "minecraft:copper_block", - "blockRuntimeId" : 3677 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1147 }, { - "id" : "minecraft:exposed_copper", - "blockRuntimeId" : 4752 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1134 }, { - "id" : "minecraft:weathered_copper", - "blockRuntimeId" : 7741 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1137 }, { - "id" : "minecraft:oxidized_copper", - "blockRuntimeId" : 5754 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1138 }, { - "id" : "minecraft:waxed_copper", - "blockRuntimeId" : 7685 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1146 }, { - "id" : "minecraft:waxed_exposed_copper", - "blockRuntimeId" : 7699 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1142 }, { - "id" : "minecraft:waxed_weathered_copper", - "blockRuntimeId" : 7727 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1136 }, { - "id" : "minecraft:waxed_oxidized_copper", - "blockRuntimeId" : 7713 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1144 }, { - "id" : "minecraft:cut_copper", - "blockRuntimeId" : 3910 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1143 }, { - "id" : "minecraft:exposed_cut_copper", - "blockRuntimeId" : 4753 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1135 }, { - "id" : "minecraft:weathered_cut_copper", - "blockRuntimeId" : 7742 + "id" : "minecraft:stained_glass", + "blockRuntimeId" : 1139 }, { - "id" : "minecraft:oxidized_cut_copper", - "blockRuntimeId" : 5755 + "id" : "minecraft:tinted_glass", + "blockRuntimeId" : 5975 }, { - "id" : "minecraft:waxed_cut_copper", - "blockRuntimeId" : 7686 + "id" : "minecraft:glass_pane", + "blockRuntimeId" : 5233 }, { - "id" : "minecraft:waxed_exposed_cut_copper", - "blockRuntimeId" : 7700 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4852 }, { - "id" : "minecraft:waxed_weathered_cut_copper", - "blockRuntimeId" : 7728 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4860 }, { - "id" : "minecraft:waxed_oxidized_cut_copper", - "blockRuntimeId" : 7714 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4859 }, { - "id" : "minecraft:emerald_block", - "blockRuntimeId" : 4717 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4867 }, { - "id" : "minecraft:diamond_block", - "blockRuntimeId" : 4474 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4864 }, { - "id" : "minecraft:lapis_block", - "blockRuntimeId" : 5365 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4866 }, { - "id" : "minecraft:raw_iron_block", - "blockRuntimeId" : 6579 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4853 }, { - "id" : "minecraft:raw_copper_block", - "blockRuntimeId" : 6577 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4856 }, { - "id" : "minecraft:raw_gold_block", - "blockRuntimeId" : 6578 + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4857 }, { - "id" : "minecraft:quartz_block", + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4865 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4861 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4855 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4863 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4862 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4854 + }, + { + "id" : "minecraft:stained_glass_pane", + "blockRuntimeId" : 4858 + }, + { + "id" : "minecraft:ladder", + "blockRuntimeId" : 8262 + }, + { + "id" : "minecraft:scaffolding", + "blockRuntimeId" : 3571 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4270 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5822 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4273 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5793 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5270 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5271 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5272 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5273 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5274 + }, + { + "id" : "minecraft:wooden_slab", + "blockRuntimeId" : 5275 + }, + { + "id" : "minecraft:mangrove_slab", + "blockRuntimeId" : 1149 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4275 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5820 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4271 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5823 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5794 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5788 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5824 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5805 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5810 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5811 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5808 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5809 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5807 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5806 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4274 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4277 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5795 + }, + { + "id" : "minecraft:stone_block_slab3", + "blockRuntimeId" : 5804 + }, + { + "id" : "minecraft:stone_block_slab", + "blockRuntimeId" : 4276 + }, + { + "id" : "minecraft:stone_block_slab4", + "blockRuntimeId" : 5821 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5789 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5790 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5791 + }, + { + "id" : "minecraft:stone_block_slab2", + "blockRuntimeId" : 5792 + }, + { + "id" : "minecraft:crimson_slab", + "blockRuntimeId" : 5900 + }, + { + "id" : "minecraft:warped_slab", + "blockRuntimeId" : 6484 + }, + { + "id" : "minecraft:blackstone_slab", + "blockRuntimeId" : 910 + }, + { + "id" : "minecraft:polished_blackstone_slab", + "blockRuntimeId" : 6018 + }, + { + "id" : "minecraft:polished_blackstone_brick_slab", + "blockRuntimeId" : 4192 + }, + { + "id" : "minecraft:cut_copper_slab", + "blockRuntimeId" : 5235 + }, + { + "id" : "minecraft:exposed_cut_copper_slab", + "blockRuntimeId" : 6600 + }, + { + "id" : "minecraft:weathered_cut_copper_slab", + "blockRuntimeId" : 6053 + }, + { + "id" : "minecraft:oxidized_cut_copper_slab", + "blockRuntimeId" : 5282 + }, + { + "id" : "minecraft:waxed_cut_copper_slab", + "blockRuntimeId" : 7815 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper_slab", + "blockRuntimeId" : 249 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper_slab", "blockRuntimeId" : 6545 }, { - "id" : "minecraft:quartz_block", + "id" : "minecraft:waxed_oxidized_cut_copper_slab", + "blockRuntimeId" : 708 + }, + { + "id" : "minecraft:cobbled_deepslate_slab", + "blockRuntimeId" : 7310 + }, + { + "id" : "minecraft:polished_deepslate_slab", + "blockRuntimeId" : 288 + }, + { + "id" : "minecraft:deepslate_tile_slab", + "blockRuntimeId" : 4291 + }, + { + "id" : "minecraft:deepslate_brick_slab", + "blockRuntimeId" : 3716 + }, + { + "id" : "minecraft:mud_brick_slab", + "blockRuntimeId" : 3910 + }, + { + "id" : "minecraft:brick_block", + "blockRuntimeId" : 4765 + }, + { + "id" : "minecraft:chiseled_nether_bricks", + "blockRuntimeId" : 7249 + }, + { + "id" : "minecraft:cracked_nether_bricks", + "blockRuntimeId" : 4552 + }, + { + "id" : "minecraft:quartz_bricks", + "blockRuntimeId" : 6351 + }, + { + "id" : "minecraft:stonebrick", "blockRuntimeId" : 6547 }, { - "id" : "minecraft:quartz_block", - "blockRuntimeId" : 6546 - }, - { - "id" : "minecraft:quartz_block", + "id" : "minecraft:stonebrick", "blockRuntimeId" : 6548 }, { - "id" : "minecraft:prismarine", - "blockRuntimeId" : 6438 + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6549 + }, + { + "id" : "minecraft:stonebrick", + "blockRuntimeId" : 6550 + }, + { + "id" : "minecraft:end_bricks", + "blockRuntimeId" : 281 }, { "id" : "minecraft:prismarine", - "blockRuntimeId" : 6439 + "blockRuntimeId" : 6087 + }, + { + "id" : "minecraft:polished_blackstone_bricks", + "blockRuntimeId" : 4680 + }, + { + "id" : "minecraft:cracked_polished_blackstone_bricks", + "blockRuntimeId" : 7214 + }, + { + "id" : "minecraft:gilded_blackstone", + "blockRuntimeId" : 4586 + }, + { + "id" : "minecraft:chiseled_polished_blackstone", + "blockRuntimeId" : 5062 + }, + { + "id" : "minecraft:deepslate_tiles", + "blockRuntimeId" : 4581 + }, + { + "id" : "minecraft:cracked_deepslate_tiles", + "blockRuntimeId" : 4160 + }, + { + "id" : "minecraft:deepslate_bricks", + "blockRuntimeId" : 5464 + }, + { + "id" : "minecraft:cracked_deepslate_bricks", + "blockRuntimeId" : 5364 + }, + { + "id" : "minecraft:chiseled_deepslate", + "blockRuntimeId" : 5234 + }, + { + "id" : "minecraft:cobblestone", + "blockRuntimeId" : 3615 + }, + { + "id" : "minecraft:mossy_cobblestone", + "blockRuntimeId" : 252 + }, + { + "id" : "minecraft:cobbled_deepslate", + "blockRuntimeId" : 6670 + }, + { + "id" : "minecraft:smooth_stone", + "blockRuntimeId" : 4582 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3653 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3654 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3655 + }, + { + "id" : "minecraft:sandstone", + "blockRuntimeId" : 3656 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6580 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6581 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6582 + }, + { + "id" : "minecraft:red_sandstone", + "blockRuntimeId" : 6583 + }, + { + "id" : "minecraft:coal_block", + "blockRuntimeId" : 5398 + }, + { + "id" : "minecraft:dried_kelp_block", + "blockRuntimeId" : 7979 + }, + { + "id" : "minecraft:gold_block", + "blockRuntimeId" : 291 + }, + { + "id" : "minecraft:iron_block", + "blockRuntimeId" : 8261 + }, + { + "id" : "minecraft:copper_block", + "blockRuntimeId" : 4651 + }, + { + "id" : "minecraft:exposed_copper", + "blockRuntimeId" : 593 + }, + { + "id" : "minecraft:weathered_copper", + "blockRuntimeId" : 8246 + }, + { + "id" : "minecraft:oxidized_copper", + "blockRuntimeId" : 3553 + }, + { + "id" : "minecraft:waxed_copper", + "blockRuntimeId" : 7734 + }, + { + "id" : "minecraft:waxed_exposed_copper", + "blockRuntimeId" : 694 + }, + { + "id" : "minecraft:waxed_weathered_copper", + "blockRuntimeId" : 707 + }, + { + "id" : "minecraft:waxed_oxidized_copper", + "blockRuntimeId" : 7542 + }, + { + "id" : "minecraft:cut_copper", + "blockRuntimeId" : 4689 + }, + { + "id" : "minecraft:exposed_cut_copper", + "blockRuntimeId" : 6166 + }, + { + "id" : "minecraft:weathered_cut_copper", + "blockRuntimeId" : 7197 + }, + { + "id" : "minecraft:oxidized_cut_copper", + "blockRuntimeId" : 5478 + }, + { + "id" : "minecraft:waxed_cut_copper", + "blockRuntimeId" : 7293 + }, + { + "id" : "minecraft:waxed_exposed_cut_copper", + "blockRuntimeId" : 3809 + }, + { + "id" : "minecraft:waxed_weathered_cut_copper", + "blockRuntimeId" : 4851 + }, + { + "id" : "minecraft:waxed_oxidized_cut_copper", + "blockRuntimeId" : 214 + }, + { + "id" : "minecraft:emerald_block", + "blockRuntimeId" : 1159 + }, + { + "id" : "minecraft:diamond_block", + "blockRuntimeId" : 272 + }, + { + "id" : "minecraft:lapis_block", + "blockRuntimeId" : 4286 + }, + { + "id" : "minecraft:raw_iron_block", + "blockRuntimeId" : 8260 + }, + { + "id" : "minecraft:raw_copper_block", + "blockRuntimeId" : 5269 + }, + { + "id" : "minecraft:raw_gold_block", + "blockRuntimeId" : 361 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3696 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3698 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3697 + }, + { + "id" : "minecraft:quartz_block", + "blockRuntimeId" : 3699 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6085 + }, + { + "id" : "minecraft:prismarine", + "blockRuntimeId" : 6086 }, { "id" : "minecraft:slime", - "blockRuntimeId" : 6864 + "blockRuntimeId" : 4233 }, { "id" : "minecraft:honey_block", - "blockRuntimeId" : 5112 + "blockRuntimeId" : 892 }, { "id" : "minecraft:honeycomb_block", - "blockRuntimeId" : 5113 + "blockRuntimeId" : 4476 }, { "id" : "minecraft:hay_block", - "blockRuntimeId" : 5084 + "blockRuntimeId" : 695 }, { "id" : "minecraft:bone_block", - "blockRuntimeId" : 692 + "blockRuntimeId" : 4234 }, { "id" : "minecraft:nether_brick", - "blockRuntimeId" : 5688 + "blockRuntimeId" : 7272 }, { "id" : "minecraft:red_nether_brick", - "blockRuntimeId" : 6624 + "blockRuntimeId" : 146 }, { "id" : "minecraft:netherite_block", - "blockRuntimeId" : 5705 + "blockRuntimeId" : 3775 }, { "id" : "minecraft:lodestone", - "blockRuntimeId" : 5563 + "blockRuntimeId" : 8259 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7915 + "blockRuntimeId" : 3458 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7923 + "blockRuntimeId" : 3466 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7922 + "blockRuntimeId" : 3465 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7930 + "blockRuntimeId" : 3473 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7927 + "blockRuntimeId" : 3470 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7929 + "blockRuntimeId" : 3472 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7916 + "blockRuntimeId" : 3459 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7919 + "blockRuntimeId" : 3462 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7920 + "blockRuntimeId" : 3463 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7928 + "blockRuntimeId" : 3471 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7924 + "blockRuntimeId" : 3467 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7918 + "blockRuntimeId" : 3461 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7926 + "blockRuntimeId" : 3469 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7925 + "blockRuntimeId" : 3468 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7917 + "blockRuntimeId" : 3460 }, { "id" : "minecraft:wool", - "blockRuntimeId" : 7921 + "blockRuntimeId" : 3464 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 963 + "blockRuntimeId" : 949 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 971 + "blockRuntimeId" : 957 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 970 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 978 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 975 - }, - { - "id" : "minecraft:carpet", - "blockRuntimeId" : 977 + "blockRuntimeId" : 956 }, { "id" : "minecraft:carpet", @@ -1177,699 +1204,747 @@ }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 967 + "blockRuntimeId" : 961 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 968 + "blockRuntimeId" : 963 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 976 + "blockRuntimeId" : 950 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 972 + "blockRuntimeId" : 953 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 966 + "blockRuntimeId" : 954 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 974 + "blockRuntimeId" : 962 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 973 + "blockRuntimeId" : 958 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 965 + "blockRuntimeId" : 952 }, { "id" : "minecraft:carpet", - "blockRuntimeId" : 969 + "blockRuntimeId" : 960 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 959 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 951 + }, + { + "id" : "minecraft:carpet", + "blockRuntimeId" : 955 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3660 + "blockRuntimeId" : 6264 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3668 + "blockRuntimeId" : 6272 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3667 + "blockRuntimeId" : 6271 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3675 + "blockRuntimeId" : 6279 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3672 + "blockRuntimeId" : 6276 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3674 + "blockRuntimeId" : 6278 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3661 + "blockRuntimeId" : 6265 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3664 + "blockRuntimeId" : 6268 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3665 + "blockRuntimeId" : 6269 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3673 + "blockRuntimeId" : 6277 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3669 + "blockRuntimeId" : 6273 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3663 + "blockRuntimeId" : 6267 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3671 + "blockRuntimeId" : 6275 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3670 + "blockRuntimeId" : 6274 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3662 + "blockRuntimeId" : 6266 }, { "id" : "minecraft:concrete_powder", - "blockRuntimeId" : 3666 + "blockRuntimeId" : 6270 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3644 + "blockRuntimeId" : 660 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3652 + "blockRuntimeId" : 668 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3651 + "blockRuntimeId" : 667 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3659 + "blockRuntimeId" : 675 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3656 + "blockRuntimeId" : 672 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3658 + "blockRuntimeId" : 674 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3645 + "blockRuntimeId" : 661 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3648 + "blockRuntimeId" : 664 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3649 + "blockRuntimeId" : 665 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3657 + "blockRuntimeId" : 673 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3653 + "blockRuntimeId" : 669 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3647 + "blockRuntimeId" : 663 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3655 + "blockRuntimeId" : 671 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3654 + "blockRuntimeId" : 670 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3646 + "blockRuntimeId" : 662 }, { "id" : "minecraft:concrete", - "blockRuntimeId" : 3650 + "blockRuntimeId" : 666 }, { "id" : "minecraft:clay", - "blockRuntimeId" : 1139 - }, - { - "id" : "minecraft:hardened_clay", - "blockRuntimeId" : 5083 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7120 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7128 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7127 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7135 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7132 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7134 - }, - { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7121 - }, - { - "id" : "minecraft:stained_hardened_clay", "blockRuntimeId" : 7124 }, { - "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7125 + "id" : "minecraft:hardened_clay", + "blockRuntimeId" : 641 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7133 + "blockRuntimeId" : 6176 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7129 + "blockRuntimeId" : 6184 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7123 + "blockRuntimeId" : 6183 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7131 + "blockRuntimeId" : 6191 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7130 + "blockRuntimeId" : 6188 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7122 + "blockRuntimeId" : 6190 }, { "id" : "minecraft:stained_hardened_clay", - "blockRuntimeId" : 7126 + "blockRuntimeId" : 6177 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6180 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6181 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6189 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6185 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6179 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6187 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6186 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6178 + }, + { + "id" : "minecraft:stained_hardened_clay", + "blockRuntimeId" : 6182 }, { "id" : "minecraft:white_glazed_terracotta", - "blockRuntimeId" : 7800 + "blockRuntimeId" : 5573 }, { "id" : "minecraft:silver_glazed_terracotta", - "blockRuntimeId" : 6846 + "blockRuntimeId" : 3531 }, { "id" : "minecraft:gray_glazed_terracotta", - "blockRuntimeId" : 5010 + "blockRuntimeId" : 8253 }, { "id" : "minecraft:black_glazed_terracotta", - "blockRuntimeId" : 488 + "blockRuntimeId" : 5834 }, { "id" : "minecraft:brown_glazed_terracotta", - "blockRuntimeId" : 894 + "blockRuntimeId" : 3547 }, { "id" : "minecraft:red_glazed_terracotta", - "blockRuntimeId" : 6601 + "blockRuntimeId" : 4167 }, { "id" : "minecraft:orange_glazed_terracotta", - "blockRuntimeId" : 5748 + "blockRuntimeId" : 1151 }, { "id" : "minecraft:yellow_glazed_terracotta", - "blockRuntimeId" : 7942 + "blockRuntimeId" : 913 }, { "id" : "minecraft:lime_glazed_terracotta", - "blockRuntimeId" : 5532 + "blockRuntimeId" : 223 }, { "id" : "minecraft:green_glazed_terracotta", - "blockRuntimeId" : 5026 + "blockRuntimeId" : 6610 }, { "id" : "minecraft:cyan_glazed_terracotta", - "blockRuntimeId" : 3931 + "blockRuntimeId" : 5358 }, { "id" : "minecraft:light_blue_glazed_terracotta", - "blockRuntimeId" : 5484 + "blockRuntimeId" : 5471 }, { "id" : "minecraft:blue_glazed_terracotta", - "blockRuntimeId" : 685 + "blockRuntimeId" : 5465 }, { "id" : "minecraft:purple_glazed_terracotta", - "blockRuntimeId" : 6519 + "blockRuntimeId" : 7011 }, { "id" : "minecraft:magenta_glazed_terracotta", - "blockRuntimeId" : 5596 + "blockRuntimeId" : 965 }, { "id" : "minecraft:pink_glazed_terracotta", - "blockRuntimeId" : 5779 + "blockRuntimeId" : 6539 }, { "id" : "minecraft:purpur_block", - "blockRuntimeId" : 6525 + "blockRuntimeId" : 7714 }, { "id" : "minecraft:purpur_block", - "blockRuntimeId" : 6527 + "blockRuntimeId" : 7716 + }, + { + "id" : "minecraft:packed_mud", + "blockRuntimeId" : 283 + }, + { + "id" : "minecraft:mud_bricks", + "blockRuntimeId" : 6889 }, { "id" : "minecraft:nether_wart_block", - "blockRuntimeId" : 5704 + "blockRuntimeId" : 4293 }, { "id" : "minecraft:warped_wart_block", - "blockRuntimeId" : 7667 + "blockRuntimeId" : 5905 }, { "id" : "minecraft:shroomlight", - "blockRuntimeId" : 6829 + "blockRuntimeId" : 5061 }, { "id" : "minecraft:crimson_nylium", - "blockRuntimeId" : 3839 + "blockRuntimeId" : 4189 }, { "id" : "minecraft:warped_nylium", - "blockRuntimeId" : 7597 + "blockRuntimeId" : 6349 }, { "id" : "minecraft:basalt", - "blockRuntimeId" : 214 + "blockRuntimeId" : 4349 }, { "id" : "minecraft:polished_basalt", - "blockRuntimeId" : 5822 + "blockRuntimeId" : 24 }, { "id" : "minecraft:smooth_basalt", - "blockRuntimeId" : 6886 + "blockRuntimeId" : 1157 }, { "id" : "minecraft:soul_soil", - "blockRuntimeId" : 6956 + "blockRuntimeId" : 5830 }, { "id" : "minecraft:dirt", - "blockRuntimeId" : 4484 + "blockRuntimeId" : 5751 }, { "id" : "minecraft:dirt", - "blockRuntimeId" : 4485 + "blockRuntimeId" : 5752 }, { "id" : "minecraft:farmland", - "blockRuntimeId" : 4766 + "blockRuntimeId" : 3912 }, { "id" : "minecraft:grass", - "blockRuntimeId" : 4997 + "blockRuntimeId" : 6975 }, { "id" : "minecraft:grass_path", - "blockRuntimeId" : 4998 + "blockRuntimeId" : 8081 }, { "id" : "minecraft:podzol", - "blockRuntimeId" : 5803 + "blockRuntimeId" : 4650 }, { "id" : "minecraft:mycelium", - "blockRuntimeId" : 5685 + "blockRuntimeId" : 3683 + }, + { + "id" : "minecraft:mud", + "blockRuntimeId" : 6684 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7180 + "blockRuntimeId" : 653 }, { "id" : "minecraft:iron_ore", - "blockRuntimeId" : 5167 + "blockRuntimeId" : 4690 }, { "id" : "minecraft:gold_ore", - "blockRuntimeId" : 4976 + "blockRuntimeId" : 912 }, { "id" : "minecraft:diamond_ore", - "blockRuntimeId" : 4475 + "blockRuntimeId" : 4361 }, { "id" : "minecraft:lapis_ore", - "blockRuntimeId" : 5366 + "blockRuntimeId" : 7699 }, { "id" : "minecraft:redstone_ore", - "blockRuntimeId" : 6647 + "blockRuntimeId" : 4289 }, { "id" : "minecraft:coal_ore", - "blockRuntimeId" : 1142 + "blockRuntimeId" : 4287 }, { "id" : "minecraft:copper_ore", - "blockRuntimeId" : 3678 + "blockRuntimeId" : 3554 }, { "id" : "minecraft:emerald_ore", - "blockRuntimeId" : 4718 + "blockRuntimeId" : 7347 }, { "id" : "minecraft:quartz_ore", - "blockRuntimeId" : 6558 + "blockRuntimeId" : 4501 }, { "id" : "minecraft:nether_gold_ore", - "blockRuntimeId" : 5698 + "blockRuntimeId" : 27 }, { "id" : "minecraft:ancient_debris", - "blockRuntimeId" : 143 + "blockRuntimeId" : 6107 }, { "id" : "minecraft:deepslate_iron_ore", - "blockRuntimeId" : 4283 + "blockRuntimeId" : 7273 }, { "id" : "minecraft:deepslate_gold_ore", - "blockRuntimeId" : 4282 + "blockRuntimeId" : 6106 }, { "id" : "minecraft:deepslate_diamond_ore", - "blockRuntimeId" : 4280 + "blockRuntimeId" : 8038 }, { "id" : "minecraft:deepslate_lapis_ore", - "blockRuntimeId" : 4284 + "blockRuntimeId" : 7262 }, { "id" : "minecraft:deepslate_redstone_ore", - "blockRuntimeId" : 4285 + "blockRuntimeId" : 6616 }, { "id" : "minecraft:deepslate_emerald_ore", - "blockRuntimeId" : 4281 + "blockRuntimeId" : 6350 }, { "id" : "minecraft:deepslate_coal_ore", - "blockRuntimeId" : 4278 + "blockRuntimeId" : 7196 }, { "id" : "minecraft:deepslate_copper_ore", - "blockRuntimeId" : 4279 + "blockRuntimeId" : 105 }, { "id" : "minecraft:gravel", - "blockRuntimeId" : 4999 + "blockRuntimeId" : 8287 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7181 + "blockRuntimeId" : 654 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7183 + "blockRuntimeId" : 656 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7185 + "blockRuntimeId" : 658 }, { "id" : "minecraft:blackstone", - "blockRuntimeId" : 494 + "blockRuntimeId" : 7585 }, { "id" : "minecraft:deepslate", - "blockRuntimeId" : 4100 + "blockRuntimeId" : 253 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7182 + "blockRuntimeId" : 655 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7184 + "blockRuntimeId" : 657 }, { "id" : "minecraft:stone", - "blockRuntimeId" : 7186 + "blockRuntimeId" : 659 }, { "id" : "minecraft:polished_blackstone", - "blockRuntimeId" : 5825 + "blockRuntimeId" : 3682 }, { "id" : "minecraft:polished_deepslate", - "blockRuntimeId" : 6203 + "blockRuntimeId" : 7754 }, { "id" : "minecraft:sand", - "blockRuntimeId" : 6704 + "blockRuntimeId" : 4195 }, { "id" : "minecraft:sand", - "blockRuntimeId" : 6705 + "blockRuntimeId" : 4196 }, { "id" : "minecraft:cactus", - "blockRuntimeId" : 920 + "blockRuntimeId" : 6986 }, { "id" : "minecraft:log", - "blockRuntimeId" : 5564 + "blockRuntimeId" : 6672 }, { "id" : "minecraft:stripped_oak_log", - "blockRuntimeId" : 7319 + "blockRuntimeId" : 7543 }, { "id" : "minecraft:log", - "blockRuntimeId" : 5565 + "blockRuntimeId" : 6673 }, { "id" : "minecraft:stripped_spruce_log", - "blockRuntimeId" : 7322 + "blockRuntimeId" : 6288 }, { "id" : "minecraft:log", - "blockRuntimeId" : 5566 + "blockRuntimeId" : 6674 }, { "id" : "minecraft:stripped_birch_log", - "blockRuntimeId" : 7304 + "blockRuntimeId" : 5972 }, { "id" : "minecraft:log", - "blockRuntimeId" : 5567 + "blockRuntimeId" : 6675 }, { "id" : "minecraft:stripped_jungle_log", - "blockRuntimeId" : 7316 + "blockRuntimeId" : 642 }, { "id" : "minecraft:log2", - "blockRuntimeId" : 5576 + "blockRuntimeId" : 3830 }, { "id" : "minecraft:stripped_acacia_log", - "blockRuntimeId" : 7301 + "blockRuntimeId" : 5848 }, { "id" : "minecraft:log2", - "blockRuntimeId" : 5577 + "blockRuntimeId" : 3831 }, { "id" : "minecraft:stripped_dark_oak_log", - "blockRuntimeId" : 7313 + "blockRuntimeId" : 216 + }, + { + "id" : "minecraft:mangrove_log", + "blockRuntimeId" : 348 + }, + { + "id" : "minecraft:stripped_mangrove_log", + "blockRuntimeId" : 8284 }, { "id" : "minecraft:crimson_stem", - "blockRuntimeId" : 3884 + "blockRuntimeId" : 5897 }, { "id" : "minecraft:stripped_crimson_stem", - "blockRuntimeId" : 7310 + "blockRuntimeId" : 6948 }, { "id" : "minecraft:warped_stem", - "blockRuntimeId" : 7642 + "blockRuntimeId" : 6486 }, { "id" : "minecraft:stripped_warped_stem", - "blockRuntimeId" : 7328 + "blockRuntimeId" : 7400 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7807 + "blockRuntimeId" : 3474 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7813 + "blockRuntimeId" : 3480 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7808 + "blockRuntimeId" : 3475 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7814 + "blockRuntimeId" : 3481 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7809 + "blockRuntimeId" : 3476 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7815 + "blockRuntimeId" : 3482 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7810 + "blockRuntimeId" : 3477 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7816 + "blockRuntimeId" : 3483 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7811 + "blockRuntimeId" : 3478 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7817 + "blockRuntimeId" : 3484 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7812 + "blockRuntimeId" : 3479 }, { "id" : "minecraft:wood", - "blockRuntimeId" : 7818 + "blockRuntimeId" : 3485 + }, + { + "id" : "minecraft:mangrove_wood", + "blockRuntimeId" : 4161 + }, + { + "id" : "minecraft:stripped_mangrove_wood", + "blockRuntimeId" : 4229 }, { "id" : "minecraft:crimson_hyphae", - "blockRuntimeId" : 3836 + "blockRuntimeId" : 4294 }, { "id" : "minecraft:stripped_crimson_hyphae", - "blockRuntimeId" : 7307 + "blockRuntimeId" : 6499 }, { "id" : "minecraft:warped_hyphae", - "blockRuntimeId" : 7594 + "blockRuntimeId" : 5902 }, { "id" : "minecraft:stripped_warped_hyphae", - "blockRuntimeId" : 7325 + "blockRuntimeId" : 5579 }, { "id" : "minecraft:leaves", - "blockRuntimeId" : 5410 + "blockRuntimeId" : 6090 }, { "id" : "minecraft:leaves", - "blockRuntimeId" : 5411 + "blockRuntimeId" : 6091 }, { "id" : "minecraft:leaves", - "blockRuntimeId" : 5412 + "blockRuntimeId" : 6092 }, { "id" : "minecraft:leaves", - "blockRuntimeId" : 5413 + "blockRuntimeId" : 6093 }, { "id" : "minecraft:leaves2", - "blockRuntimeId" : 5426 + "blockRuntimeId" : 4353 }, { "id" : "minecraft:leaves2", - "blockRuntimeId" : 5427 + "blockRuntimeId" : 4354 + }, + { + "id" : "minecraft:mangrove_leaves", + "blockRuntimeId" : 6666 }, { "id" : "minecraft:azalea_leaves", - "blockRuntimeId" : 169 + "blockRuntimeId" : 7710 }, { "id" : "minecraft:azalea_leaves_flowered", - "blockRuntimeId" : 173 + "blockRuntimeId" : 6339 }, { "id" : "minecraft:sapling", - "blockRuntimeId" : 6718 + "blockRuntimeId" : 712 }, { "id" : "minecraft:sapling", - "blockRuntimeId" : 6719 + "blockRuntimeId" : 713 }, { "id" : "minecraft:sapling", - "blockRuntimeId" : 6720 + "blockRuntimeId" : 714 }, { "id" : "minecraft:sapling", - "blockRuntimeId" : 6721 + "blockRuntimeId" : 715 }, { "id" : "minecraft:sapling", - "blockRuntimeId" : 6722 + "blockRuntimeId" : 716 }, { "id" : "minecraft:sapling", - "blockRuntimeId" : 6723 + "blockRuntimeId" : 717 + }, + { + "id" : "minecraft:mangrove_propagule", + "blockRuntimeId" : 6976 }, { "id" : "minecraft:bee_nest", - "blockRuntimeId" : 236 + "blockRuntimeId" : 5754 }, { "id" : "minecraft:wheat_seeds" @@ -1912,7 +1987,7 @@ }, { "id" : "minecraft:melon_block", - "blockRuntimeId" : 5609 + "blockRuntimeId" : 392 }, { "id" : "minecraft:melon_slice" @@ -1928,200 +2003,200 @@ }, { "id" : "minecraft:pumpkin", - "blockRuntimeId" : 6457 + "blockRuntimeId" : 4577 }, { "id" : "minecraft:carved_pumpkin", - "blockRuntimeId" : 988 + "blockRuntimeId" : 7378 }, { "id" : "minecraft:lit_pumpkin", - "blockRuntimeId" : 5551 + "blockRuntimeId" : 6685 }, { "id" : "minecraft:honeycomb" }, { "id" : "minecraft:tallgrass", - "blockRuntimeId" : 7349 + "blockRuntimeId" : 929 }, { "id" : "minecraft:double_plant", - "blockRuntimeId" : 4504 + "blockRuntimeId" : 5455 }, { "id" : "minecraft:tallgrass", - "blockRuntimeId" : 7348 + "blockRuntimeId" : 928 }, { "id" : "minecraft:double_plant", - "blockRuntimeId" : 4503 + "blockRuntimeId" : 5454 }, { "id" : "minecraft:nether_sprouts" }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3682 + "blockRuntimeId" : 6492 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3680 + "blockRuntimeId" : 6490 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3681 + "blockRuntimeId" : 6491 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3679 + "blockRuntimeId" : 6489 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3683 + "blockRuntimeId" : 6493 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3687 + "blockRuntimeId" : 6497 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3685 + "blockRuntimeId" : 6495 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3686 + "blockRuntimeId" : 6496 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3684 + "blockRuntimeId" : 6494 }, { "id" : "minecraft:coral", - "blockRuntimeId" : 3688 + "blockRuntimeId" : 6498 }, { "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3702 + "blockRuntimeId" : 4616 }, { "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3700 + "blockRuntimeId" : 4614 }, { "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3701 + "blockRuntimeId" : 4615 }, { "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3699 + "blockRuntimeId" : 4613 }, { "id" : "minecraft:coral_fan", - "blockRuntimeId" : 3703 + "blockRuntimeId" : 4617 }, { "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3712 + "blockRuntimeId" : 69 }, { "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3710 + "blockRuntimeId" : 67 }, { "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3711 + "blockRuntimeId" : 68 }, { "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3709 + "blockRuntimeId" : 66 }, { "id" : "minecraft:coral_fan_dead", - "blockRuntimeId" : 3713 + "blockRuntimeId" : 70 }, { "id" : "minecraft:kelp" }, { "id" : "minecraft:seagrass", - "blockRuntimeId" : 6825 + "blockRuntimeId" : 246 }, { "id" : "minecraft:crimson_roots", - "blockRuntimeId" : 3857 + "blockRuntimeId" : 7573 }, { "id" : "minecraft:warped_roots", - "blockRuntimeId" : 7615 + "blockRuntimeId" : 4362 }, { "id" : "minecraft:yellow_flower", - "blockRuntimeId" : 7941 + "blockRuntimeId" : 302 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6590 + "blockRuntimeId" : 3616 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6591 + "blockRuntimeId" : 3617 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6592 + "blockRuntimeId" : 3618 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6593 + "blockRuntimeId" : 3619 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6594 + "blockRuntimeId" : 3620 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6595 + "blockRuntimeId" : 3621 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6596 + "blockRuntimeId" : 3622 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6597 + "blockRuntimeId" : 3623 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6598 + "blockRuntimeId" : 3624 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6599 + "blockRuntimeId" : 3625 }, { "id" : "minecraft:red_flower", - "blockRuntimeId" : 6600 + "blockRuntimeId" : 3626 }, { "id" : "minecraft:double_plant", - "blockRuntimeId" : 4501 + "blockRuntimeId" : 5452 }, { "id" : "minecraft:double_plant", - "blockRuntimeId" : 4502 + "blockRuntimeId" : 5453 }, { "id" : "minecraft:double_plant", - "blockRuntimeId" : 4505 + "blockRuntimeId" : 5456 }, { "id" : "minecraft:double_plant", - "blockRuntimeId" : 4506 + "blockRuntimeId" : 5457 }, { "id" : "minecraft:wither_rose", - "blockRuntimeId" : 7806 + "blockRuntimeId" : 6165 }, { "id" : "minecraft:white_dye" @@ -2188,127 +2263,135 @@ }, { "id" : "minecraft:vine", - "blockRuntimeId" : 7502 + "blockRuntimeId" : 894 }, { "id" : "minecraft:weeping_vines", - "blockRuntimeId" : 7756 + "blockRuntimeId" : 5479 }, { "id" : "minecraft:twisting_vines", - "blockRuntimeId" : 7430 + "blockRuntimeId" : 5691 }, { "id" : "minecraft:waterlily", - "blockRuntimeId" : 7684 + "blockRuntimeId" : 1158 }, { "id" : "minecraft:deadbush", - "blockRuntimeId" : 4099 + "blockRuntimeId" : 4677 }, { "id" : "minecraft:bamboo", - "blockRuntimeId" : 177 + "blockRuntimeId" : 3684 }, { "id" : "minecraft:snow", - "blockRuntimeId" : 6912 + "blockRuntimeId" : 4194 }, { "id" : "minecraft:ice", - "blockRuntimeId" : 5126 + "blockRuntimeId" : 6689 }, { "id" : "minecraft:packed_ice", - "blockRuntimeId" : 5768 + "blockRuntimeId" : 282 }, { "id" : "minecraft:blue_ice", - "blockRuntimeId" : 691 + "blockRuntimeId" : 7027 }, { "id" : "minecraft:snow_layer", - "blockRuntimeId" : 6913 + "blockRuntimeId" : 155 }, { "id" : "minecraft:pointed_dripstone", - "blockRuntimeId" : 5809 + "blockRuntimeId" : 7416 }, { "id" : "minecraft:dripstone_block", - "blockRuntimeId" : 4585 + "blockRuntimeId" : 893 }, { "id" : "minecraft:moss_carpet", - "blockRuntimeId" : 5666 + "blockRuntimeId" : 286 }, { "id" : "minecraft:moss_block", - "blockRuntimeId" : 5665 + "blockRuntimeId" : 6538 }, { "id" : "minecraft:dirt_with_roots", - "blockRuntimeId" : 4486 + "blockRuntimeId" : 5397 }, { "id" : "minecraft:hanging_roots", - "blockRuntimeId" : 5048 + "blockRuntimeId" : 205 + }, + { + "id" : "minecraft:mangrove_roots", + "blockRuntimeId" : 6175 + }, + { + "id" : "minecraft:muddy_mangrove_roots", + "blockRuntimeId" : 345 }, { "id" : "minecraft:big_dripleaf", - "blockRuntimeId" : 328 + "blockRuntimeId" : 5980 }, { "id" : "minecraft:small_dripleaf_block", - "blockRuntimeId" : 6878 + "blockRuntimeId" : 4320 }, { "id" : "minecraft:spore_blossom", - "blockRuntimeId" : 6965 + "blockRuntimeId" : 7312 }, { "id" : "minecraft:azalea", - "blockRuntimeId" : 168 + "blockRuntimeId" : 6888 }, { "id" : "minecraft:flowering_azalea", - "blockRuntimeId" : 4815 + "blockRuntimeId" : 5477 }, { "id" : "minecraft:glow_lichen", - "blockRuntimeId" : 4972 + "blockRuntimeId" : 5684 }, { "id" : "minecraft:amethyst_block", - "blockRuntimeId" : 136 + "blockRuntimeId" : 290 }, { "id" : "minecraft:budding_amethyst", - "blockRuntimeId" : 919 + "blockRuntimeId" : 7002 }, { "id" : "minecraft:amethyst_cluster", - "blockRuntimeId" : 137 + "blockRuntimeId" : 7810 }, { "id" : "minecraft:large_amethyst_bud", - "blockRuntimeId" : 5367 + "blockRuntimeId" : 4728 }, { "id" : "minecraft:medium_amethyst_bud", - "blockRuntimeId" : 5603 + "blockRuntimeId" : 4376 }, { "id" : "minecraft:small_amethyst_bud", - "blockRuntimeId" : 6865 + "blockRuntimeId" : 304 }, { "id" : "minecraft:tuff", - "blockRuntimeId" : 7417 + "blockRuntimeId" : 347 }, { "id" : "minecraft:calcite", - "blockRuntimeId" : 943 + "blockRuntimeId" : 215 }, { "id" : "minecraft:chicken" @@ -2339,35 +2422,35 @@ }, { "id" : "minecraft:brown_mushroom", - "blockRuntimeId" : 900 + "blockRuntimeId" : 3546 }, { "id" : "minecraft:red_mushroom", - "blockRuntimeId" : 6607 + "blockRuntimeId" : 4585 }, { "id" : "minecraft:crimson_fungus", - "blockRuntimeId" : 3835 + "blockRuntimeId" : 7753 }, { "id" : "minecraft:warped_fungus", - "blockRuntimeId" : 7593 + "blockRuntimeId" : 287 }, { "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 915 + "blockRuntimeId" : 7362 }, { "id" : "minecraft:red_mushroom_block", - "blockRuntimeId" : 6622 + "blockRuntimeId" : 3611 }, { "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 916 + "blockRuntimeId" : 7363 }, { "id" : "minecraft:brown_mushroom_block", - "blockRuntimeId" : 901 + "blockRuntimeId" : 7348 }, { "id" : "minecraft:egg" @@ -2386,50 +2469,66 @@ }, { "id" : "minecraft:web", - "blockRuntimeId" : 7755 + "blockRuntimeId" : 6713 }, { "id" : "minecraft:spider_eye" }, { "id" : "minecraft:mob_spawner", - "blockRuntimeId" : 5658 + "blockRuntimeId" : 401 }, { "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5659 + "blockRuntimeId" : 4144 }, { "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5660 + "blockRuntimeId" : 4145 }, { "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5661 + "blockRuntimeId" : 4146 }, { "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5662 + "blockRuntimeId" : 4147 }, { "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5663 + "blockRuntimeId" : 4148 }, { "id" : "minecraft:monster_egg", - "blockRuntimeId" : 5664 + "blockRuntimeId" : 4149 }, { "id" : "minecraft:infested_deepslate", - "blockRuntimeId" : 5127 + "blockRuntimeId" : 4641 }, { "id" : "minecraft:dragon_egg", - "blockRuntimeId" : 4583 + "blockRuntimeId" : 7271 }, { "id" : "minecraft:turtle_egg", - "blockRuntimeId" : 7418 + "blockRuntimeId" : 7997 + }, + { + "id" : "minecraft:frog_spawn", + "blockRuntimeId" : 4399 + }, + { + "id" : "minecraft:pearlescent_froglight", + "blockRuntimeId" : 6435 + }, + { + "id" : "minecraft:verdant_froglight", + "blockRuntimeId" : 6481 + }, + { + "id" : "minecraft:ochre_froglight", + "blockRuntimeId" : 3510 }, { "id" : "minecraft:chicken_spawn_egg" @@ -2593,6 +2692,18 @@ { "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:ghast_spawn_egg" }, @@ -2631,42 +2742,42 @@ }, { "id" : "minecraft:obsidian", - "blockRuntimeId" : 5737 + "blockRuntimeId" : 428 }, { "id" : "minecraft:crying_obsidian", - "blockRuntimeId" : 3909 + "blockRuntimeId" : 6722 }, { "id" : "minecraft:bedrock", - "blockRuntimeId" : 234 + "blockRuntimeId" : 7017 }, { "id" : "minecraft:soul_sand", - "blockRuntimeId" : 6955 + "blockRuntimeId" : 5831 }, { "id" : "minecraft:netherrack", - "blockRuntimeId" : 5706 + "blockRuntimeId" : 7037 }, { "id" : "minecraft:magma", - "blockRuntimeId" : 5602 + "blockRuntimeId" : 8009 }, { "id" : "minecraft:nether_wart" }, { "id" : "minecraft:end_stone", - "blockRuntimeId" : 4745 + "blockRuntimeId" : 3836 }, { "id" : "minecraft:chorus_flower", - "blockRuntimeId" : 1132 + "blockRuntimeId" : 4530 }, { "id" : "minecraft:chorus_plant", - "blockRuntimeId" : 1138 + "blockRuntimeId" : 5505 }, { "id" : "minecraft:chorus_fruit" @@ -2676,51 +2787,75 @@ }, { "id" : "minecraft:sponge", - "blockRuntimeId" : 6963 + "blockRuntimeId" : 629 }, { "id" : "minecraft:sponge", - "blockRuntimeId" : 6964 + "blockRuntimeId" : 630 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3689 + "blockRuntimeId" : 5237 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3690 + "blockRuntimeId" : 5238 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3691 + "blockRuntimeId" : 5239 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3692 + "blockRuntimeId" : 5240 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3693 + "blockRuntimeId" : 5241 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3694 + "blockRuntimeId" : 5242 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3695 + "blockRuntimeId" : 5243 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3696 + "blockRuntimeId" : 5244 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3697 + "blockRuntimeId" : 5245 }, { "id" : "minecraft:coral_block", - "blockRuntimeId" : 3698 + "blockRuntimeId" : 5246 + }, + { + "id" : "minecraft:sculk", + "blockRuntimeId" : 7036 + }, + { + "id" : "minecraft:sculk_vein", + "blockRuntimeId" : 7132 + }, + { + "id" : "minecraft:sculk_catalyst", + "blockRuntimeId" : 3613 + }, + { + "id" : "minecraft:sculk_shrieker", + "blockRuntimeId" : 219 + }, + { + "id" : "minecraft:sculk_sensor", + "blockRuntimeId" : 4389 + }, + { + "id" : "minecraft:reinforced_deepslate", + "blockRuntimeId" : 5832 }, { "id" : "minecraft:leather_helmet" @@ -3123,6 +3258,40 @@ { "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" }, @@ -3747,111 +3916,110 @@ }, { "id" : "minecraft:torch", - "blockRuntimeId" : 7357 + "blockRuntimeId" : 724 }, { "id" : "minecraft:soul_torch", - "blockRuntimeId" : 6957 + "blockRuntimeId" : 4644 }, { "id" : "minecraft:sea_pickle", - "blockRuntimeId" : 6817 + "blockRuntimeId" : 5855 }, { "id" : "minecraft:lantern", - "blockRuntimeId" : 5363 + "blockRuntimeId" : 7074 }, { "id" : "minecraft:soul_lantern", - "blockRuntimeId" : 6953 + "blockRuntimeId" : 5749 }, { "id" : "minecraft:candle", - "blockRuntimeId" : 953 + "blockRuntimeId" : 7403 }, { "id" : "minecraft:white_candle", - "blockRuntimeId" : 7790 + "blockRuntimeId" : 5300 }, { "id" : "minecraft:orange_candle", - "blockRuntimeId" : 5738 + "blockRuntimeId" : 362 }, { "id" : "minecraft:magenta_candle", - "blockRuntimeId" : 5586 + "blockRuntimeId" : 418 }, { "id" : "minecraft:light_blue_candle", - "blockRuntimeId" : 5474 + "blockRuntimeId" : 4569 }, { "id" : "minecraft:yellow_candle", - "blockRuntimeId" : 7931 + "blockRuntimeId" : 6192 }, { "id" : "minecraft:lime_candle", - "blockRuntimeId" : 5522 + "blockRuntimeId" : 6368 }, { "id" : "minecraft:pink_candle", - "blockRuntimeId" : 5769 + "blockRuntimeId" : 7370 }, { "id" : "minecraft:gray_candle", - "blockRuntimeId" : 5000 + "blockRuntimeId" : 939 }, { "id" : "minecraft:light_gray_candle", - "blockRuntimeId" : 5490 + "blockRuntimeId" : 6224 }, { "id" : "minecraft:cyan_candle", - "blockRuntimeId" : 3921 + "blockRuntimeId" : 7726 }, { "id" : "minecraft:purple_candle", - "blockRuntimeId" : 6509 + "blockRuntimeId" : 7038 }, { - "id" : "minecraft:blue_candle", - "blockRuntimeId" : 675 + "id" : "minecraft:blue_candle" }, { "id" : "minecraft:brown_candle", - "blockRuntimeId" : 884 + "blockRuntimeId" : 5875 }, { "id" : "minecraft:green_candle", - "blockRuntimeId" : 5016 + "blockRuntimeId" : 686 }, { "id" : "minecraft:red_candle", - "blockRuntimeId" : 6580 + "blockRuntimeId" : 4681 }, { "id" : "minecraft:black_candle", - "blockRuntimeId" : 478 + "blockRuntimeId" : 171 }, { "id" : "minecraft:crafting_table", - "blockRuntimeId" : 3771 + "blockRuntimeId" : 5854 }, { "id" : "minecraft:cartography_table", - "blockRuntimeId" : 987 + "blockRuntimeId" : 8288 }, { "id" : "minecraft:fletching_table", - "blockRuntimeId" : 4812 + "blockRuntimeId" : 5833 }, { "id" : "minecraft:smithing_table", - "blockRuntimeId" : 6879 + "blockRuntimeId" : 3726 }, { "id" : "minecraft:beehive", - "blockRuntimeId" : 260 + "blockRuntimeId" : 6108 }, { "id" : "minecraft:campfire" @@ -3861,152 +4029,152 @@ }, { "id" : "minecraft:furnace", - "blockRuntimeId" : 4876 + "blockRuntimeId" : 7802 }, { "id" : "minecraft:blast_furnace", - "blockRuntimeId" : 669 + "blockRuntimeId" : 7567 }, { "id" : "minecraft:smoker", - "blockRuntimeId" : 6880 + "blockRuntimeId" : 647 }, { "id" : "minecraft:respawn_anchor", - "blockRuntimeId" : 6699 + "blockRuntimeId" : 681 }, { "id" : "minecraft:brewing_stand" }, { "id" : "minecraft:anvil", - "blockRuntimeId" : 152 + "blockRuntimeId" : 6634 }, { "id" : "minecraft:anvil", - "blockRuntimeId" : 156 + "blockRuntimeId" : 6638 }, { "id" : "minecraft:anvil", - "blockRuntimeId" : 160 + "blockRuntimeId" : 6642 }, { "id" : "minecraft:grindstone", - "blockRuntimeId" : 5032 + "blockRuntimeId" : 8039 }, { "id" : "minecraft:enchanting_table", - "blockRuntimeId" : 4719 + "blockRuntimeId" : 6723 }, { "id" : "minecraft:bookshelf", - "blockRuntimeId" : 704 + "blockRuntimeId" : 6671 }, { "id" : "minecraft:lectern", - "blockRuntimeId" : 5434 + "blockRuntimeId" : 6940 }, { "id" : "minecraft:cauldron" }, { "id" : "minecraft:composter", - "blockRuntimeId" : 3635 + "blockRuntimeId" : 5415 }, { "id" : "minecraft:chest", - "blockRuntimeId" : 1123 + "blockRuntimeId" : 7115 }, { "id" : "minecraft:trapped_chest", - "blockRuntimeId" : 7379 + "blockRuntimeId" : 5583 }, { "id" : "minecraft:ender_chest", - "blockRuntimeId" : 4746 + "blockRuntimeId" : 4369 }, { "id" : "minecraft:barrel", - "blockRuntimeId" : 201 + "blockRuntimeId" : 4518 }, { "id" : "minecraft:undyed_shulker_box", - "blockRuntimeId" : 7462 + "blockRuntimeId" : 3681 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6830 + "blockRuntimeId" : 5316 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6838 + "blockRuntimeId" : 5324 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6837 + "blockRuntimeId" : 5323 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6845 + "blockRuntimeId" : 5331 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6842 + "blockRuntimeId" : 5328 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6844 + "blockRuntimeId" : 5330 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6831 + "blockRuntimeId" : 5317 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6834 + "blockRuntimeId" : 5320 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6835 + "blockRuntimeId" : 5321 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6843 + "blockRuntimeId" : 5329 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6839 + "blockRuntimeId" : 5325 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6833 + "blockRuntimeId" : 5319 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6841 + "blockRuntimeId" : 5327 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6840 + "blockRuntimeId" : 5326 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6832 + "blockRuntimeId" : 5318 }, { "id" : "minecraft:shulker_box", - "blockRuntimeId" : 6836 + "blockRuntimeId" : 5322 }, { "id" : "minecraft:armor_stand" }, { "id" : "minecraft:noteblock", - "blockRuntimeId" : 5716 + "blockRuntimeId" : 346 }, { "id" : "minecraft:jukebox", - "blockRuntimeId" : 5208 + "blockRuntimeId" : 4874 }, { "id" : "minecraft:music_disc_13" @@ -4047,23 +4215,29 @@ { "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" : 4974 + "blockRuntimeId" : 3885 }, { "id" : "minecraft:redstone_lamp", - "blockRuntimeId" : 6646 + "blockRuntimeId" : 251 }, { - "id" : "minecraft:sealantern", - "blockRuntimeId" : 6828 + "id" : "minecraft:sea_lantern", + "blockRuntimeId" : 7546 }, { "id" : "minecraft:oak_sign" @@ -4083,6 +4257,9 @@ { "id" : "minecraft:dark_oak_sign" }, + { + "id" : "minecraft:mangrove_sign" + }, { "id" : "minecraft:crimson_sign" }, @@ -4137,6 +4314,9 @@ { "id" : "minecraft:axolotl_bucket" }, + { + "id" : "minecraft:tadpole_bucket" + }, { "id" : "minecraft:skull", "damage" : 3 @@ -4162,23 +4342,23 @@ }, { "id" : "minecraft:beacon", - "blockRuntimeId" : 217 + "blockRuntimeId" : 145 }, { "id" : "minecraft:bell", - "blockRuntimeId" : 292 + "blockRuntimeId" : 6908 }, { "id" : "minecraft:conduit", - "blockRuntimeId" : 3676 + "blockRuntimeId" : 4232 }, { "id" : "minecraft:stonecutter_block", - "blockRuntimeId" : 7295 + "blockRuntimeId" : 7574 }, { "id" : "minecraft:end_portal_frame", - "blockRuntimeId" : 4731 + "blockRuntimeId" : 6077 }, { "id" : "minecraft:coal" @@ -4291,6 +4471,9 @@ { "id" : "minecraft:fermented_spider_eye" }, + { + "id" : "minecraft:echo_shard" + }, { "id" : "minecraft:dragon_breath" }, @@ -4314,11 +4497,11 @@ }, { "id" : "minecraft:end_rod", - "blockRuntimeId" : 4739 + "blockRuntimeId" : 5891 }, { "id" : "minecraft:lightning_rod", - "blockRuntimeId" : 5516 + "blockRuntimeId" : 1176 }, { "id" : "minecraft:end_crystal" @@ -4760,6 +4943,18 @@ "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" }, @@ -4778,21 +4973,45 @@ { "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" : 6567 + "blockRuntimeId" : 3920 }, { "id" : "minecraft:golden_rail", - "blockRuntimeId" : 4977 + "blockRuntimeId" : 5332 }, { "id" : "minecraft:detector_rail", - "blockRuntimeId" : 4462 + "blockRuntimeId" : 4132 }, { "id" : "minecraft:activator_rail", - "blockRuntimeId" : 122 + "blockRuntimeId" : 309 }, { "id" : "minecraft:minecart" @@ -4811,114 +5030,123 @@ }, { "id" : "minecraft:redstone_block", - "blockRuntimeId" : 6645 + "blockRuntimeId" : 3776 }, { "id" : "minecraft:redstone_torch", - "blockRuntimeId" : 6648 + "blockRuntimeId" : 3525 }, { "id" : "minecraft:lever", - "blockRuntimeId" : 5442 + "blockRuntimeId" : 6514 }, { "id" : "minecraft:wooden_button", - "blockRuntimeId" : 7843 + "blockRuntimeId" : 6391 }, { "id" : "minecraft:spruce_button", - "blockRuntimeId" : 6966 + "blockRuntimeId" : 4321 }, { "id" : "minecraft:birch_button", - "blockRuntimeId" : 356 + "blockRuntimeId" : 7766 }, { "id" : "minecraft:jungle_button", - "blockRuntimeId" : 5209 + "blockRuntimeId" : 116 }, { - "id" : "minecraft:acacia_button" + "id" : "minecraft:acacia_button", + "blockRuntimeId" : 7231 }, { "id" : "minecraft:dark_oak_button", - "blockRuntimeId" : 3937 + "blockRuntimeId" : 93 + }, + { + "id" : "minecraft:mangrove_button", + "blockRuntimeId" : 7062 }, { "id" : "minecraft:stone_button", - "blockRuntimeId" : 7195 + "blockRuntimeId" : 596 }, { "id" : "minecraft:crimson_button", - "blockRuntimeId" : 3772 + "blockRuntimeId" : 4432 }, { "id" : "minecraft:warped_button", - "blockRuntimeId" : 7530 + "blockRuntimeId" : 7250 }, { "id" : "minecraft:polished_blackstone_button", - "blockRuntimeId" : 6001 + "blockRuntimeId" : 7790 }, { "id" : "minecraft:tripwire_hook", - "blockRuntimeId" : 7401 + "blockRuntimeId" : 5914 }, { "id" : "minecraft:wooden_pressure_plate", - "blockRuntimeId" : 7887 + "blockRuntimeId" : 8063 }, { "id" : "minecraft:spruce_pressure_plate", - "blockRuntimeId" : 7026 + "blockRuntimeId" : 3759 }, { "id" : "minecraft:birch_pressure_plate", - "blockRuntimeId" : 416 + "blockRuntimeId" : 3555 }, { "id" : "minecraft:jungle_pressure_plate", - "blockRuntimeId" : 5269 + "blockRuntimeId" : 3635 }, { "id" : "minecraft:acacia_pressure_plate", - "blockRuntimeId" : 60 + "blockRuntimeId" : 5247 }, { "id" : "minecraft:dark_oak_pressure_plate", - "blockRuntimeId" : 3997 + "blockRuntimeId" : 5956 + }, + { + "id" : "minecraft:mangrove_pressure_plate", + "blockRuntimeId" : 3869 }, { "id" : "minecraft:crimson_pressure_plate", - "blockRuntimeId" : 3841 + "blockRuntimeId" : 8268 }, { "id" : "minecraft:warped_pressure_plate", - "blockRuntimeId" : 7599 + "blockRuntimeId" : 256 }, { "id" : "minecraft:stone_pressure_plate", - "blockRuntimeId" : 7207 + "blockRuntimeId" : 3886 }, { "id" : "minecraft:light_weighted_pressure_plate", - "blockRuntimeId" : 5500 + "blockRuntimeId" : 3665 }, { "id" : "minecraft:heavy_weighted_pressure_plate", - "blockRuntimeId" : 5096 + "blockRuntimeId" : 1160 }, { "id" : "minecraft:polished_blackstone_pressure_plate", - "blockRuntimeId" : 6015 + "blockRuntimeId" : 6232 }, { "id" : "minecraft:observer", - "blockRuntimeId" : 5725 + "blockRuntimeId" : 3513 }, { "id" : "minecraft:daylight_detector", - "blockRuntimeId" : 4067 + "blockRuntimeId" : 4197 }, { "id" : "minecraft:repeater" @@ -4931,30 +5159,30 @@ }, { "id" : "minecraft:dropper", - "blockRuntimeId" : 4589 + "blockRuntimeId" : 7385 }, { "id" : "minecraft:dispenser", - "blockRuntimeId" : 4490 + "blockRuntimeId" : 8013 }, { "id" : "minecraft:piston", - "blockRuntimeId" : 5786 + "blockRuntimeId" : 922 }, { "id" : "minecraft:sticky_piston", - "blockRuntimeId" : 7169 + "blockRuntimeId" : 4364 }, { "id" : "minecraft:tnt", - "blockRuntimeId" : 7353 + "blockRuntimeId" : 6707 }, { "id" : "minecraft:name_tag" }, { "id" : "minecraft:loom", - "blockRuntimeId" : 5582 + "blockRuntimeId" : 3826 }, { "id" : "minecraft:banner" @@ -5045,6 +5273,9 @@ { "id" : "minecraft:piglin_banner_pattern" }, + { + "id" : "minecraft:globe_banner_pattern" + }, { "id" : "minecraft:firework_rocket", "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" @@ -5197,7 +5428,7 @@ }, { "id" : "minecraft:target", - "blockRuntimeId" : 7351 + "blockRuntimeId" : 6390 }, { "id" : "minecraft:lodestone_compass" diff --git a/core/src/main/resources/bedrock/entity_identifiers.dat b/core/src/main/resources/bedrock/entity_identifiers.dat index b9da310f5..2e3733aa6 100644 Binary files a/core/src/main/resources/bedrock/entity_identifiers.dat and b/core/src/main/resources/bedrock/entity_identifiers.dat differ diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_17_30.json b/core/src/main/resources/bedrock/runtime_item_states.1_17_30.json deleted file mode 100644 index 79690e3da..000000000 --- a/core/src/main/resources/bedrock/runtime_item_states.1_17_30.json +++ /dev/null @@ -1,4306 +0,0 @@ -[ - { - "name" : "minecraft:acacia_boat", - "id" : 379 - }, - { - "name" : "minecraft:acacia_button", - "id" : -140 - }, - { - "name" : "minecraft:acacia_door", - "id" : 556 - }, - { - "name" : "minecraft:acacia_fence_gate", - "id" : 187 - }, - { - "name" : "minecraft:acacia_pressure_plate", - "id" : -150 - }, - { - "name" : "minecraft:acacia_sign", - "id" : 579 - }, - { - "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" : 487 - }, - { - "name" : "minecraft:air", - "id" : -158 - }, - { - "name" : "minecraft:allow", - "id" : 210 - }, - { - "name" : "minecraft:amethyst_block", - "id" : -327 - }, - { - "name" : "minecraft:amethyst_cluster", - "id" : -329 - }, - { - "name" : "minecraft:amethyst_shard", - "id" : 623 - }, - { - "name" : "minecraft:ancient_debris", - "id" : -271 - }, - { - "name" : "minecraft:andesite_stairs", - "id" : -171 - }, - { - "name" : "minecraft:anvil", - "id" : 145 - }, - { - "name" : "minecraft:apple", - "id" : 257 - }, - { - "name" : "minecraft:armor_stand", - "id" : 552 - }, - { - "name" : "minecraft:arrow", - "id" : 301 - }, - { - "name" : "minecraft:axolotl_bucket", - "id" : 369 - }, - { - "name" : "minecraft:axolotl_spawn_egg", - "id" : 500 - }, - { - "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" : 597 - }, - { - "name" : "minecraft:bamboo", - "id" : -163 - }, - { - "name" : "minecraft:bamboo_sapling", - "id" : -164 - }, - { - "name" : "minecraft:banner", - "id" : 567 - }, - { - "name" : "minecraft:banner_pattern", - "id" : 627 - }, - { - "name" : "minecraft:barrel", - "id" : -203 - }, - { - "name" : "minecraft:barrier", - "id" : -161 - }, - { - "name" : "minecraft:basalt", - "id" : -234 - }, - { - "name" : "minecraft:bat_spawn_egg", - "id" : 453 - }, - { - "name" : "minecraft:beacon", - "id" : 138 - }, - { - "name" : "minecraft:bed", - "id" : 418 - }, - { - "name" : "minecraft:bedrock", - "id" : 7 - }, - { - "name" : "minecraft:bee_nest", - "id" : -218 - }, - { - "name" : "minecraft:bee_spawn_egg", - "id" : 494 - }, - { - "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" : 376 - }, - { - "name" : "minecraft:birch_button", - "id" : -141 - }, - { - "name" : "minecraft:birch_door", - "id" : 554 - }, - { - "name" : "minecraft:birch_fence_gate", - "id" : 184 - }, - { - "name" : "minecraft:birch_pressure_plate", - "id" : -151 - }, - { - "name" : "minecraft:birch_sign", - "id" : 577 - }, - { - "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" : 395 - }, - { - "name" : "minecraft:black_glazed_terracotta", - "id" : 235 - }, - { - "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" : 429 - }, - { - "name" : "minecraft:blaze_rod", - "id" : 423 - }, - { - "name" : "minecraft:blaze_spawn_egg", - "id" : 456 - }, - { - "name" : "minecraft:bleach", - "id" : 595 - }, - { - "name" : "minecraft:blue_candle", - "id" : -424 - }, - { - "name" : "minecraft:blue_candle_cake", - "id" : -441 - }, - { - "name" : "minecraft:blue_dye", - "id" : 399 - }, - { - "name" : "minecraft:blue_glazed_terracotta", - "id" : 231 - }, - { - "name" : "minecraft:blue_ice", - "id" : -11 - }, - { - "name" : "minecraft:boat", - "id" : 625 - }, - { - "name" : "minecraft:bone", - "id" : 415 - }, - { - "name" : "minecraft:bone_block", - "id" : 216 - }, - { - "name" : "minecraft:bone_meal", - "id" : 411 - }, - { - "name" : "minecraft:book", - "id" : 387 - }, - { - "name" : "minecraft:bookshelf", - "id" : 47 - }, - { - "name" : "minecraft:border_block", - "id" : 212 - }, - { - "name" : "minecraft:bordure_indented_banner_pattern", - "id" : 586 - }, - { - "name" : "minecraft:bow", - "id" : 300 - }, - { - "name" : "minecraft:bowl", - "id" : 321 - }, - { - "name" : "minecraft:bread", - "id" : 261 - }, - { - "name" : "minecraft:brewing_stand", - "id" : 431 - }, - { - "name" : "minecraft:brewingstandblock", - "id" : 117 - }, - { - "name" : "minecraft:brick", - "id" : 383 - }, - { - "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" : 398 - }, - { - "name" : "minecraft:brown_glazed_terracotta", - "id" : 232 - }, - { - "name" : "minecraft:brown_mushroom", - "id" : 39 - }, - { - "name" : "minecraft:brown_mushroom_block", - "id" : 99 - }, - { - "name" : "minecraft:bubble_column", - "id" : -160 - }, - { - "name" : "minecraft:bucket", - "id" : 360 - }, - { - "name" : "minecraft:budding_amethyst", - "id" : -328 - }, - { - "name" : "minecraft:cactus", - "id" : 81 - }, - { - "name" : "minecraft:cake", - "id" : 417 - }, - { - "name" : "minecraft:calcite", - "id" : -326 - }, - { - "name" : "minecraft:camera", - "id" : 592 - }, - { - "name" : "minecraft:campfire", - "id" : 588 - }, - { - "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" : 517 - }, - { - "name" : "minecraft:carrots", - "id" : 141 - }, - { - "name" : "minecraft:cartography_table", - "id" : -200 - }, - { - "name" : "minecraft:carved_pumpkin", - "id" : -155 - }, - { - "name" : "minecraft:cat_spawn_egg", - "id" : 488 - }, - { - "name" : "minecraft:cauldron", - "id" : 432 - }, - { - "name" : "minecraft:cave_spider_spawn_egg", - "id" : 457 - }, - { - "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" : 617 - }, - { - "name" : "minecraft:chain_command_block", - "id" : 189 - }, - { - "name" : "minecraft:chainmail_boots", - "id" : 342 - }, - { - "name" : "minecraft:chainmail_chestplate", - "id" : 340 - }, - { - "name" : "minecraft:chainmail_helmet", - "id" : 339 - }, - { - "name" : "minecraft:chainmail_leggings", - "id" : 341 - }, - { - "name" : "minecraft:charcoal", - "id" : 303 - }, - { - "name" : "minecraft:chemical_heat", - "id" : 192 - }, - { - "name" : "minecraft:chemistry_table", - "id" : 238 - }, - { - "name" : "minecraft:chest", - "id" : 54 - }, - { - "name" : "minecraft:chest_minecart", - "id" : 389 - }, - { - "name" : "minecraft:chicken", - "id" : 275 - }, - { - "name" : "minecraft:chicken_spawn_egg", - "id" : 435 - }, - { - "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" : 558 - }, - { - "name" : "minecraft:chorus_plant", - "id" : 240 - }, - { - "name" : "minecraft:clay", - "id" : 82 - }, - { - "name" : "minecraft:clay_ball", - "id" : 384 - }, - { - "name" : "minecraft:clock", - "id" : 393 - }, - { - "name" : "minecraft:coal", - "id" : 302 - }, - { - "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" : 412 - }, - { - "name" : "minecraft:cod", - "id" : 264 - }, - { - "name" : "minecraft:cod_bucket", - "id" : 364 - }, - { - "name" : "minecraft:cod_spawn_egg", - "id" : 480 - }, - { - "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" : 563 - }, - { - "name" : "minecraft:comparator", - "id" : 522 - }, - { - "name" : "minecraft:compass", - "id" : 391 - }, - { - "name" : "minecraft:composter", - "id" : -213 - }, - { - "name" : "minecraft:compound", - "id" : 593 - }, - { - "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" : 551 - }, - { - "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" : 504 - }, - { - "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" : 436 - }, - { - "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" : 582 - }, - { - "name" : "minecraft:creeper_spawn_egg", - "id" : 441 - }, - { - "name" : "minecraft:crimson_button", - "id" : -260 - }, - { - "name" : "minecraft:crimson_door", - "id" : 614 - }, - { - "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_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" : 612 - }, - { - "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" : 575 - }, - { - "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" : 401 - }, - { - "name" : "minecraft:cyan_glazed_terracotta", - "id" : 229 - }, - { - "name" : "minecraft:dark_oak_boat", - "id" : 380 - }, - { - "name" : "minecraft:dark_oak_button", - "id" : -142 - }, - { - "name" : "minecraft:dark_oak_door", - "id" : 557 - }, - { - "name" : "minecraft:dark_oak_fence_gate", - "id" : 186 - }, - { - "name" : "minecraft:dark_oak_pressure_plate", - "id" : -152 - }, - { - "name" : "minecraft:dark_oak_sign", - "id" : 580 - }, - { - "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: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" : 304 - }, - { - "name" : "minecraft:diamond_axe", - "id" : 319 - }, - { - "name" : "minecraft:diamond_block", - "id" : 57 - }, - { - "name" : "minecraft:diamond_boots", - "id" : 350 - }, - { - "name" : "minecraft:diamond_chestplate", - "id" : 348 - }, - { - "name" : "minecraft:diamond_helmet", - "id" : 347 - }, - { - "name" : "minecraft:diamond_hoe", - "id" : 332 - }, - { - "name" : "minecraft:diamond_horse_armor", - "id" : 533 - }, - { - "name" : "minecraft:diamond_leggings", - "id" : 349 - }, - { - "name" : "minecraft:diamond_ore", - "id" : 56 - }, - { - "name" : "minecraft:diamond_pickaxe", - "id" : 318 - }, - { - "name" : "minecraft:diamond_shovel", - "id" : 317 - }, - { - "name" : "minecraft:diamond_sword", - "id" : 316 - }, - { - "name" : "minecraft:diorite_stairs", - "id" : -170 - }, - { - "name" : "minecraft:dirt", - "id" : 3 - }, - { - "name" : "minecraft:dirt_with_roots", - "id" : -318 - }, - { - "name" : "minecraft:dispenser", - "id" : 23 - }, - { - "name" : "minecraft:dolphin_spawn_egg", - "id" : 484 - }, - { - "name" : "minecraft:donkey_spawn_egg", - "id" : 465 - }, - { - "name" : "minecraft:double_cut_copper_slab", - "id" : -368 - }, - { - "name" : "minecraft:double_plant", - "id" : 175 - }, - { - "name" : "minecraft:double_stone_slab", - "id" : 44 - }, - { - "name" : "minecraft:double_stone_slab2", - "id" : 182 - }, - { - "name" : "minecraft:double_stone_slab3", - "id" : -162 - }, - { - "name" : "minecraft:double_stone_slab4", - "id" : -166 - }, - { - "name" : "minecraft:double_wooden_slab", - "id" : 157 - }, - { - "name" : "minecraft:dragon_breath", - "id" : 560 - }, - { - "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" : 483 - }, - { - "name" : "minecraft:dye", - "id" : 626 - }, - { - "name" : "minecraft:egg", - "id" : 390 - }, - { - "name" : "minecraft:elder_guardian_spawn_egg", - "id" : 471 - }, - { - "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" : 564 - }, - { - "name" : "minecraft:emerald", - "id" : 512 - }, - { - "name" : "minecraft:emerald_block", - "id" : 133 - }, - { - "name" : "minecraft:emerald_ore", - "id" : 129 - }, - { - "name" : "minecraft:empty_map", - "id" : 515 - }, - { - "name" : "minecraft:enchanted_book", - "id" : 521 - }, - { - "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" : 629 - }, - { - "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_eye", - "id" : 433 - }, - { - "name" : "minecraft:ender_pearl", - "id" : 422 - }, - { - "name" : "minecraft:enderman_spawn_egg", - "id" : 442 - }, - { - "name" : "minecraft:endermite_spawn_egg", - "id" : 460 - }, - { - "name" : "minecraft:evoker_spawn_egg", - "id" : 475 - }, - { - "name" : "minecraft:experience_bottle", - "id" : 508 - }, - { - "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" : 327 - }, - { - "name" : "minecraft:fence", - "id" : 85 - }, - { - "name" : "minecraft:fence_gate", - "id" : 107 - }, - { - "name" : "minecraft:fermented_spider_eye", - "id" : 428 - }, - { - "name" : "minecraft:field_masoned_banner_pattern", - "id" : 585 - }, - { - "name" : "minecraft:filled_map", - "id" : 420 - }, - { - "name" : "minecraft:fire", - "id" : 51 - }, - { - "name" : "minecraft:fire_charge", - "id" : 509 - }, - { - "name" : "minecraft:firework_rocket", - "id" : 519 - }, - { - "name" : "minecraft:firework_star", - "id" : 520 - }, - { - "name" : "minecraft:fishing_rod", - "id" : 392 - }, - { - "name" : "minecraft:fletching_table", - "id" : -201 - }, - { - "name" : "minecraft:flint", - "id" : 356 - }, - { - "name" : "minecraft:flint_and_steel", - "id" : 299 - }, - { - "name" : "minecraft:flower_banner_pattern", - "id" : 581 - }, - { - "name" : "minecraft:flower_pot", - "id" : 514 - }, - { - "name" : "minecraft:flowering_azalea", - "id" : -338 - }, - { - "name" : "minecraft:flowing_lava", - "id" : 10 - }, - { - "name" : "minecraft:flowing_water", - "id" : 8 - }, - { - "name" : "minecraft:fox_spawn_egg", - "id" : 490 - }, - { - "name" : "minecraft:frame", - "id" : 513 - }, - { - "name" : "minecraft:frosted_ice", - "id" : 207 - }, - { - "name" : "minecraft:furnace", - "id" : 61 - }, - { - "name" : "minecraft:ghast_spawn_egg", - "id" : 454 - }, - { - "name" : "minecraft:ghast_tear", - "id" : 424 - }, - { - "name" : "minecraft:gilded_blackstone", - "id" : -281 - }, - { - "name" : "minecraft:glass", - "id" : 20 - }, - { - "name" : "minecraft:glass_bottle", - "id" : 427 - }, - { - "name" : "minecraft:glass_pane", - "id" : 102 - }, - { - "name" : "minecraft:glistering_melon_slice", - "id" : 434 - }, - { - "name" : "minecraft:glow_berries", - "id" : 630 - }, - { - "name" : "minecraft:glow_frame", - "id" : 621 - }, - { - "name" : "minecraft:glow_ink_sac", - "id" : 503 - }, - { - "name" : "minecraft:glow_lichen", - "id" : -411 - }, - { - "name" : "minecraft:glow_squid_spawn_egg", - "id" : 502 - }, - { - "name" : "minecraft:glow_stick", - "id" : 166 - }, - { - "name" : "minecraft:glowingobsidian", - "id" : 246 - }, - { - "name" : "minecraft:glowstone", - "id" : 89 - }, - { - "name" : "minecraft:glowstone_dust", - "id" : 394 - }, - { - "name" : "minecraft:goat_horn", - "id" : 622 - }, - { - "name" : "minecraft:goat_spawn_egg", - "id" : 501 - }, - { - "name" : "minecraft:gold_block", - "id" : 41 - }, - { - "name" : "minecraft:gold_ingot", - "id" : 306 - }, - { - "name" : "minecraft:gold_nugget", - "id" : 425 - }, - { - "name" : "minecraft:gold_ore", - "id" : 14 - }, - { - "name" : "minecraft:golden_apple", - "id" : 258 - }, - { - "name" : "minecraft:golden_axe", - "id" : 325 - }, - { - "name" : "minecraft:golden_boots", - "id" : 354 - }, - { - "name" : "minecraft:golden_carrot", - "id" : 283 - }, - { - "name" : "minecraft:golden_chestplate", - "id" : 352 - }, - { - "name" : "minecraft:golden_helmet", - "id" : 351 - }, - { - "name" : "minecraft:golden_hoe", - "id" : 333 - }, - { - "name" : "minecraft:golden_horse_armor", - "id" : 532 - }, - { - "name" : "minecraft:golden_leggings", - "id" : 353 - }, - { - "name" : "minecraft:golden_pickaxe", - "id" : 324 - }, - { - "name" : "minecraft:golden_rail", - "id" : 27 - }, - { - "name" : "minecraft:golden_shovel", - "id" : 323 - }, - { - "name" : "minecraft:golden_sword", - "id" : 322 - }, - { - "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" : 403 - }, - { - "name" : "minecraft:gray_glazed_terracotta", - "id" : 227 - }, - { - "name" : "minecraft:green_candle", - "id" : -426 - }, - { - "name" : "minecraft:green_candle_cake", - "id" : -443 - }, - { - "name" : "minecraft:green_dye", - "id" : 397 - }, - { - "name" : "minecraft:green_glazed_terracotta", - "id" : 233 - }, - { - "name" : "minecraft:grindstone", - "id" : -195 - }, - { - "name" : "minecraft:guardian_spawn_egg", - "id" : 461 - }, - { - "name" : "minecraft:gunpowder", - "id" : 328 - }, - { - "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" : 571 - }, - { - "name" : "minecraft:heavy_weighted_pressure_plate", - "id" : 148 - }, - { - "name" : "minecraft:hoglin_spawn_egg", - "id" : 496 - }, - { - "name" : "minecraft:honey_block", - "id" : -220 - }, - { - "name" : "minecraft:honey_bottle", - "id" : 591 - }, - { - "name" : "minecraft:honeycomb", - "id" : 590 - }, - { - "name" : "minecraft:honeycomb_block", - "id" : -221 - }, - { - "name" : "minecraft:hopper", - "id" : 527 - }, - { - "name" : "minecraft:hopper_minecart", - "id" : 526 - }, - { - "name" : "minecraft:horse_spawn_egg", - "id" : 458 - }, - { - "name" : "minecraft:husk_spawn_egg", - "id" : 463 - }, - { - "name" : "minecraft:ice", - "id" : 79 - }, - { - "name" : "minecraft:ice_bomb", - "id" : 594 - }, - { - "name" : "minecraft:infested_deepslate", - "id" : -454 - }, - { - "name" : "minecraft:info_update", - "id" : 248 - }, - { - "name" : "minecraft:info_update2", - "id" : 249 - }, - { - "name" : "minecraft:ink_sac", - "id" : 413 - }, - { - "name" : "minecraft:invisiblebedrock", - "id" : 95 - }, - { - "name" : "minecraft:iron_axe", - "id" : 298 - }, - { - "name" : "minecraft:iron_bars", - "id" : 101 - }, - { - "name" : "minecraft:iron_block", - "id" : 42 - }, - { - "name" : "minecraft:iron_boots", - "id" : 346 - }, - { - "name" : "minecraft:iron_chestplate", - "id" : 344 - }, - { - "name" : "minecraft:iron_door", - "id" : 372 - }, - { - "name" : "minecraft:iron_helmet", - "id" : 343 - }, - { - "name" : "minecraft:iron_hoe", - "id" : 331 - }, - { - "name" : "minecraft:iron_horse_armor", - "id" : 531 - }, - { - "name" : "minecraft:iron_ingot", - "id" : 305 - }, - { - "name" : "minecraft:iron_leggings", - "id" : 345 - }, - { - "name" : "minecraft:iron_nugget", - "id" : 569 - }, - { - "name" : "minecraft:iron_ore", - "id" : 15 - }, - { - "name" : "minecraft:iron_pickaxe", - "id" : 297 - }, - { - "name" : "minecraft:iron_shovel", - "id" : 296 - }, - { - "name" : "minecraft:iron_sword", - "id" : 307 - }, - { - "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.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.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" : 377 - }, - { - "name" : "minecraft:jungle_button", - "id" : -143 - }, - { - "name" : "minecraft:jungle_door", - "id" : 555 - }, - { - "name" : "minecraft:jungle_fence_gate", - "id" : 185 - }, - { - "name" : "minecraft:jungle_pressure_plate", - "id" : -153 - }, - { - "name" : "minecraft:jungle_sign", - "id" : 578 - }, - { - "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" : 382 - }, - { - "name" : "minecraft:ladder", - "id" : 65 - }, - { - "name" : "minecraft:lantern", - "id" : -208 - }, - { - "name" : "minecraft:lapis_block", - "id" : 22 - }, - { - "name" : "minecraft:lapis_lazuli", - "id" : 414 - }, - { - "name" : "minecraft:lapis_ore", - "id" : 21 - }, - { - "name" : "minecraft:large_amethyst_bud", - "id" : -330 - }, - { - "name" : "minecraft:lava", - "id" : 11 - }, - { - "name" : "minecraft:lava_bucket", - "id" : 363 - }, - { - "name" : "minecraft:lava_cauldron", - "id" : -210 - }, - { - "name" : "minecraft:lead", - "id" : 547 - }, - { - "name" : "minecraft:leather", - "id" : 381 - }, - { - "name" : "minecraft:leather_boots", - "id" : 338 - }, - { - "name" : "minecraft:leather_chestplate", - "id" : 336 - }, - { - "name" : "minecraft:leather_helmet", - "id" : 335 - }, - { - "name" : "minecraft:leather_horse_armor", - "id" : 530 - }, - { - "name" : "minecraft:leather_leggings", - "id" : 337 - }, - { - "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" : 407 - }, - { - "name" : "minecraft:light_blue_glazed_terracotta", - "id" : 223 - }, - { - "name" : "minecraft:light_gray_candle", - "id" : -421 - }, - { - "name" : "minecraft:light_gray_candle_cake", - "id" : -438 - }, - { - "name" : "minecraft:light_gray_dye", - "id" : 402 - }, - { - "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" : 405 - }, - { - "name" : "minecraft:lime_glazed_terracotta", - "id" : 225 - }, - { - "name" : "minecraft:lingering_potion", - "id" : 562 - }, - { - "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" : 473 - }, - { - "name" : "minecraft:lodestone", - "id" : -222 - }, - { - "name" : "minecraft:lodestone_compass", - "id" : 600 - }, - { - "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" : 408 - }, - { - "name" : "minecraft:magenta_glazed_terracotta", - "id" : 222 - }, - { - "name" : "minecraft:magma", - "id" : 213 - }, - { - "name" : "minecraft:magma_cream", - "id" : 430 - }, - { - "name" : "minecraft:magma_cube_spawn_egg", - "id" : 455 - }, - { - "name" : "minecraft:medicine", - "id" : 598 - }, - { - "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" : 361 - }, - { - "name" : "minecraft:minecart", - "id" : 370 - }, - { - "name" : "minecraft:mob_spawner", - "id" : 52 - }, - { - "name" : "minecraft:mojang_banner_pattern", - "id" : 584 - }, - { - "name" : "minecraft:monster_egg", - "id" : 97 - }, - { - "name" : "minecraft:mooshroom_spawn_egg", - "id" : 440 - }, - { - "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:movingblock", - "id" : 250 - }, - { - "name" : "minecraft:mule_spawn_egg", - "id" : 466 - }, - { - "name" : "minecraft:mushroom_stew", - "id" : 260 - }, - { - "name" : "minecraft:music_disc_11", - "id" : 544 - }, - { - "name" : "minecraft:music_disc_13", - "id" : 534 - }, - { - "name" : "minecraft:music_disc_blocks", - "id" : 536 - }, - { - "name" : "minecraft:music_disc_cat", - "id" : 535 - }, - { - "name" : "minecraft:music_disc_chirp", - "id" : 537 - }, - { - "name" : "minecraft:music_disc_far", - "id" : 538 - }, - { - "name" : "minecraft:music_disc_mall", - "id" : 539 - }, - { - "name" : "minecraft:music_disc_mellohi", - "id" : 540 - }, - { - "name" : "minecraft:music_disc_pigstep", - "id" : 618 - }, - { - "name" : "minecraft:music_disc_stal", - "id" : 541 - }, - { - "name" : "minecraft:music_disc_strad", - "id" : 542 - }, - { - "name" : "minecraft:music_disc_wait", - "id" : 545 - }, - { - "name" : "minecraft:music_disc_ward", - "id" : 543 - }, - { - "name" : "minecraft:mutton", - "id" : 550 - }, - { - "name" : "minecraft:mycelium", - "id" : 110 - }, - { - "name" : "minecraft:name_tag", - "id" : 548 - }, - { - "name" : "minecraft:nautilus_shell", - "id" : 570 - }, - { - "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" : 619 - }, - { - "name" : "minecraft:nether_star", - "id" : 518 - }, - { - "name" : "minecraft:nether_wart", - "id" : 294 - }, - { - "name" : "minecraft:nether_wart_block", - "id" : 214 - }, - { - "name" : "minecraft:netherbrick", - "id" : 523 - }, - { - "name" : "minecraft:netherite_axe", - "id" : 605 - }, - { - "name" : "minecraft:netherite_block", - "id" : -270 - }, - { - "name" : "minecraft:netherite_boots", - "id" : 610 - }, - { - "name" : "minecraft:netherite_chestplate", - "id" : 608 - }, - { - "name" : "minecraft:netherite_helmet", - "id" : 607 - }, - { - "name" : "minecraft:netherite_hoe", - "id" : 606 - }, - { - "name" : "minecraft:netherite_ingot", - "id" : 601 - }, - { - "name" : "minecraft:netherite_leggings", - "id" : 609 - }, - { - "name" : "minecraft:netherite_pickaxe", - "id" : 604 - }, - { - "name" : "minecraft:netherite_scrap", - "id" : 611 - }, - { - "name" : "minecraft:netherite_shovel", - "id" : 603 - }, - { - "name" : "minecraft:netherite_sword", - "id" : 602 - }, - { - "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" : 470 - }, - { - "name" : "minecraft:oak_boat", - "id" : 375 - }, - { - "name" : "minecraft:oak_sign", - "id" : 358 - }, - { - "name" : "minecraft:oak_stairs", - "id" : 53 - }, - { - "name" : "minecraft:observer", - "id" : 251 - }, - { - "name" : "minecraft:obsidian", - "id" : 49 - }, - { - "name" : "minecraft:ocelot_spawn_egg", - "id" : 451 - }, - { - "name" : "minecraft:orange_candle", - "id" : -414 - }, - { - "name" : "minecraft:orange_candle_cake", - "id" : -431 - }, - { - "name" : "minecraft:orange_dye", - "id" : 409 - }, - { - "name" : "minecraft:orange_glazed_terracotta", - "id" : 221 - }, - { - "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:painting", - "id" : 357 - }, - { - "name" : "minecraft:panda_spawn_egg", - "id" : 489 - }, - { - "name" : "minecraft:paper", - "id" : 386 - }, - { - "name" : "minecraft:parrot_spawn_egg", - "id" : 478 - }, - { - "name" : "minecraft:phantom_membrane", - "id" : 574 - }, - { - "name" : "minecraft:phantom_spawn_egg", - "id" : 486 - }, - { - "name" : "minecraft:pig_spawn_egg", - "id" : 437 - }, - { - "name" : "minecraft:piglin_banner_pattern", - "id" : 587 - }, - { - "name" : "minecraft:piglin_brute_spawn_egg", - "id" : 499 - }, - { - "name" : "minecraft:piglin_spawn_egg", - "id" : 497 - }, - { - "name" : "minecraft:pillager_spawn_egg", - "id" : 491 - }, - { - "name" : "minecraft:pink_candle", - "id" : -419 - }, - { - "name" : "minecraft:pink_candle_cake", - "id" : -436 - }, - { - "name" : "minecraft:pink_dye", - "id" : 404 - }, - { - "name" : "minecraft:pink_glazed_terracotta", - "id" : 226 - }, - { - "name" : "minecraft:piston", - "id" : 33 - }, - { - "name" : "minecraft:pistonarmcollision", - "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" : 472 - }, - { - "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" : 559 - }, - { - "name" : "minecraft:porkchop", - "id" : 262 - }, - { - "name" : "minecraft:portal", - "id" : 90 - }, - { - "name" : "minecraft:potato", - "id" : 280 - }, - { - "name" : "minecraft:potatoes", - "id" : 142 - }, - { - "name" : "minecraft:potion", - "id" : 426 - }, - { - "name" : "minecraft:powder_snow", - "id" : -306 - }, - { - "name" : "minecraft:powder_snow_bucket", - "id" : 368 - }, - { - "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" : 549 - }, - { - "name" : "minecraft:prismarine_shard", - "id" : 565 - }, - { - "name" : "minecraft:prismarine_stairs", - "id" : -2 - }, - { - "name" : "minecraft:pufferfish", - "id" : 267 - }, - { - "name" : "minecraft:pufferfish_bucket", - "id" : 367 - }, - { - "name" : "minecraft:pufferfish_spawn_egg", - "id" : 481 - }, - { - "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" : 400 - }, - { - "name" : "minecraft:purple_glazed_terracotta", - "id" : 219 - }, - { - "name" : "minecraft:purpur_block", - "id" : 201 - }, - { - "name" : "minecraft:purpur_stairs", - "id" : 203 - }, - { - "name" : "minecraft:quartz", - "id" : 524 - }, - { - "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" : 528 - }, - { - "name" : "minecraft:rabbit_hide", - "id" : 529 - }, - { - "name" : "minecraft:rabbit_spawn_egg", - "id" : 459 - }, - { - "name" : "minecraft:rabbit_stew", - "id" : 290 - }, - { - "name" : "minecraft:rail", - "id" : 66 - }, - { - "name" : "minecraft:rapid_fertilizer", - "id" : 596 - }, - { - "name" : "minecraft:ravager_spawn_egg", - "id" : 493 - }, - { - "name" : "minecraft:raw_copper", - "id" : 507 - }, - { - "name" : "minecraft:raw_copper_block", - "id" : -452 - }, - { - "name" : "minecraft:raw_gold", - "id" : 506 - }, - { - "name" : "minecraft:raw_gold_block", - "id" : -453 - }, - { - "name" : "minecraft:raw_iron", - "id" : 505 - }, - { - "name" : "minecraft:raw_iron_block", - "id" : -451 - }, - { - "name" : "minecraft:real_double_stone_slab", - "id" : 43 - }, - { - "name" : "minecraft:real_double_stone_slab2", - "id" : 181 - }, - { - "name" : "minecraft:real_double_stone_slab3", - "id" : -167 - }, - { - "name" : "minecraft:real_double_stone_slab4", - "id" : -168 - }, - { - "name" : "minecraft:red_candle", - "id" : -427 - }, - { - "name" : "minecraft:red_candle_cake", - "id" : -444 - }, - { - "name" : "minecraft:red_dye", - "id" : 396 - }, - { - "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:redstone", - "id" : 373 - }, - { - "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:repeater", - "id" : 419 - }, - { - "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" : 371 - }, - { - "name" : "minecraft:salmon", - "id" : 265 - }, - { - "name" : "minecraft:salmon_bucket", - "id" : 365 - }, - { - "name" : "minecraft:salmon_spawn_egg", - "id" : 482 - }, - { - "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" : 572 - }, - { - "name" : "minecraft:sea_pickle", - "id" : -156 - }, - { - "name" : "minecraft:seagrass", - "id" : -130 - }, - { - "name" : "minecraft:sealantern", - "id" : 169 - }, - { - "name" : "minecraft:shears", - "id" : 421 - }, - { - "name" : "minecraft:sheep_spawn_egg", - "id" : 438 - }, - { - "name" : "minecraft:shield", - "id" : 355 - }, - { - "name" : "minecraft:shroomlight", - "id" : -230 - }, - { - "name" : "minecraft:shulker_box", - "id" : 218 - }, - { - "name" : "minecraft:shulker_shell", - "id" : 566 - }, - { - "name" : "minecraft:shulker_spawn_egg", - "id" : 469 - }, - { - "name" : "minecraft:silver_glazed_terracotta", - "id" : 228 - }, - { - "name" : "minecraft:silverfish_spawn_egg", - "id" : 443 - }, - { - "name" : "minecraft:skeleton_horse_spawn_egg", - "id" : 467 - }, - { - "name" : "minecraft:skeleton_spawn_egg", - "id" : 444 - }, - { - "name" : "minecraft:skull", - "id" : 516 - }, - { - "name" : "minecraft:skull_banner_pattern", - "id" : 583 - }, - { - "name" : "minecraft:slime", - "id" : 165 - }, - { - "name" : "minecraft:slime_ball", - "id" : 388 - }, - { - "name" : "minecraft:slime_spawn_egg", - "id" : 445 - }, - { - "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:snow", - "id" : 80 - }, - { - "name" : "minecraft:snow_layer", - "id" : 78 - }, - { - "name" : "minecraft:snowball", - "id" : 374 - }, - { - "name" : "minecraft:soul_campfire", - "id" : 620 - }, - { - "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" : 599 - }, - { - "name" : "minecraft:spawn_egg", - "id" : 628 - }, - { - "name" : "minecraft:spider_eye", - "id" : 278 - }, - { - "name" : "minecraft:spider_spawn_egg", - "id" : 446 - }, - { - "name" : "minecraft:splash_potion", - "id" : 561 - }, - { - "name" : "minecraft:sponge", - "id" : 19 - }, - { - "name" : "minecraft:spore_blossom", - "id" : -321 - }, - { - "name" : "minecraft:spruce_boat", - "id" : 378 - }, - { - "name" : "minecraft:spruce_button", - "id" : -144 - }, - { - "name" : "minecraft:spruce_door", - "id" : 553 - }, - { - "name" : "minecraft:spruce_fence_gate", - "id" : 183 - }, - { - "name" : "minecraft:spruce_pressure_plate", - "id" : -154 - }, - { - "name" : "minecraft:spruce_sign", - "id" : 576 - }, - { - "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" : 624 - }, - { - "name" : "minecraft:squid_spawn_egg", - "id" : 450 - }, - { - "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" : 320 - }, - { - "name" : "minecraft:sticky_piston", - "id" : 29 - }, - { - "name" : "minecraft:stickypistonarmcollision", - "id" : -217 - }, - { - "name" : "minecraft:stone", - "id" : 1 - }, - { - "name" : "minecraft:stone_axe", - "id" : 315 - }, - { - "name" : "minecraft:stone_brick_stairs", - "id" : 109 - }, - { - "name" : "minecraft:stone_button", - "id" : 77 - }, - { - "name" : "minecraft:stone_hoe", - "id" : 330 - }, - { - "name" : "minecraft:stone_pickaxe", - "id" : 314 - }, - { - "name" : "minecraft:stone_pressure_plate", - "id" : 70 - }, - { - "name" : "minecraft:stone_shovel", - "id" : 313 - }, - { - "name" : "minecraft:stone_stairs", - "id" : 67 - }, - { - "name" : "minecraft:stone_sword", - "id" : 312 - }, - { - "name" : "minecraft:stonebrick", - "id" : 98 - }, - { - "name" : "minecraft:stonecutter", - "id" : 245 - }, - { - "name" : "minecraft:stonecutter_block", - "id" : -197 - }, - { - "name" : "minecraft:stray_spawn_egg", - "id" : 462 - }, - { - "name" : "minecraft:strider_spawn_egg", - "id" : 495 - }, - { - "name" : "minecraft:string", - "id" : 326 - }, - { - "name" : "minecraft:stripped_acacia_log", - "id" : -8 - }, - { - "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_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" : 416 - }, - { - "name" : "minecraft:sugar_cane", - "id" : 385 - }, - { - "name" : "minecraft:suspicious_stew", - "id" : 589 - }, - { - "name" : "minecraft:sweet_berries", - "id" : 287 - }, - { - "name" : "minecraft:sweet_berry_bush", - "id" : -207 - }, - { - "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" : 525 - }, - { - "name" : "minecraft:torch", - "id" : 50 - }, - { - "name" : "minecraft:totem_of_undying", - "id" : 568 - }, - { - "name" : "minecraft:trapdoor", - "id" : 96 - }, - { - "name" : "minecraft:trapped_chest", - "id" : 146 - }, - { - "name" : "minecraft:trident", - "id" : 546 - }, - { - "name" : "minecraft:tripwire", - "id" : 132 - }, - { - "name" : "minecraft:tripwire_hook", - "id" : 131 - }, - { - "name" : "minecraft:tropical_fish", - "id" : 266 - }, - { - "name" : "minecraft:tropical_fish_bucket", - "id" : 366 - }, - { - "name" : "minecraft:tropical_fish_spawn_egg", - "id" : 479 - }, - { - "name" : "minecraft:tuff", - "id" : -333 - }, - { - "name" : "minecraft:turtle_egg", - "id" : -159 - }, - { - "name" : "minecraft:turtle_helmet", - "id" : 573 - }, - { - "name" : "minecraft:turtle_spawn_egg", - "id" : 485 - }, - { - "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:vex_spawn_egg", - "id" : 476 - }, - { - "name" : "minecraft:villager_spawn_egg", - "id" : 449 - }, - { - "name" : "minecraft:vindicator_spawn_egg", - "id" : 474 - }, - { - "name" : "minecraft:vine", - "id" : 106 - }, - { - "name" : "minecraft:wall_banner", - "id" : 177 - }, - { - "name" : "minecraft:wall_sign", - "id" : 68 - }, - { - "name" : "minecraft:wandering_trader_spawn_egg", - "id" : 492 - }, - { - "name" : "minecraft:warped_button", - "id" : -261 - }, - { - "name" : "minecraft:warped_door", - "id" : 615 - }, - { - "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" : 616 - }, - { - "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" : 613 - }, - { - "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" : 362 - }, - { - "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" : 334 - }, - { - "name" : "minecraft:wheat_seeds", - "id" : 291 - }, - { - "name" : "minecraft:white_candle", - "id" : -413 - }, - { - "name" : "minecraft:white_candle_cake", - "id" : -430 - }, - { - "name" : "minecraft:white_dye", - "id" : 410 - }, - { - "name" : "minecraft:white_glazed_terracotta", - "id" : 220 - }, - { - "name" : "minecraft:witch_spawn_egg", - "id" : 452 - }, - { - "name" : "minecraft:wither_rose", - "id" : -216 - }, - { - "name" : "minecraft:wither_skeleton_spawn_egg", - "id" : 464 - }, - { - "name" : "minecraft:wolf_spawn_egg", - "id" : 439 - }, - { - "name" : "minecraft:wood", - "id" : -212 - }, - { - "name" : "minecraft:wooden_axe", - "id" : 311 - }, - { - "name" : "minecraft:wooden_button", - "id" : 143 - }, - { - "name" : "minecraft:wooden_door", - "id" : 359 - }, - { - "name" : "minecraft:wooden_hoe", - "id" : 329 - }, - { - "name" : "minecraft:wooden_pickaxe", - "id" : 310 - }, - { - "name" : "minecraft:wooden_pressure_plate", - "id" : 72 - }, - { - "name" : "minecraft:wooden_shovel", - "id" : 309 - }, - { - "name" : "minecraft:wooden_slab", - "id" : 158 - }, - { - "name" : "minecraft:wooden_sword", - "id" : 308 - }, - { - "name" : "minecraft:wool", - "id" : 35 - }, - { - "name" : "minecraft:writable_book", - "id" : 510 - }, - { - "name" : "minecraft:written_book", - "id" : 511 - }, - { - "name" : "minecraft:yellow_candle", - "id" : -417 - }, - { - "name" : "minecraft:yellow_candle_cake", - "id" : -434 - }, - { - "name" : "minecraft:yellow_dye", - "id" : 406 - }, - { - "name" : "minecraft:yellow_flower", - "id" : 37 - }, - { - "name" : "minecraft:yellow_glazed_terracotta", - "id" : 224 - }, - { - "name" : "minecraft:zoglin_spawn_egg", - "id" : 498 - }, - { - "name" : "minecraft:zombie_horse_spawn_egg", - "id" : 468 - }, - { - "name" : "minecraft:zombie_pigman_spawn_egg", - "id" : 448 - }, - { - "name" : "minecraft:zombie_spawn_egg", - "id" : 447 - }, - { - "name" : "minecraft:zombie_villager_spawn_egg", - "id" : 477 - } -] \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_17_40.json b/core/src/main/resources/bedrock/runtime_item_states.1_17_40.json deleted file mode 100644 index 342a45afb..000000000 --- a/core/src/main/resources/bedrock/runtime_item_states.1_17_40.json +++ /dev/null @@ -1,4322 +0,0 @@ -[ - { - "name" : "minecraft:acacia_boat", - "id" : 379 - }, - { - "name" : "minecraft:acacia_button", - "id" : -140 - }, - { - "name" : "minecraft:acacia_door", - "id" : 556 - }, - { - "name" : "minecraft:acacia_fence_gate", - "id" : 187 - }, - { - "name" : "minecraft:acacia_pressure_plate", - "id" : -150 - }, - { - "name" : "minecraft:acacia_sign", - "id" : 579 - }, - { - "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" : 487 - }, - { - "name" : "minecraft:air", - "id" : -158 - }, - { - "name" : "minecraft:allow", - "id" : 210 - }, - { - "name" : "minecraft:amethyst_block", - "id" : -327 - }, - { - "name" : "minecraft:amethyst_cluster", - "id" : -329 - }, - { - "name" : "minecraft:amethyst_shard", - "id" : 624 - }, - { - "name" : "minecraft:ancient_debris", - "id" : -271 - }, - { - "name" : "minecraft:andesite_stairs", - "id" : -171 - }, - { - "name" : "minecraft:anvil", - "id" : 145 - }, - { - "name" : "minecraft:apple", - "id" : 257 - }, - { - "name" : "minecraft:armor_stand", - "id" : 552 - }, - { - "name" : "minecraft:arrow", - "id" : 301 - }, - { - "name" : "minecraft:axolotl_bucket", - "id" : 369 - }, - { - "name" : "minecraft:axolotl_spawn_egg", - "id" : 500 - }, - { - "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" : 598 - }, - { - "name" : "minecraft:bamboo", - "id" : -163 - }, - { - "name" : "minecraft:bamboo_sapling", - "id" : -164 - }, - { - "name" : "minecraft:banner", - "id" : 567 - }, - { - "name" : "minecraft:banner_pattern", - "id" : 628 - }, - { - "name" : "minecraft:barrel", - "id" : -203 - }, - { - "name" : "minecraft:barrier", - "id" : -161 - }, - { - "name" : "minecraft:basalt", - "id" : -234 - }, - { - "name" : "minecraft:bat_spawn_egg", - "id" : 453 - }, - { - "name" : "minecraft:beacon", - "id" : 138 - }, - { - "name" : "minecraft:bed", - "id" : 418 - }, - { - "name" : "minecraft:bedrock", - "id" : 7 - }, - { - "name" : "minecraft:bee_nest", - "id" : -218 - }, - { - "name" : "minecraft:bee_spawn_egg", - "id" : 494 - }, - { - "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" : 376 - }, - { - "name" : "minecraft:birch_button", - "id" : -141 - }, - { - "name" : "minecraft:birch_door", - "id" : 554 - }, - { - "name" : "minecraft:birch_fence_gate", - "id" : 184 - }, - { - "name" : "minecraft:birch_pressure_plate", - "id" : -151 - }, - { - "name" : "minecraft:birch_sign", - "id" : 577 - }, - { - "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" : 395 - }, - { - "name" : "minecraft:black_glazed_terracotta", - "id" : 235 - }, - { - "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" : 429 - }, - { - "name" : "minecraft:blaze_rod", - "id" : 423 - }, - { - "name" : "minecraft:blaze_spawn_egg", - "id" : 456 - }, - { - "name" : "minecraft:bleach", - "id" : 596 - }, - { - "name" : "minecraft:blue_candle", - "id" : -424 - }, - { - "name" : "minecraft:blue_candle_cake", - "id" : -441 - }, - { - "name" : "minecraft:blue_dye", - "id" : 399 - }, - { - "name" : "minecraft:blue_glazed_terracotta", - "id" : 231 - }, - { - "name" : "minecraft:blue_ice", - "id" : -11 - }, - { - "name" : "minecraft:boat", - "id" : 626 - }, - { - "name" : "minecraft:bone", - "id" : 415 - }, - { - "name" : "minecraft:bone_block", - "id" : 216 - }, - { - "name" : "minecraft:bone_meal", - "id" : 411 - }, - { - "name" : "minecraft:book", - "id" : 387 - }, - { - "name" : "minecraft:bookshelf", - "id" : 47 - }, - { - "name" : "minecraft:border_block", - "id" : 212 - }, - { - "name" : "minecraft:bordure_indented_banner_pattern", - "id" : 586 - }, - { - "name" : "minecraft:bow", - "id" : 300 - }, - { - "name" : "minecraft:bowl", - "id" : 321 - }, - { - "name" : "minecraft:bread", - "id" : 261 - }, - { - "name" : "minecraft:brewing_stand", - "id" : 431 - }, - { - "name" : "minecraft:brewingstandblock", - "id" : 117 - }, - { - "name" : "minecraft:brick", - "id" : 383 - }, - { - "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" : 398 - }, - { - "name" : "minecraft:brown_glazed_terracotta", - "id" : 232 - }, - { - "name" : "minecraft:brown_mushroom", - "id" : 39 - }, - { - "name" : "minecraft:brown_mushroom_block", - "id" : 99 - }, - { - "name" : "minecraft:bubble_column", - "id" : -160 - }, - { - "name" : "minecraft:bucket", - "id" : 360 - }, - { - "name" : "minecraft:budding_amethyst", - "id" : -328 - }, - { - "name" : "minecraft:cactus", - "id" : 81 - }, - { - "name" : "minecraft:cake", - "id" : 417 - }, - { - "name" : "minecraft:calcite", - "id" : -326 - }, - { - "name" : "minecraft:camera", - "id" : 593 - }, - { - "name" : "minecraft:campfire", - "id" : 588 - }, - { - "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" : 517 - }, - { - "name" : "minecraft:carrots", - "id" : 141 - }, - { - "name" : "minecraft:cartography_table", - "id" : -200 - }, - { - "name" : "minecraft:carved_pumpkin", - "id" : -155 - }, - { - "name" : "minecraft:cat_spawn_egg", - "id" : 488 - }, - { - "name" : "minecraft:cauldron", - "id" : 432 - }, - { - "name" : "minecraft:cave_spider_spawn_egg", - "id" : 457 - }, - { - "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" : 618 - }, - { - "name" : "minecraft:chain_command_block", - "id" : 189 - }, - { - "name" : "minecraft:chainmail_boots", - "id" : 342 - }, - { - "name" : "minecraft:chainmail_chestplate", - "id" : 340 - }, - { - "name" : "minecraft:chainmail_helmet", - "id" : 339 - }, - { - "name" : "minecraft:chainmail_leggings", - "id" : 341 - }, - { - "name" : "minecraft:charcoal", - "id" : 303 - }, - { - "name" : "minecraft:chemical_heat", - "id" : 192 - }, - { - "name" : "minecraft:chemistry_table", - "id" : 238 - }, - { - "name" : "minecraft:chest", - "id" : 54 - }, - { - "name" : "minecraft:chest_minecart", - "id" : 389 - }, - { - "name" : "minecraft:chicken", - "id" : 275 - }, - { - "name" : "minecraft:chicken_spawn_egg", - "id" : 435 - }, - { - "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" : 558 - }, - { - "name" : "minecraft:chorus_plant", - "id" : 240 - }, - { - "name" : "minecraft:clay", - "id" : 82 - }, - { - "name" : "minecraft:clay_ball", - "id" : 384 - }, - { - "name" : "minecraft:client_request_placeholder_block", - "id" : -465 - }, - { - "name" : "minecraft:clock", - "id" : 393 - }, - { - "name" : "minecraft:coal", - "id" : 302 - }, - { - "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" : 412 - }, - { - "name" : "minecraft:cod", - "id" : 264 - }, - { - "name" : "minecraft:cod_bucket", - "id" : 364 - }, - { - "name" : "minecraft:cod_spawn_egg", - "id" : 480 - }, - { - "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" : 563 - }, - { - "name" : "minecraft:comparator", - "id" : 522 - }, - { - "name" : "minecraft:compass", - "id" : 391 - }, - { - "name" : "minecraft:composter", - "id" : -213 - }, - { - "name" : "minecraft:compound", - "id" : 594 - }, - { - "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" : 551 - }, - { - "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" : 504 - }, - { - "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" : 436 - }, - { - "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" : 582 - }, - { - "name" : "minecraft:creeper_spawn_egg", - "id" : 441 - }, - { - "name" : "minecraft:crimson_button", - "id" : -260 - }, - { - "name" : "minecraft:crimson_door", - "id" : 615 - }, - { - "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_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" : 613 - }, - { - "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" : 575 - }, - { - "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" : 401 - }, - { - "name" : "minecraft:cyan_glazed_terracotta", - "id" : 229 - }, - { - "name" : "minecraft:dark_oak_boat", - "id" : 380 - }, - { - "name" : "minecraft:dark_oak_button", - "id" : -142 - }, - { - "name" : "minecraft:dark_oak_door", - "id" : 557 - }, - { - "name" : "minecraft:dark_oak_fence_gate", - "id" : 186 - }, - { - "name" : "minecraft:dark_oak_pressure_plate", - "id" : -152 - }, - { - "name" : "minecraft:dark_oak_sign", - "id" : 580 - }, - { - "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:debug_stick", - "id" : 590 - }, - { - "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" : 304 - }, - { - "name" : "minecraft:diamond_axe", - "id" : 319 - }, - { - "name" : "minecraft:diamond_block", - "id" : 57 - }, - { - "name" : "minecraft:diamond_boots", - "id" : 350 - }, - { - "name" : "minecraft:diamond_chestplate", - "id" : 348 - }, - { - "name" : "minecraft:diamond_helmet", - "id" : 347 - }, - { - "name" : "minecraft:diamond_hoe", - "id" : 332 - }, - { - "name" : "minecraft:diamond_horse_armor", - "id" : 533 - }, - { - "name" : "minecraft:diamond_leggings", - "id" : 349 - }, - { - "name" : "minecraft:diamond_ore", - "id" : 56 - }, - { - "name" : "minecraft:diamond_pickaxe", - "id" : 318 - }, - { - "name" : "minecraft:diamond_shovel", - "id" : 317 - }, - { - "name" : "minecraft:diamond_sword", - "id" : 316 - }, - { - "name" : "minecraft:diorite_stairs", - "id" : -170 - }, - { - "name" : "minecraft:dirt", - "id" : 3 - }, - { - "name" : "minecraft:dirt_with_roots", - "id" : -318 - }, - { - "name" : "minecraft:dispenser", - "id" : 23 - }, - { - "name" : "minecraft:dolphin_spawn_egg", - "id" : 484 - }, - { - "name" : "minecraft:donkey_spawn_egg", - "id" : 465 - }, - { - "name" : "minecraft:double_cut_copper_slab", - "id" : -368 - }, - { - "name" : "minecraft:double_plant", - "id" : 175 - }, - { - "name" : "minecraft:double_stone_slab", - "id" : 44 - }, - { - "name" : "minecraft:double_stone_slab2", - "id" : 182 - }, - { - "name" : "minecraft:double_stone_slab3", - "id" : -162 - }, - { - "name" : "minecraft:double_stone_slab4", - "id" : -166 - }, - { - "name" : "minecraft:double_wooden_slab", - "id" : 157 - }, - { - "name" : "minecraft:dragon_breath", - "id" : 560 - }, - { - "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" : 483 - }, - { - "name" : "minecraft:dye", - "id" : 627 - }, - { - "name" : "minecraft:egg", - "id" : 390 - }, - { - "name" : "minecraft:elder_guardian_spawn_egg", - "id" : 471 - }, - { - "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" : 564 - }, - { - "name" : "minecraft:emerald", - "id" : 512 - }, - { - "name" : "minecraft:emerald_block", - "id" : 133 - }, - { - "name" : "minecraft:emerald_ore", - "id" : 129 - }, - { - "name" : "minecraft:empty_map", - "id" : 515 - }, - { - "name" : "minecraft:enchanted_book", - "id" : 521 - }, - { - "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" : 630 - }, - { - "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_eye", - "id" : 433 - }, - { - "name" : "minecraft:ender_pearl", - "id" : 422 - }, - { - "name" : "minecraft:enderman_spawn_egg", - "id" : 442 - }, - { - "name" : "minecraft:endermite_spawn_egg", - "id" : 460 - }, - { - "name" : "minecraft:evoker_spawn_egg", - "id" : 475 - }, - { - "name" : "minecraft:experience_bottle", - "id" : 508 - }, - { - "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" : 327 - }, - { - "name" : "minecraft:fence", - "id" : 85 - }, - { - "name" : "minecraft:fence_gate", - "id" : 107 - }, - { - "name" : "minecraft:fermented_spider_eye", - "id" : 428 - }, - { - "name" : "minecraft:field_masoned_banner_pattern", - "id" : 585 - }, - { - "name" : "minecraft:filled_map", - "id" : 420 - }, - { - "name" : "minecraft:fire", - "id" : 51 - }, - { - "name" : "minecraft:fire_charge", - "id" : 509 - }, - { - "name" : "minecraft:firework_rocket", - "id" : 519 - }, - { - "name" : "minecraft:firework_star", - "id" : 520 - }, - { - "name" : "minecraft:fishing_rod", - "id" : 392 - }, - { - "name" : "minecraft:fletching_table", - "id" : -201 - }, - { - "name" : "minecraft:flint", - "id" : 356 - }, - { - "name" : "minecraft:flint_and_steel", - "id" : 299 - }, - { - "name" : "minecraft:flower_banner_pattern", - "id" : 581 - }, - { - "name" : "minecraft:flower_pot", - "id" : 514 - }, - { - "name" : "minecraft:flowering_azalea", - "id" : -338 - }, - { - "name" : "minecraft:flowing_lava", - "id" : 10 - }, - { - "name" : "minecraft:flowing_water", - "id" : 8 - }, - { - "name" : "minecraft:fox_spawn_egg", - "id" : 490 - }, - { - "name" : "minecraft:frame", - "id" : 513 - }, - { - "name" : "minecraft:frosted_ice", - "id" : 207 - }, - { - "name" : "minecraft:furnace", - "id" : 61 - }, - { - "name" : "minecraft:ghast_spawn_egg", - "id" : 454 - }, - { - "name" : "minecraft:ghast_tear", - "id" : 424 - }, - { - "name" : "minecraft:gilded_blackstone", - "id" : -281 - }, - { - "name" : "minecraft:glass", - "id" : 20 - }, - { - "name" : "minecraft:glass_bottle", - "id" : 427 - }, - { - "name" : "minecraft:glass_pane", - "id" : 102 - }, - { - "name" : "minecraft:glistering_melon_slice", - "id" : 434 - }, - { - "name" : "minecraft:glow_berries", - "id" : 631 - }, - { - "name" : "minecraft:glow_frame", - "id" : 622 - }, - { - "name" : "minecraft:glow_ink_sac", - "id" : 503 - }, - { - "name" : "minecraft:glow_lichen", - "id" : -411 - }, - { - "name" : "minecraft:glow_squid_spawn_egg", - "id" : 502 - }, - { - "name" : "minecraft:glow_stick", - "id" : 166 - }, - { - "name" : "minecraft:glowingobsidian", - "id" : 246 - }, - { - "name" : "minecraft:glowstone", - "id" : 89 - }, - { - "name" : "minecraft:glowstone_dust", - "id" : 394 - }, - { - "name" : "minecraft:goat_horn", - "id" : 623 - }, - { - "name" : "minecraft:goat_spawn_egg", - "id" : 501 - }, - { - "name" : "minecraft:gold_block", - "id" : 41 - }, - { - "name" : "minecraft:gold_ingot", - "id" : 306 - }, - { - "name" : "minecraft:gold_nugget", - "id" : 425 - }, - { - "name" : "minecraft:gold_ore", - "id" : 14 - }, - { - "name" : "minecraft:golden_apple", - "id" : 258 - }, - { - "name" : "minecraft:golden_axe", - "id" : 325 - }, - { - "name" : "minecraft:golden_boots", - "id" : 354 - }, - { - "name" : "minecraft:golden_carrot", - "id" : 283 - }, - { - "name" : "minecraft:golden_chestplate", - "id" : 352 - }, - { - "name" : "minecraft:golden_helmet", - "id" : 351 - }, - { - "name" : "minecraft:golden_hoe", - "id" : 333 - }, - { - "name" : "minecraft:golden_horse_armor", - "id" : 532 - }, - { - "name" : "minecraft:golden_leggings", - "id" : 353 - }, - { - "name" : "minecraft:golden_pickaxe", - "id" : 324 - }, - { - "name" : "minecraft:golden_rail", - "id" : 27 - }, - { - "name" : "minecraft:golden_shovel", - "id" : 323 - }, - { - "name" : "minecraft:golden_sword", - "id" : 322 - }, - { - "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" : 403 - }, - { - "name" : "minecraft:gray_glazed_terracotta", - "id" : 227 - }, - { - "name" : "minecraft:green_candle", - "id" : -426 - }, - { - "name" : "minecraft:green_candle_cake", - "id" : -443 - }, - { - "name" : "minecraft:green_dye", - "id" : 397 - }, - { - "name" : "minecraft:green_glazed_terracotta", - "id" : 233 - }, - { - "name" : "minecraft:grindstone", - "id" : -195 - }, - { - "name" : "minecraft:guardian_spawn_egg", - "id" : 461 - }, - { - "name" : "minecraft:gunpowder", - "id" : 328 - }, - { - "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" : 571 - }, - { - "name" : "minecraft:heavy_weighted_pressure_plate", - "id" : 148 - }, - { - "name" : "minecraft:hoglin_spawn_egg", - "id" : 496 - }, - { - "name" : "minecraft:honey_block", - "id" : -220 - }, - { - "name" : "minecraft:honey_bottle", - "id" : 592 - }, - { - "name" : "minecraft:honeycomb", - "id" : 591 - }, - { - "name" : "minecraft:honeycomb_block", - "id" : -221 - }, - { - "name" : "minecraft:hopper", - "id" : 527 - }, - { - "name" : "minecraft:hopper_minecart", - "id" : 526 - }, - { - "name" : "minecraft:horse_spawn_egg", - "id" : 458 - }, - { - "name" : "minecraft:husk_spawn_egg", - "id" : 463 - }, - { - "name" : "minecraft:ice", - "id" : 79 - }, - { - "name" : "minecraft:ice_bomb", - "id" : 595 - }, - { - "name" : "minecraft:infested_deepslate", - "id" : -454 - }, - { - "name" : "minecraft:info_update", - "id" : 248 - }, - { - "name" : "minecraft:info_update2", - "id" : 249 - }, - { - "name" : "minecraft:ink_sac", - "id" : 413 - }, - { - "name" : "minecraft:invisiblebedrock", - "id" : 95 - }, - { - "name" : "minecraft:iron_axe", - "id" : 298 - }, - { - "name" : "minecraft:iron_bars", - "id" : 101 - }, - { - "name" : "minecraft:iron_block", - "id" : 42 - }, - { - "name" : "minecraft:iron_boots", - "id" : 346 - }, - { - "name" : "minecraft:iron_chestplate", - "id" : 344 - }, - { - "name" : "minecraft:iron_door", - "id" : 372 - }, - { - "name" : "minecraft:iron_helmet", - "id" : 343 - }, - { - "name" : "minecraft:iron_hoe", - "id" : 331 - }, - { - "name" : "minecraft:iron_horse_armor", - "id" : 531 - }, - { - "name" : "minecraft:iron_ingot", - "id" : 305 - }, - { - "name" : "minecraft:iron_leggings", - "id" : 345 - }, - { - "name" : "minecraft:iron_nugget", - "id" : 569 - }, - { - "name" : "minecraft:iron_ore", - "id" : 15 - }, - { - "name" : "minecraft:iron_pickaxe", - "id" : 297 - }, - { - "name" : "minecraft:iron_shovel", - "id" : 296 - }, - { - "name" : "minecraft:iron_sword", - "id" : 307 - }, - { - "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.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.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" : 377 - }, - { - "name" : "minecraft:jungle_button", - "id" : -143 - }, - { - "name" : "minecraft:jungle_door", - "id" : 555 - }, - { - "name" : "minecraft:jungle_fence_gate", - "id" : 185 - }, - { - "name" : "minecraft:jungle_pressure_plate", - "id" : -153 - }, - { - "name" : "minecraft:jungle_sign", - "id" : 578 - }, - { - "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" : 382 - }, - { - "name" : "minecraft:ladder", - "id" : 65 - }, - { - "name" : "minecraft:lantern", - "id" : -208 - }, - { - "name" : "minecraft:lapis_block", - "id" : 22 - }, - { - "name" : "minecraft:lapis_lazuli", - "id" : 414 - }, - { - "name" : "minecraft:lapis_ore", - "id" : 21 - }, - { - "name" : "minecraft:large_amethyst_bud", - "id" : -330 - }, - { - "name" : "minecraft:lava", - "id" : 11 - }, - { - "name" : "minecraft:lava_bucket", - "id" : 363 - }, - { - "name" : "minecraft:lava_cauldron", - "id" : -210 - }, - { - "name" : "minecraft:lead", - "id" : 547 - }, - { - "name" : "minecraft:leather", - "id" : 381 - }, - { - "name" : "minecraft:leather_boots", - "id" : 338 - }, - { - "name" : "minecraft:leather_chestplate", - "id" : 336 - }, - { - "name" : "minecraft:leather_helmet", - "id" : 335 - }, - { - "name" : "minecraft:leather_horse_armor", - "id" : 530 - }, - { - "name" : "minecraft:leather_leggings", - "id" : 337 - }, - { - "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" : 407 - }, - { - "name" : "minecraft:light_blue_glazed_terracotta", - "id" : 223 - }, - { - "name" : "minecraft:light_gray_candle", - "id" : -421 - }, - { - "name" : "minecraft:light_gray_candle_cake", - "id" : -438 - }, - { - "name" : "minecraft:light_gray_dye", - "id" : 402 - }, - { - "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" : 405 - }, - { - "name" : "minecraft:lime_glazed_terracotta", - "id" : 225 - }, - { - "name" : "minecraft:lingering_potion", - "id" : 562 - }, - { - "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" : 473 - }, - { - "name" : "minecraft:lodestone", - "id" : -222 - }, - { - "name" : "minecraft:lodestone_compass", - "id" : 601 - }, - { - "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" : 408 - }, - { - "name" : "minecraft:magenta_glazed_terracotta", - "id" : 222 - }, - { - "name" : "minecraft:magma", - "id" : 213 - }, - { - "name" : "minecraft:magma_cream", - "id" : 430 - }, - { - "name" : "minecraft:magma_cube_spawn_egg", - "id" : 455 - }, - { - "name" : "minecraft:medicine", - "id" : 599 - }, - { - "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" : 361 - }, - { - "name" : "minecraft:minecart", - "id" : 370 - }, - { - "name" : "minecraft:mob_spawner", - "id" : 52 - }, - { - "name" : "minecraft:mojang_banner_pattern", - "id" : 584 - }, - { - "name" : "minecraft:monster_egg", - "id" : 97 - }, - { - "name" : "minecraft:mooshroom_spawn_egg", - "id" : 440 - }, - { - "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:movingblock", - "id" : 250 - }, - { - "name" : "minecraft:mule_spawn_egg", - "id" : 466 - }, - { - "name" : "minecraft:mushroom_stew", - "id" : 260 - }, - { - "name" : "minecraft:music_disc_11", - "id" : 544 - }, - { - "name" : "minecraft:music_disc_13", - "id" : 534 - }, - { - "name" : "minecraft:music_disc_blocks", - "id" : 536 - }, - { - "name" : "minecraft:music_disc_cat", - "id" : 535 - }, - { - "name" : "minecraft:music_disc_chirp", - "id" : 537 - }, - { - "name" : "minecraft:music_disc_far", - "id" : 538 - }, - { - "name" : "minecraft:music_disc_mall", - "id" : 539 - }, - { - "name" : "minecraft:music_disc_mellohi", - "id" : 540 - }, - { - "name" : "minecraft:music_disc_pigstep", - "id" : 619 - }, - { - "name" : "minecraft:music_disc_stal", - "id" : 541 - }, - { - "name" : "minecraft:music_disc_strad", - "id" : 542 - }, - { - "name" : "minecraft:music_disc_wait", - "id" : 545 - }, - { - "name" : "minecraft:music_disc_ward", - "id" : 543 - }, - { - "name" : "minecraft:mutton", - "id" : 550 - }, - { - "name" : "minecraft:mycelium", - "id" : 110 - }, - { - "name" : "minecraft:mysterious_frame", - "id" : -466 - }, - { - "name" : "minecraft:mysterious_frame_slot", - "id" : -467 - }, - { - "name" : "minecraft:name_tag", - "id" : 548 - }, - { - "name" : "minecraft:nautilus_shell", - "id" : 570 - }, - { - "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" : 620 - }, - { - "name" : "minecraft:nether_star", - "id" : 518 - }, - { - "name" : "minecraft:nether_wart", - "id" : 294 - }, - { - "name" : "minecraft:nether_wart_block", - "id" : 214 - }, - { - "name" : "minecraft:netherbrick", - "id" : 523 - }, - { - "name" : "minecraft:netherite_axe", - "id" : 606 - }, - { - "name" : "minecraft:netherite_block", - "id" : -270 - }, - { - "name" : "minecraft:netherite_boots", - "id" : 611 - }, - { - "name" : "minecraft:netherite_chestplate", - "id" : 609 - }, - { - "name" : "minecraft:netherite_helmet", - "id" : 608 - }, - { - "name" : "minecraft:netherite_hoe", - "id" : 607 - }, - { - "name" : "minecraft:netherite_ingot", - "id" : 602 - }, - { - "name" : "minecraft:netherite_leggings", - "id" : 610 - }, - { - "name" : "minecraft:netherite_pickaxe", - "id" : 605 - }, - { - "name" : "minecraft:netherite_scrap", - "id" : 612 - }, - { - "name" : "minecraft:netherite_shovel", - "id" : 604 - }, - { - "name" : "minecraft:netherite_sword", - "id" : 603 - }, - { - "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" : 470 - }, - { - "name" : "minecraft:oak_boat", - "id" : 375 - }, - { - "name" : "minecraft:oak_sign", - "id" : 358 - }, - { - "name" : "minecraft:oak_stairs", - "id" : 53 - }, - { - "name" : "minecraft:observer", - "id" : 251 - }, - { - "name" : "minecraft:obsidian", - "id" : 49 - }, - { - "name" : "minecraft:ocelot_spawn_egg", - "id" : 451 - }, - { - "name" : "minecraft:orange_candle", - "id" : -414 - }, - { - "name" : "minecraft:orange_candle_cake", - "id" : -431 - }, - { - "name" : "minecraft:orange_dye", - "id" : 409 - }, - { - "name" : "minecraft:orange_glazed_terracotta", - "id" : 221 - }, - { - "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:painting", - "id" : 357 - }, - { - "name" : "minecraft:panda_spawn_egg", - "id" : 489 - }, - { - "name" : "minecraft:paper", - "id" : 386 - }, - { - "name" : "minecraft:parrot_spawn_egg", - "id" : 478 - }, - { - "name" : "minecraft:phantom_membrane", - "id" : 574 - }, - { - "name" : "minecraft:phantom_spawn_egg", - "id" : 486 - }, - { - "name" : "minecraft:pig_spawn_egg", - "id" : 437 - }, - { - "name" : "minecraft:piglin_banner_pattern", - "id" : 587 - }, - { - "name" : "minecraft:piglin_brute_spawn_egg", - "id" : 499 - }, - { - "name" : "minecraft:piglin_spawn_egg", - "id" : 497 - }, - { - "name" : "minecraft:pillager_spawn_egg", - "id" : 491 - }, - { - "name" : "minecraft:pink_candle", - "id" : -419 - }, - { - "name" : "minecraft:pink_candle_cake", - "id" : -436 - }, - { - "name" : "minecraft:pink_dye", - "id" : 404 - }, - { - "name" : "minecraft:pink_glazed_terracotta", - "id" : 226 - }, - { - "name" : "minecraft:piston", - "id" : 33 - }, - { - "name" : "minecraft:pistonarmcollision", - "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" : 472 - }, - { - "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" : 559 - }, - { - "name" : "minecraft:porkchop", - "id" : 262 - }, - { - "name" : "minecraft:portal", - "id" : 90 - }, - { - "name" : "minecraft:potato", - "id" : 280 - }, - { - "name" : "minecraft:potatoes", - "id" : 142 - }, - { - "name" : "minecraft:potion", - "id" : 426 - }, - { - "name" : "minecraft:powder_snow", - "id" : -306 - }, - { - "name" : "minecraft:powder_snow_bucket", - "id" : 368 - }, - { - "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" : 549 - }, - { - "name" : "minecraft:prismarine_shard", - "id" : 565 - }, - { - "name" : "minecraft:prismarine_stairs", - "id" : -2 - }, - { - "name" : "minecraft:pufferfish", - "id" : 267 - }, - { - "name" : "minecraft:pufferfish_bucket", - "id" : 367 - }, - { - "name" : "minecraft:pufferfish_spawn_egg", - "id" : 481 - }, - { - "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" : 400 - }, - { - "name" : "minecraft:purple_glazed_terracotta", - "id" : 219 - }, - { - "name" : "minecraft:purpur_block", - "id" : 201 - }, - { - "name" : "minecraft:purpur_stairs", - "id" : 203 - }, - { - "name" : "minecraft:quartz", - "id" : 524 - }, - { - "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" : 528 - }, - { - "name" : "minecraft:rabbit_hide", - "id" : 529 - }, - { - "name" : "minecraft:rabbit_spawn_egg", - "id" : 459 - }, - { - "name" : "minecraft:rabbit_stew", - "id" : 290 - }, - { - "name" : "minecraft:rail", - "id" : 66 - }, - { - "name" : "minecraft:rapid_fertilizer", - "id" : 597 - }, - { - "name" : "minecraft:ravager_spawn_egg", - "id" : 493 - }, - { - "name" : "minecraft:raw_copper", - "id" : 507 - }, - { - "name" : "minecraft:raw_copper_block", - "id" : -452 - }, - { - "name" : "minecraft:raw_gold", - "id" : 506 - }, - { - "name" : "minecraft:raw_gold_block", - "id" : -453 - }, - { - "name" : "minecraft:raw_iron", - "id" : 505 - }, - { - "name" : "minecraft:raw_iron_block", - "id" : -451 - }, - { - "name" : "minecraft:real_double_stone_slab", - "id" : 43 - }, - { - "name" : "minecraft:real_double_stone_slab2", - "id" : 181 - }, - { - "name" : "minecraft:real_double_stone_slab3", - "id" : -167 - }, - { - "name" : "minecraft:real_double_stone_slab4", - "id" : -168 - }, - { - "name" : "minecraft:red_candle", - "id" : -427 - }, - { - "name" : "minecraft:red_candle_cake", - "id" : -444 - }, - { - "name" : "minecraft:red_dye", - "id" : 396 - }, - { - "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:redstone", - "id" : 373 - }, - { - "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:repeater", - "id" : 419 - }, - { - "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" : 371 - }, - { - "name" : "minecraft:salmon", - "id" : 265 - }, - { - "name" : "minecraft:salmon_bucket", - "id" : 365 - }, - { - "name" : "minecraft:salmon_spawn_egg", - "id" : 482 - }, - { - "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" : 572 - }, - { - "name" : "minecraft:sea_pickle", - "id" : -156 - }, - { - "name" : "minecraft:seagrass", - "id" : -130 - }, - { - "name" : "minecraft:sealantern", - "id" : 169 - }, - { - "name" : "minecraft:shears", - "id" : 421 - }, - { - "name" : "minecraft:sheep_spawn_egg", - "id" : 438 - }, - { - "name" : "minecraft:shield", - "id" : 355 - }, - { - "name" : "minecraft:shroomlight", - "id" : -230 - }, - { - "name" : "minecraft:shulker_box", - "id" : 218 - }, - { - "name" : "minecraft:shulker_shell", - "id" : 566 - }, - { - "name" : "minecraft:shulker_spawn_egg", - "id" : 469 - }, - { - "name" : "minecraft:silver_glazed_terracotta", - "id" : 228 - }, - { - "name" : "minecraft:silverfish_spawn_egg", - "id" : 443 - }, - { - "name" : "minecraft:skeleton_horse_spawn_egg", - "id" : 467 - }, - { - "name" : "minecraft:skeleton_spawn_egg", - "id" : 444 - }, - { - "name" : "minecraft:skull", - "id" : 516 - }, - { - "name" : "minecraft:skull_banner_pattern", - "id" : 583 - }, - { - "name" : "minecraft:slime", - "id" : 165 - }, - { - "name" : "minecraft:slime_ball", - "id" : 388 - }, - { - "name" : "minecraft:slime_spawn_egg", - "id" : 445 - }, - { - "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:snow", - "id" : 80 - }, - { - "name" : "minecraft:snow_layer", - "id" : 78 - }, - { - "name" : "minecraft:snowball", - "id" : 374 - }, - { - "name" : "minecraft:soul_campfire", - "id" : 621 - }, - { - "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" : 600 - }, - { - "name" : "minecraft:spawn_egg", - "id" : 629 - }, - { - "name" : "minecraft:spider_eye", - "id" : 278 - }, - { - "name" : "minecraft:spider_spawn_egg", - "id" : 446 - }, - { - "name" : "minecraft:splash_potion", - "id" : 561 - }, - { - "name" : "minecraft:sponge", - "id" : 19 - }, - { - "name" : "minecraft:spore_blossom", - "id" : -321 - }, - { - "name" : "minecraft:spruce_boat", - "id" : 378 - }, - { - "name" : "minecraft:spruce_button", - "id" : -144 - }, - { - "name" : "minecraft:spruce_door", - "id" : 553 - }, - { - "name" : "minecraft:spruce_fence_gate", - "id" : 183 - }, - { - "name" : "minecraft:spruce_pressure_plate", - "id" : -154 - }, - { - "name" : "minecraft:spruce_sign", - "id" : 576 - }, - { - "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" : 625 - }, - { - "name" : "minecraft:squid_spawn_egg", - "id" : 450 - }, - { - "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" : 320 - }, - { - "name" : "minecraft:sticky_piston", - "id" : 29 - }, - { - "name" : "minecraft:stickypistonarmcollision", - "id" : -217 - }, - { - "name" : "minecraft:stone", - "id" : 1 - }, - { - "name" : "minecraft:stone_axe", - "id" : 315 - }, - { - "name" : "minecraft:stone_brick_stairs", - "id" : 109 - }, - { - "name" : "minecraft:stone_button", - "id" : 77 - }, - { - "name" : "minecraft:stone_hoe", - "id" : 330 - }, - { - "name" : "minecraft:stone_pickaxe", - "id" : 314 - }, - { - "name" : "minecraft:stone_pressure_plate", - "id" : 70 - }, - { - "name" : "minecraft:stone_shovel", - "id" : 313 - }, - { - "name" : "minecraft:stone_stairs", - "id" : 67 - }, - { - "name" : "minecraft:stone_sword", - "id" : 312 - }, - { - "name" : "minecraft:stonebrick", - "id" : 98 - }, - { - "name" : "minecraft:stonecutter", - "id" : 245 - }, - { - "name" : "minecraft:stonecutter_block", - "id" : -197 - }, - { - "name" : "minecraft:stray_spawn_egg", - "id" : 462 - }, - { - "name" : "minecraft:strider_spawn_egg", - "id" : 495 - }, - { - "name" : "minecraft:string", - "id" : 326 - }, - { - "name" : "minecraft:stripped_acacia_log", - "id" : -8 - }, - { - "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_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" : 416 - }, - { - "name" : "minecraft:sugar_cane", - "id" : 385 - }, - { - "name" : "minecraft:suspicious_stew", - "id" : 589 - }, - { - "name" : "minecraft:sweet_berries", - "id" : 287 - }, - { - "name" : "minecraft:sweet_berry_bush", - "id" : -207 - }, - { - "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" : 525 - }, - { - "name" : "minecraft:torch", - "id" : 50 - }, - { - "name" : "minecraft:totem_of_undying", - "id" : 568 - }, - { - "name" : "minecraft:trapdoor", - "id" : 96 - }, - { - "name" : "minecraft:trapped_chest", - "id" : 146 - }, - { - "name" : "minecraft:trident", - "id" : 546 - }, - { - "name" : "minecraft:tripwire", - "id" : 132 - }, - { - "name" : "minecraft:tripwire_hook", - "id" : 131 - }, - { - "name" : "minecraft:tropical_fish", - "id" : 266 - }, - { - "name" : "minecraft:tropical_fish_bucket", - "id" : 366 - }, - { - "name" : "minecraft:tropical_fish_spawn_egg", - "id" : 479 - }, - { - "name" : "minecraft:tuff", - "id" : -333 - }, - { - "name" : "minecraft:turtle_egg", - "id" : -159 - }, - { - "name" : "minecraft:turtle_helmet", - "id" : 573 - }, - { - "name" : "minecraft:turtle_spawn_egg", - "id" : 485 - }, - { - "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:vex_spawn_egg", - "id" : 476 - }, - { - "name" : "minecraft:villager_spawn_egg", - "id" : 449 - }, - { - "name" : "minecraft:vindicator_spawn_egg", - "id" : 474 - }, - { - "name" : "minecraft:vine", - "id" : 106 - }, - { - "name" : "minecraft:wall_banner", - "id" : 177 - }, - { - "name" : "minecraft:wall_sign", - "id" : 68 - }, - { - "name" : "minecraft:wandering_trader_spawn_egg", - "id" : 492 - }, - { - "name" : "minecraft:warped_button", - "id" : -261 - }, - { - "name" : "minecraft:warped_door", - "id" : 616 - }, - { - "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" : 617 - }, - { - "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" : 614 - }, - { - "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" : 362 - }, - { - "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" : 334 - }, - { - "name" : "minecraft:wheat_seeds", - "id" : 291 - }, - { - "name" : "minecraft:white_candle", - "id" : -413 - }, - { - "name" : "minecraft:white_candle_cake", - "id" : -430 - }, - { - "name" : "minecraft:white_dye", - "id" : 410 - }, - { - "name" : "minecraft:white_glazed_terracotta", - "id" : 220 - }, - { - "name" : "minecraft:witch_spawn_egg", - "id" : 452 - }, - { - "name" : "minecraft:wither_rose", - "id" : -216 - }, - { - "name" : "minecraft:wither_skeleton_spawn_egg", - "id" : 464 - }, - { - "name" : "minecraft:wolf_spawn_egg", - "id" : 439 - }, - { - "name" : "minecraft:wood", - "id" : -212 - }, - { - "name" : "minecraft:wooden_axe", - "id" : 311 - }, - { - "name" : "minecraft:wooden_button", - "id" : 143 - }, - { - "name" : "minecraft:wooden_door", - "id" : 359 - }, - { - "name" : "minecraft:wooden_hoe", - "id" : 329 - }, - { - "name" : "minecraft:wooden_pickaxe", - "id" : 310 - }, - { - "name" : "minecraft:wooden_pressure_plate", - "id" : 72 - }, - { - "name" : "minecraft:wooden_shovel", - "id" : 309 - }, - { - "name" : "minecraft:wooden_slab", - "id" : 158 - }, - { - "name" : "minecraft:wooden_sword", - "id" : 308 - }, - { - "name" : "minecraft:wool", - "id" : 35 - }, - { - "name" : "minecraft:writable_book", - "id" : 510 - }, - { - "name" : "minecraft:written_book", - "id" : 511 - }, - { - "name" : "minecraft:yellow_candle", - "id" : -417 - }, - { - "name" : "minecraft:yellow_candle_cake", - "id" : -434 - }, - { - "name" : "minecraft:yellow_dye", - "id" : 406 - }, - { - "name" : "minecraft:yellow_flower", - "id" : 37 - }, - { - "name" : "minecraft:yellow_glazed_terracotta", - "id" : 224 - }, - { - "name" : "minecraft:zoglin_spawn_egg", - "id" : 498 - }, - { - "name" : "minecraft:zombie_horse_spawn_egg", - "id" : 468 - }, - { - "name" : "minecraft:zombie_pigman_spawn_egg", - "id" : 448 - }, - { - "name" : "minecraft:zombie_spawn_egg", - "id" : 447 - }, - { - "name" : "minecraft:zombie_villager_spawn_egg", - "id" : 477 - } -] \ No newline at end of file diff --git a/core/src/main/resources/bedrock/runtime_item_states.1_18_0.json b/core/src/main/resources/bedrock/runtime_item_states.1_19_0.json similarity index 94% rename from core/src/main/resources/bedrock/runtime_item_states.1_18_0.json rename to core/src/main/resources/bedrock/runtime_item_states.1_19_0.json index 315547438..b1ffe6353 100644 --- a/core/src/main/resources/bedrock/runtime_item_states.1_18_0.json +++ b/core/src/main/resources/bedrock/runtime_item_states.1_19_0.json @@ -7,6 +7,10 @@ "name" : "minecraft:acacia_button", "id" : -140 }, + { + "name" : "minecraft:acacia_chest_boat", + "id" : 643 + }, { "name" : "minecraft:acacia_door", "id" : 556 @@ -51,6 +55,10 @@ "name" : "minecraft:air", "id" : -158 }, + { + "name" : "minecraft:allay_spawn_egg", + "id" : 631 + }, { "name" : "minecraft:allow", "id" : 210 @@ -117,7 +125,7 @@ }, { "name" : "minecraft:balloon", - "id" : 597 + "id" : 598 }, { "name" : "minecraft:bamboo", @@ -133,7 +141,7 @@ }, { "name" : "minecraft:banner_pattern", - "id" : 629 + "id" : 651 }, { "name" : "minecraft:barrel", @@ -207,6 +215,10 @@ "name" : "minecraft:birch_button", "id" : -141 }, + { + "name" : "minecraft:birch_chest_boat", + "id" : 640 + }, { "name" : "minecraft:birch_door", "id" : 554 @@ -293,7 +305,7 @@ }, { "name" : "minecraft:bleach", - "id" : 595 + "id" : 596 }, { "name" : "minecraft:blue_candle", @@ -317,7 +329,7 @@ }, { "name" : "minecraft:boat", - "id" : 627 + "id" : 649 }, { "name" : "minecraft:bone", @@ -363,10 +375,6 @@ "name" : "minecraft:brewing_stand", "id" : 431 }, - { - "name" : "minecraft:brewingstandblock", - "id" : 117 - }, { "name" : "minecraft:brick", "id" : 383 @@ -429,11 +437,11 @@ }, { "name" : "minecraft:camera", - "id" : 592 + "id" : 593 }, { "name" : "minecraft:campfire", - "id" : 588 + "id" : 589 }, { "name" : "minecraft:candle", @@ -493,7 +501,7 @@ }, { "name" : "minecraft:chain", - "id" : 618 + "id" : 619 }, { "name" : "minecraft:chain_command_block", @@ -531,6 +539,10 @@ "name" : "minecraft:chest", "id" : 54 }, + { + "name" : "minecraft:chest_boat", + "id" : 646 + }, { "name" : "minecraft:chest_minecart", "id" : 389 @@ -673,7 +685,7 @@ }, { "name" : "minecraft:compound", - "id" : 593 + "id" : 594 }, { "name" : "minecraft:concrete", @@ -797,7 +809,7 @@ }, { "name" : "minecraft:crimson_door", - "id" : 615 + "id" : 616 }, { "name" : "minecraft:crimson_double_slab", @@ -837,7 +849,7 @@ }, { "name" : "minecraft:crimson_sign", - "id" : 613 + "id" : 614 }, { "name" : "minecraft:crimson_slab", @@ -907,6 +919,10 @@ "name" : "minecraft:dark_oak_button", "id" : -142 }, + { + "name" : "minecraft:dark_oak_chest_boat", + "id" : 644 + }, { "name" : "minecraft:dark_oak_door", "id" : 557 @@ -1103,6 +1119,10 @@ "name" : "minecraft:dirt_with_roots", "id" : -318 }, + { + "name" : "minecraft:disc_fragment_5", + "id" : 638 + }, { "name" : "minecraft:dispenser", "id" : 23 @@ -1124,20 +1144,20 @@ "id" : 175 }, { - "name" : "minecraft:double_stone_slab", - "id" : 44 + "name" : "minecraft:double_stone_block_slab", + "id" : 43 }, { - "name" : "minecraft:double_stone_slab2", - "id" : 182 + "name" : "minecraft:double_stone_block_slab2", + "id" : 181 }, { - "name" : "minecraft:double_stone_slab3", - "id" : -162 + "name" : "minecraft:double_stone_block_slab3", + "id" : -167 }, { - "name" : "minecraft:double_stone_slab4", - "id" : -166 + "name" : "minecraft:double_stone_block_slab4", + "id" : -168 }, { "name" : "minecraft:double_wooden_slab", @@ -1173,7 +1193,11 @@ }, { "name" : "minecraft:dye", - "id" : 628 + "id" : 650 + }, + { + "name" : "minecraft:echo_shard", + "id" : 648 }, { "name" : "minecraft:egg", @@ -1701,7 +1725,7 @@ }, { "name" : "minecraft:end_crystal", - "id" : 631 + "id" : 653 }, { "name" : "minecraft:end_gateway", @@ -1807,6 +1831,10 @@ "name" : "minecraft:fire_charge", "id" : 509 }, + { + "name" : "minecraft:firefly_spawn_egg", + "id" : 633 + }, { "name" : "minecraft:firework_rocket", "id" : 519 @@ -1859,6 +1887,14 @@ "name" : "minecraft:frame", "id" : 513 }, + { + "name" : "minecraft:frog_spawn", + "id" : -468 + }, + { + "name" : "minecraft:frog_spawn_egg", + "id" : 628 + }, { "name" : "minecraft:frosted_ice", "id" : 207 @@ -1895,13 +1931,17 @@ "name" : "minecraft:glistering_melon_slice", "id" : 434 }, + { + "name" : "minecraft:globe_banner_pattern", + "id" : 588 + }, { "name" : "minecraft:glow_berries", - "id" : 632 + "id" : 654 }, { "name" : "minecraft:glow_frame", - "id" : 622 + "id" : 623 }, { "name" : "minecraft:glow_ink_sac", @@ -1917,7 +1957,7 @@ }, { "name" : "minecraft:glow_stick", - "id" : 600 + "id" : 601 }, { "name" : "minecraft:glowingobsidian", @@ -1933,7 +1973,7 @@ }, { "name" : "minecraft:goat_horn", - "id" : 623 + "id" : 627 }, { "name" : "minecraft:goat_spawn_egg", @@ -2113,11 +2153,11 @@ }, { "name" : "minecraft:honey_bottle", - "id" : 591 + "id" : 592 }, { "name" : "minecraft:honeycomb", - "id" : 590 + "id" : 591 }, { "name" : "minecraft:honeycomb_block", @@ -2145,7 +2185,7 @@ }, { "name" : "minecraft:ice_bomb", - "id" : 594 + "id" : 595 }, { "name" : "minecraft:infested_deepslate", @@ -2164,7 +2204,7 @@ "id" : 413 }, { - "name" : "minecraft:invisiblebedrock", + "name" : "minecraft:invisible_bedrock", "id" : 95 }, { @@ -2251,6 +2291,10 @@ "name" : "minecraft:item.birch_door", "id" : 194 }, + { + "name" : "minecraft:item.brewing_stand", + "id" : 117 + }, { "name" : "minecraft:item.cake", "id" : 92 @@ -2307,6 +2351,10 @@ "name" : "minecraft:item.kelp", "id" : -138 }, + { + "name" : "minecraft:item.mangrove_door", + "id" : -493 + }, { "name" : "minecraft:item.nether_sprouts", "id" : -238 @@ -2359,6 +2407,10 @@ "name" : "minecraft:jungle_button", "id" : -143 }, + { + "name" : "minecraft:jungle_chest_boat", + "id" : 641 + }, { "name" : "minecraft:jungle_door", "id" : 555 @@ -2573,7 +2625,7 @@ }, { "name" : "minecraft:lodestone_compass", - "id" : 601 + "id" : 602 }, { "name" : "minecraft:log", @@ -2615,9 +2667,89 @@ "name" : "minecraft:magma_cube_spawn_egg", "id" : 455 }, + { + "name" : "minecraft:mangrove_boat", + "id" : 636 + }, + { + "name" : "minecraft:mangrove_button", + "id" : -487 + }, + { + "name" : "minecraft:mangrove_chest_boat", + "id" : 645 + }, + { + "name" : "minecraft:mangrove_door", + "id" : 634 + }, + { + "name" : "minecraft:mangrove_double_slab", + "id" : -499 + }, + { + "name" : "minecraft:mangrove_fence", + "id" : -491 + }, + { + "name" : "minecraft:mangrove_fence_gate", + "id" : -492 + }, + { + "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" : 635 + }, + { + "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" : 598 + "id" : 599 }, { "name" : "minecraft:medium_amethyst_bud", @@ -2684,9 +2816,37 @@ "id" : -175 }, { - "name" : "minecraft:movingblock", + "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" : 466 @@ -2703,6 +2863,10 @@ "name" : "minecraft:music_disc_13", "id" : 534 }, + { + "name" : "minecraft:music_disc_5", + "id" : 637 + }, { "name" : "minecraft:music_disc_blocks", "id" : 536 @@ -2733,7 +2897,7 @@ }, { "name" : "minecraft:music_disc_pigstep", - "id" : 619 + "id" : 620 }, { "name" : "minecraft:music_disc_stal", @@ -2759,14 +2923,6 @@ "name" : "minecraft:mycelium", "id" : 110 }, - { - "name" : "minecraft:mysterious_frame", - "id" : -466 - }, - { - "name" : "minecraft:mysterious_frame_slot", - "id" : -467 - }, { "name" : "minecraft:name_tag", "id" : 548 @@ -2793,7 +2949,7 @@ }, { "name" : "minecraft:nether_sprouts", - "id" : 620 + "id" : 621 }, { "name" : "minecraft:nether_star", @@ -2813,7 +2969,7 @@ }, { "name" : "minecraft:netherite_axe", - "id" : 606 + "id" : 607 }, { "name" : "minecraft:netherite_block", @@ -2821,43 +2977,43 @@ }, { "name" : "minecraft:netherite_boots", - "id" : 611 - }, - { - "name" : "minecraft:netherite_chestplate", - "id" : 609 - }, - { - "name" : "minecraft:netherite_helmet", - "id" : 608 - }, - { - "name" : "minecraft:netherite_hoe", - "id" : 607 - }, - { - "name" : "minecraft:netherite_ingot", - "id" : 602 - }, - { - "name" : "minecraft:netherite_leggings", - "id" : 610 - }, - { - "name" : "minecraft:netherite_pickaxe", - "id" : 605 - }, - { - "name" : "minecraft:netherite_scrap", "id" : 612 }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 610 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 609 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 608 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 603 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 611 + }, + { + "name" : "minecraft:netherite_pickaxe", + "id" : 606 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 613 + }, { "name" : "minecraft:netherite_shovel", - "id" : 604 + "id" : 605 }, { "name" : "minecraft:netherite_sword", - "id" : 603 + "id" : 604 }, { "name" : "minecraft:netherrack", @@ -2883,6 +3039,10 @@ "name" : "minecraft:oak_boat", "id" : 375 }, + { + "name" : "minecraft:oak_chest_boat", + "id" : 639 + }, { "name" : "minecraft:oak_sign", "id" : 358 @@ -2903,6 +3063,10 @@ "name" : "minecraft:ocelot_spawn_egg", "id" : 451 }, + { + "name" : "minecraft:ochre_froglight", + "id" : -471 + }, { "name" : "minecraft:orange_candle", "id" : -414 @@ -2943,6 +3107,10 @@ "name" : "minecraft:packed_ice", "id" : 174 }, + { + "name" : "minecraft:packed_mud", + "id" : -477 + }, { "name" : "minecraft:painting", "id" : 357 @@ -2959,6 +3127,10 @@ "name" : "minecraft:parrot_spawn_egg", "id" : 478 }, + { + "name" : "minecraft:pearlescent_froglight", + "id" : -469 + }, { "name" : "minecraft:phantom_membrane", "id" : 574 @@ -3008,7 +3180,7 @@ "id" : 33 }, { - "name" : "minecraft:pistonarmcollision", + "name" : "minecraft:piston_arm_collision", "id" : 34 }, { @@ -3273,7 +3445,7 @@ }, { "name" : "minecraft:rapid_fertilizer", - "id" : 596 + "id" : 597 }, { "name" : "minecraft:ravager_spawn_egg", @@ -3304,20 +3476,8 @@ "id" : -451 }, { - "name" : "minecraft:real_double_stone_slab", - "id" : 43 - }, - { - "name" : "minecraft:real_double_stone_slab2", - "id" : 181 - }, - { - "name" : "minecraft:real_double_stone_slab3", - "id" : -167 - }, - { - "name" : "minecraft:real_double_stone_slab4", - "id" : -168 + "name" : "minecraft:recovery_compass", + "id" : 647 }, { "name" : "minecraft:red_candle", @@ -3387,6 +3547,10 @@ "name" : "minecraft:redstone_wire", "id" : 55 }, + { + "name" : "minecraft:reinforced_deepslate", + "id" : -466 + }, { "name" : "minecraft:repeater", "id" : 419 @@ -3467,6 +3631,10 @@ "name" : "minecraft:scute", "id" : 572 }, + { + "name" : "minecraft:sea_lantern", + "id" : 169 + }, { "name" : "minecraft:sea_pickle", "id" : -156 @@ -3475,10 +3643,6 @@ "name" : "minecraft:seagrass", "id" : -130 }, - { - "name" : "minecraft:sealantern", - "id" : 169 - }, { "name" : "minecraft:shears", "id" : 421 @@ -3593,7 +3757,7 @@ }, { "name" : "minecraft:soul_campfire", - "id" : 621 + "id" : 622 }, { "name" : "minecraft:soul_fire", @@ -3617,11 +3781,11 @@ }, { "name" : "minecraft:sparkler", - "id" : 599 + "id" : 600 }, { "name" : "minecraft:spawn_egg", - "id" : 630 + "id" : 652 }, { "name" : "minecraft:spider_eye", @@ -3651,6 +3815,10 @@ "name" : "minecraft:spruce_button", "id" : -144 }, + { + "name" : "minecraft:spruce_chest_boat", + "id" : 642 + }, { "name" : "minecraft:spruce_door", "id" : 553 @@ -3720,7 +3888,7 @@ "id" : 29 }, { - "name" : "minecraft:stickypistonarmcollision", + "name" : "minecraft:sticky_piston_arm_collision", "id" : -217 }, { @@ -3731,6 +3899,22 @@ "name" : "minecraft:stone_axe", "id" : 315 }, + { + "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 @@ -3811,6 +3995,14 @@ "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 @@ -3845,7 +4037,7 @@ }, { "name" : "minecraft:suspicious_stew", - "id" : 589 + "id" : 590 }, { "name" : "minecraft:sweet_berries", @@ -3855,6 +4047,14 @@ "name" : "minecraft:sweet_berry_bush", "id" : -207 }, + { + "name" : "minecraft:tadpole_bucket", + "id" : 630 + }, + { + "name" : "minecraft:tadpole_spawn_egg", + "id" : 629 + }, { "name" : "minecraft:tallgrass", "id" : 31 @@ -3896,7 +4096,7 @@ "id" : 546 }, { - "name" : "minecraft:tripwire", + "name" : "minecraft:trip_wire", "id" : 132 }, { @@ -3959,6 +4159,10 @@ "name" : "minecraft:unpowered_repeater", "id" : 93 }, + { + "name" : "minecraft:verdant_froglight", + "id" : -470 + }, { "name" : "minecraft:vex_spawn_egg", "id" : 476 @@ -3987,13 +4191,17 @@ "name" : "minecraft:wandering_trader_spawn_egg", "id" : 492 }, + { + "name" : "minecraft:warden_spawn_egg", + "id" : 632 + }, { "name" : "minecraft:warped_button", "id" : -261 }, { "name" : "minecraft:warped_door", - "id" : 616 + "id" : 617 }, { "name" : "minecraft:warped_double_slab", @@ -4013,7 +4221,7 @@ }, { "name" : "minecraft:warped_fungus_on_a_stick", - "id" : 617 + "id" : 618 }, { "name" : "minecraft:warped_hyphae", @@ -4037,7 +4245,7 @@ }, { "name" : "minecraft:warped_sign", - "id" : 614 + "id" : 615 }, { "name" : "minecraft:warped_slab", diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 8c5737a39..d1a956187 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -66,20 +66,19 @@ remote: # If you're using a plugin version of Floodgate on the same server, the key will automatically be picked up from Floodgate. floodgate-key-file: key.pem -# The Xbox/Minecraft Bedrock username is the key for the Java server auth-info. -# This allows automatic configuration/login to the remote Java server. -# If you are brave enough to put your Mojang account info into a config file. -# Uncomment the lines below to enable this feature. -#userAuths: -# BedrockAccountUsername: # Your Minecraft: Bedrock Edition username -# email: javaccountemail@example.com # Your Minecraft: Java Edition email -# password: javaccountpassword123 # Your Minecraft: Java Edition password -# microsoft-account: true # Whether the account is a Mojang or Microsoft account. -# -# bluerkelp2: -# email: not_really_my_email_address_mr_minecrafter53267@gmail.com -# password: "this isn't really my password" -# microsoft-account: false +# For online mode authentication type only. +# Stores a list of Bedrock players that should have their Java Edition account saved after login. +# This saves a token that can be reused to authenticate the player later. This does not save emails or passwords, +# but you should still be cautious when adding to this list and giving others access to this Geyser instance's files. +# Removing a name from this list will delete its cached login information on the next Geyser startup. +# The file for this is in the same folder as this config, named "saved-refresh-tokens.json". +saved-user-logins: + - ThisExampleUsernameShouldBeLongEnoughToNeverBeAnXboxUsername + - ThisOtherExampleUsernameShouldAlsoBeLongEnough + +# Specify how many seconds to wait while user authorizes Geyser to access their Microsoft account. +# User is allowed to disconnect from the server during this period. +pending-authentication-timeout: 120 # Bedrock clients can freeze when opening up the command prompt for the first time if given a lot of commands. # Disabling this will prevent command suggestions from being sent and solve freezing for Bedrock clients. @@ -125,6 +124,13 @@ show-cooldown: title # Controls if coordinates are shown to players. 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 @@ -142,6 +148,13 @@ cache-images: 0 # Allows custom skulls to be displayed. Keeping them enabled may cause a performance decrease on older/weaker devices. allow-custom-skulls: true +# The maximum number of custom skulls to be displayed per player. Increasing this may decrease performance on weaker devices. +# Setting this to -1 will cause all custom skulls to be displayed regardless of distance or number. +max-visible-custom-skulls: 128 + +# The radius in blocks around the player in which custom skulls are displayed. +custom-skull-render-distance: 32 + # Whether to add (at this time, only) the furnace minecart as a separate item in the game, which normally does not exist in Bedrock Edition. # This should only need to be disabled if using a proxy that does not use the "transfer packet" style of server switching. # If this is disabled, furnace minecart items will be mapped to hopper minecart items. diff --git a/core/src/main/resources/languages b/core/src/main/resources/languages index 1a50238c1..f073cf2b9 160000 --- a/core/src/main/resources/languages +++ b/core/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 1a50238c1c743579a1dbd93c57d02b5da3be14fa +Subproject commit f073cf2b9e62d1a9da45ac23448d59ca71074339 diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 82ad7ba27..e13611fd9 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 82ad7ba279c68eb11a0b1a969c9efb3228c59227 +Subproject commit e13611fd97b1801d4c4b914cd409351a49d19537 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 96298f98e..6a280ea57 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 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 d2841db53..a2a9f98f6 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/licenseheader.txt b/licenseheader.txt index 8ef205a31..9bfe117f9 100644 --- a/licenseheader.txt +++ b/licenseheader.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * 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 diff --git a/pom.xml b/pom.xml index 004d58666..f4930959d 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 2.0.0-SNAPSHOT + 2.0.3-SNAPSHOT pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. @@ -17,6 +17,8 @@ UTF-8 16 16 + geysermc + https://sonarcloud.io @@ -38,20 +40,7 @@ core - - - - apache.snapshots - https://repository.apache.org/snapshots/ - - - - - - apache.snapshots - https://repository.apache.org/snapshots/ - jitpack.io https://jitpack.io diff --git a/screenshots/endcity.png b/screenshots/endcity.png deleted file mode 100644 index 65d73b94d..000000000 Binary files a/screenshots/endcity.png and /dev/null differ diff --git a/screenshots/endportal.png b/screenshots/endportal.png deleted file mode 100644 index 0da630b47..000000000 Binary files a/screenshots/endportal.png and /dev/null differ diff --git a/screenshots/hypixel.png b/screenshots/hypixel.png deleted file mode 100644 index d90ae4769..000000000 Binary files a/screenshots/hypixel.png and /dev/null differ diff --git a/screenshots/mineplex.png b/screenshots/mineplex.png deleted file mode 100644 index e948d22f6..000000000 Binary files a/screenshots/mineplex.png and /dev/null differ diff --git a/screenshots/nether.png b/screenshots/nether.png deleted file mode 100644 index 537613922..000000000 Binary files a/screenshots/nether.png and /dev/null differ diff --git a/screenshots/version.png b/screenshots/version.png deleted file mode 100644 index a9ba834b5..000000000 Binary files a/screenshots/version.png and /dev/null differ