diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 19b655c2..b4b93dca 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,7 +1,7 @@ # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] -patreon: #GeyserMC # Disabled currently +patreon: GeyserMC open_collective: # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 17e88f26..7a1fdba5 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -7,51 +7,34 @@ assignees: '' --- - - - + **Describe the bug** - -A clear and concise description of what the bug is. + **To Reproduce** - -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error + + + + + **Expected behavior** - -A clear and concise description of what you expected to happen. + **Screenshots / Videos** + -If applicable, add screenshots to help explain your problem. +**Server Version** + -**Server Version and Plugins** - -If you just run Geyser-Spigot, you can leave this area blank as the next section covers this information. - -If you're running a multi-server instance, or using Geyser Standalone: - -- Give us the exact output from `/version` on all servers involved. Saying "latest" does not help us at all. -- Please list all plugins on all servers involved. - -If this bug occurs on a server you do not control, please fill this in to the best of your knowledge. - -**Geyser Dump** - -If Geyser starts correctly, please also include the link to a dump by using `/geyser dump`. If you use the Standalone GUI, the option can be found under `Commands` => `Dump`. This provides us information about your server that we can use to debug your issue. +**Geyser Version** + **Minecraft: Bedrock Edition Version** - -The version of your Minecraft: Bedrock Edition client you tested with, along with your device type (e.g. Windows 10, Switch...). + **Additional Context** - -Add any other context about the problem here. + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index 46653e62..75a76cd0 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -11,4 +11,4 @@ assignees: '' Add a description **Alternatives?** -List any alternatives you might have tried +Any alternatives you have tryed diff --git a/.github/workflows/pullrequest.yml b/.github/workflows/pullrequest.yml index 78a3ce29..7f941da6 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -8,8 +8,8 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/cache@v2 + - uses: actions/checkout@v1 + - uses: actions/cache@v1 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} @@ -22,33 +22,33 @@ jobs: - name: submodules-init uses: snickerbockers/submodules-init@v4 - name: Build with Maven - run: mvn -B package -T 2C + run: mvn -B package - name: Archive artifacts (Geyser Standalone) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v1 if: success() with: name: Geyser Standalone path: bootstrap/standalone/target/Geyser.jar - - name: Archive artifacts (Geyser Spigot) - uses: actions/upload-artifact@v2 + - name: Archive artifacts (Geyser Bukkit) + uses: actions/upload-artifact@v1 if: success() with: - name: Geyser Spigot - path: bootstrap/spigot/target/Geyser-Spigot.jar + name: Geyser Bukkit + path: bootstrap/bukkit/target/Geyser-Bukkit.jar - name: Archive artifacts (Geyser BungeeCord) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v1 if: success() with: name: Geyser BungeeCord path: bootstrap/bungeecord/target/Geyser-BungeeCord.jar - name: Archive artifacts (Geyser Sponge) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v1 if: success() with: name: Geyser Sponge path: bootstrap/sponge/target/Geyser-Sponge.jar - name: Archive artifacts (Geyser Velocity) - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v1 if: success() with: name: Geyser Velocity diff --git a/.gitignore b/.gitignore index 85f8a6e9..0af6ecd0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode -# Edit at https://www.gitignore.io/gitignore?templates=git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode +# Created by https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all +# Edit at https://www.gitignore.io/?templates=git,java,maven,eclipse,netbeans,jetbrains+all ### Eclipse ### .metadata @@ -53,19 +53,22 @@ local.properties # Annotation Processing .apt_generated/ -.apt_generated_test/ # Scala IDE specific (Scala & Java development for Eclipse) .cache-main .scala_dependencies .worksheet -# Uncomment this line if you wish to ignore the project description file. -# Typically, this file would be tracked if it contains build/dependency configurations: +### Eclipse Patch ### +# Eclipse Core .project -### Eclipse Patch ### -# Spring Boot Tooling +# JDT-specific (Eclipse Java Development Tools) +.classpath + +# Annotation Processing +.apt_generated + .sts4-cache/ ### Git ### @@ -109,7 +112,7 @@ local.properties hs_err_pid* ### JetBrains+all ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff @@ -139,9 +142,6 @@ hs_err_pid* # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. -# .idea/artifacts -# .idea/compiler.xml -# .idea/jarRepositories.xml # .idea/modules.xml # .idea/*.iml # .idea/modules @@ -207,7 +207,6 @@ release.properties dependency-reduced-pom.xml buildNumber.properties .mvn/timing.properties -# https://github.com/takari/maven-wrapper#usage-without-binary-jar .mvn/wrapper/maven-wrapper.jar ### NetBeans ### @@ -220,20 +219,7 @@ dist/ nbdist/ .nb-gradle/ -### VisualStudioCode ### -# Note: Manually edited to remove settings files -.vscode/* -# !.vscode/settings.json -# !.vscode/tasks.json -# !.vscode/launch.json -# !.vscode/extensions.json -# *.code-workspace - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history - -# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all,visualstudiocode +# End of https://www.gitignore.io/api/git,java,maven,eclipse,netbeans,jetbrains+all ### Geyser ### run/ @@ -241,6 +227,3 @@ config.yml logs/ public-key.pem locales/ -/cache/ -/packs/ -/dump.json \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 0c014712..0090e64a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "connector/src/main/resources/mappings"] path = connector/src/main/resources/mappings url = https://github.com/GeyserMC/mappings.git -[submodule "connector/src/main/resources/languages"] - path = connector/src/main/resources/languages - url = https://github.com/GeyserMC/languages.git diff --git a/.idea/copyright/Geyser.xml b/.idea/copyright/Geyser.xml index c6b553aa..568fa7b8 100644 --- a/.idea/copyright/Geyser.xml +++ b/.idea/copyright/Geyser.xml @@ -1,6 +1,6 @@ - \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7a5a3d2..acb35e9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,44 +1 @@ -Thank for for considering a contribution! Generally, Geyser welcomes PRs from everyone. There are some guidelines about what features should go where: - - -*Pull requests that may not get accepted:* Niche features that apply to a specific group, for example integration with a specific plugin. For now, please create a separate plugin if possible. - -*Pull requests for Floodgate:* Anything that opens up information within the game for developers to use. - -*Pull requests for Geyser:* Anything that fixes compatibility between Java or Bedrock, or improves the quality of play for Bedrock players. The exception is wherever direct server access is required; in this case it may be better for Floodgate. - - -We have some general style guides that should be applied throughout the code: - -```java - -private static final AIR_ITEM = 0; // Static item names should be capitalized - -public Int2IntMap items = new Int2IntOpenHashMap(); // Use the interface as the class type but initialize with the implementation. - -public int nameWithMultipleWords = 0; - -/** -* Javadoc comment to explain what a function does. -*/ -public void applyStuff() { - if (condition) { - // Do stuff. - } else if (anotherCondition) { - // Do something else. - } - - switch (value) { - case 0: - break; - case 1: - break: - } -} -``` - -Make sure to comment your code where possible. - -The nature of our software requires a lot of arrays and maps to be stored - where possible, use Fastutil's specialized maps. For example, if you're storing block state translations, use an `Int2IntMap`. - -We have a rundown of all the tools you need to develop over on our [wiki](https://github.com/GeyserMC/Geyser/wiki/Developer-Guide). If you have any questions, please feel free to reach out to our [Discord](https://discord.geysermc.org)! +When contributing, please remember to read wiki about the api. Learn Steivice10's library and the nukkit protocol library if you are editing any core classes. Keep your code clean and readable, and please be mindful of fil conflicts. If you need help, join our discord. Other than that, you're all set! diff --git a/Jenkinsfile b/Jenkinsfile index 50149136..ffa4f1bd 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { jdk 'Java 8' } options { - buildDiscarder(logRotator(artifactNumToKeepStr: '20')) + buildDiscarder(logRotator(artifactNumToKeepStr: '5')) } stages { stage ('Build') { @@ -24,77 +24,17 @@ pipeline { when { branch "master" } - steps { - rtMavenDeployer( - id: "maven-deployer", - serverId: "opencollab-artifactory", - releaseRepo: "maven-releases", - snapshotRepo: "maven-snapshots" - ) - rtMavenResolver( - id: "maven-resolver", - serverId: "opencollab-artifactory", - releaseRepo: "release", - snapshotRepo: "snapshot" - ) - rtMavenRun( - pom: 'pom.xml', - goals: 'javadoc:jar source:jar install -DskipTests', - deployerId: "maven-deployer", - resolverId: "maven-resolver" - ) - rtPublishBuildInfo( - serverId: "opencollab-artifactory" - ) + sh 'mvn javadoc:jar source:jar deploy -DskipTests' } } } post { always { - script { - def changeLogSets = currentBuild.changeSets - def message = "**Changes:**" - - if (changeLogSets.size() == 0) { - message += "\n*No changes.*" - } else { - def repositoryUrl = scm.userRemoteConfigs[0].url.replace(".git", "") - def count = 0; - def extra = 0; - for (int i = 0; i < changeLogSets.size(); i++) { - def entries = changeLogSets[i].items - for (int j = 0; j < entries.length; j++) { - if (count <= 10) { - def entry = entries[j] - def commitId = entry.commitId.substring(0, 6) - message += "\n - [`${commitId}`](${repositoryUrl}/commit/${entry.commitId}) ${entry.msg}" - count++ - } else { - extra++; - } - } - } - - if (extra != 0) { - message += "\n - ${extra} more commits" - } - } - - env.changes = message - } deleteDir() withCredentials([string(credentialsId: 'geyser-discord-webhook', variable: 'DISCORD_WEBHOOK')]) { - discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n${changes}\n\n[**Artifacts on Jenkins**](https://ci.opencollab.dev/job/GeyserMC/job/Geyser)", footer: 'Open Collaboration Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK - } - } - success { - script { - if (env.BRANCH_NAME == 'master') { - build propagate: false, wait: false, job: 'GeyserMC/Geyser-Fabric/java-1.16' - build propagate: false, wait: false, job: 'GeyserMC/GeyserAndroid/master' - } + discordSend description: "**Build:** [${currentBuild.id}](${env.BUILD_URL})\n**Status:** [${currentBuild.currentResult}](${env.BUILD_URL})\n\n[**Artifacts on Jenkins**](https://ci.nukkitx.com/job/Geyser)", footer: 'NukkitX Jenkins', link: env.BUILD_URL, successful: currentBuild.resultIsBetterOrEqualTo('SUCCESS'), title: "${env.JOB_NAME} #${currentBuild.id}", webhookURL: DISCORD_WEBHOOK } } } diff --git a/LICENSE b/LICENSE index 0e368d54..acd4af14 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License -Copyright (c) 2019-2021 GeyserMC. http://geysermc.org +Copyright (c) 2019-2020 GeyserMC. http://geysermc.org Permission is hereby 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 1d1657ed..874c79f3 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,11 @@ -Geyser +Geyser [![forthebadge made-with-java](http://ForTheBadge.com/images/badges/made-with-java.svg)](https://java.com/) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) -[![Build Status](https://ci.opencollab.dev/job/Geyser/job/master/badge/icon)](https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/master/) +[![Build Status](https://ci.nukkitx.com/job/Geyser/job/master/badge/icon)](https://ci.nukkitx.com/job/Geyser/job/master/) [![Discord](https://img.shields.io/discord/613163671870242838.svg?color=%237289da&label=discord)](http://discord.geysermc.org/) [![HitCount](http://hits.dwyl.io/Geyser/GeyserMC.svg)](http://hits.dwyl.io/Geyser/GeyserMC) -[![Crowdin](https://badges.crowdin.net/geyser/localized.svg)](https://translate.geysermc.org/) Geyser is a bridge between Minecraft: Bedrock Edition and Minecraft: Java Edition, closing the gap from those wanting to play true cross-platform. @@ -18,7 +17,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have now joined us here! -### Currently supporting Minecraft Bedrock v1.16.100 - v1.16.201 and Minecraft Java v1.16.4. +### Currently supporting Minecraft Bedrock v1.14.6(0) and Minecraft Java v1.15.2. ## Setting Up Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser. @@ -30,30 +29,16 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - Docs: https://github.com/GeyserMC/Geyser/wiki - Download: http://ci.geysermc.org - Discord: http://discord.geysermc.org/ -- ~~Donate: https://patreon.com/GeyserMC~~ Currently disabled. -- Test Server: `test.geysermc.org` port `25565` for Java and `19132` for Bedrock +- Donate: https://patreon.com/GeyserMC ## What's Left to be Added/Fixed -- Lecterns -- Near-perfect movement (to the point where anticheat on large servers is unlikely to ban you) -- Resource pack conversion/CustomModelData -- Some Entity Flags - The Following Inventories - - Enchantment Table (as a proper GUI) - - Beacon - - Cartography Table - - Stonecutter - - Structure Block - - Horse Inventory - - Loom - - Smithing Table - -## What can't be fixed -The following things can't be fixed because of Bedrock limitations. They might be fixable in the future, but not as of now. - -- Custom heads in inventories -- Clickable links in chat -- Glowing effect + - [ ] Enchantment Table + - [ ] Beacon + - [ ] Cartography Table + - [ ] Stonecutter + - [ ] Villager Trading +- Some Entity Flags ## Compiling 1. Clone the repo to your computer diff --git a/bootstrap/spigot/pom.xml b/bootstrap/bukkit/pom.xml similarity index 57% rename from bootstrap/spigot/pom.xml rename to bootstrap/bukkit/pom.xml index 93eebc3d..1f831d67 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/bukkit/pom.xml @@ -6,37 +6,32 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT + ../ - bootstrap-spigot - + bootstrap-bukkit org.geysermc connector - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT compile org.spigotmc spigot-api - 1.15.2-R0.1-SNAPSHOT + 1.14-R0.1-SNAPSHOT provided us.myles viaversion - 3.2.0 + 3.0.0-SNAPSHOT provided - - org.geysermc.adapters - spigot-all - 1.0-SNAPSHOT - - ${outputName}-Spigot + ${outputName}-Bukkit src/main/resources/ @@ -51,7 +46,7 @@ - org.geysermc.platform.spigot.GeyserSpigotMain + org.geysermc.platform.bukkit.GeyserBukkitMain @@ -70,35 +65,11 @@ io.netty - org.geysermc.platform.spigot.shaded.netty + org.geysermc.platform.bukkit.shaded.netty it.unimi.dsi.fastutil - org.geysermc.platform.spigot.shaded.fastutil - - - com.fasterxml.jackson - org.geysermc.platform.spigot.shaded.jackson - - - org.reflections - org.geysermc.platform.spigot.shaded.reflections - - - com.google.common - org.geysermc.platform.spigot.shaded.google.common - - - com.google.guava - org.geysermc.platform.spigot.shaded.google.guava - - - org.dom4j - org.geysermc.platform.spigot.shaded.dom4j - - - net.kyori - org.geysermc.platform.spigot.shaded.kyori + org.geysermc.platform.bukkit.shaded.fastutil diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java new file mode 100644 index 00000000..df98b408 --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitConfiguration.java @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.platform.bukkit; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.plugin.Plugin; +import org.geysermc.connector.FloodgateKeyLoader; +import org.geysermc.connector.GeyserConfiguration; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; + +public class GeyserBukkitConfiguration implements GeyserConfiguration { + + private FileConfiguration config; + private File dataFolder; + + private BukkitBedrockConfiguration bedrockConfig; + private BukkitRemoteConfiguration remoteConfig; + private BukkitMetricsInfo metricsInfo; + + private Map userAuthInfo = new HashMap<>(); + + private Path floodgateKey; + + public GeyserBukkitConfiguration(File dataFolder, FileConfiguration config) { + this.dataFolder = dataFolder; + this.config = config; + + bedrockConfig = new BukkitBedrockConfiguration(); + remoteConfig = new BukkitRemoteConfiguration(); + metricsInfo = new BukkitMetricsInfo(); + + if (!config.contains("userAuths")) + return; + + for (String key : config.getConfigurationSection("userAuths").getKeys(false)) { + userAuthInfo.put(key, new BukkitUserAuthenticationInfo(key)); + } + } + + public void loadFloodgate(GeyserBukkitPlugin plugin) { + Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit"); + floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null); + } + + @Override + public IBedrockConfiguration getBedrock() { + return bedrockConfig; + } + + @Override + public IRemoteConfiguration getRemote() { + return remoteConfig; + } + + @Override + public Map getUserAuths() { + return userAuthInfo; + } + + @Override + public boolean isCommandSuggestions() { + return config.getBoolean("command-suggestions", true); + } + + @Override + public boolean isPassthroughMotd() { + return config.getBoolean("passthrough-motd", false); + } + + @Override + public boolean isPassthroughPlayerCounts() { + return config.getBoolean("passthrough-player-counts", false); + } + + @Override + public boolean isLegacyPingPassthrough() { + return config.getBoolean("legacy-ping-passthrough", false); + } + + @Override + public int getPingPassthroughInterval() { + return config.getInt("ping-passthrough-interval", 3); + } + + @Override + public int getMaxPlayers() { + return config.getInt("max-players", 10); + } + + @Override + public boolean isDebugMode() { + return config.getBoolean("debug-mode", false); + } + + @Override + public int getGeneralThreadPool() { + return config.getInt("general-thread-pool", 32); + } + + @Override + public boolean isAllowThirdPartyCapes() { + return config.getBoolean("allow-third-party-capes", true); + } + + @Override + public boolean isAllowThirdPartyEars() { + return config.getBoolean("allow-third-party-ears", false); + } + + @Override + public String getDefaultLocale() { + return config.getString("default-locale", "en_us"); + } + + @Override + public Path getFloodgateKeyFile() { + return floodgateKey; + } + + @Override + public boolean isCacheChunks() { + return true; // We override this as with Bukkit, we have direct access to the server implementation + } + + @Override + public boolean isAboveBedrockNetherBuilding() { + return config.getBoolean("above-bedrock-nether-building", false); + } + + @Override + public IMetricsInfo getMetrics() { + return metricsInfo; + } + + public class BukkitBedrockConfiguration implements IBedrockConfiguration { + + @Override + public String getAddress() { + return config.getString("bedrock.address", "0.0.0.0"); + } + + @Override + public int getPort() { + return config.getInt("bedrock.port", 25565); + } + + @Override + public String getMotd1() { + return config.getString("bedrock.motd1", "GeyserMC"); + } + + @Override + public String getMotd2() { + return config.getString("bedrock.motd2", "GeyserMC"); + } + } + + public class BukkitRemoteConfiguration implements IRemoteConfiguration { + + @Override + public String getAddress() { + return config.getString("remote.address", "127.0.0.1"); + } + + @Override + public int getPort() { + return config.getInt("remote.port", 25565); + } + + @Override + public String getAuthType() { + return config.getString("remote.auth-type", "online"); + } + } + + public class BukkitUserAuthenticationInfo implements IUserAuthenticationInfo { + + private String key; + + public BukkitUserAuthenticationInfo(String key) { + this.key = key; + } + + @Override + public String getEmail() { + return config.getString("userAuths." + key + ".email"); + } + + @Override + public String getPassword() { + return config.getString("userAuths." + key + ".password"); + } + } + + public class BukkitMetricsInfo implements IMetricsInfo { + + @Override + public boolean isEnabled() { + return config.getBoolean("metrics.enabled", true); + } + + @Override + public String getUniqueId() { + return config.getString("metrics.uuid", "generateduuid"); + } + } + + @Override + public int getConfigVersion() { + return config.getInt("config-version", 0); + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitLogger.java similarity index 86% rename from bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java rename to bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitLogger.java index f760079f..08822568 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,21 +23,20 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.spigot; +package org.geysermc.platform.bukkit; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; + import org.geysermc.connector.GeyserLogger; import java.util.logging.Level; import java.util.logging.Logger; @AllArgsConstructor -public class GeyserSpigotLogger implements GeyserLogger { - private final Logger logger; - @Getter @Setter - private boolean debug; +public class GeyserBukkitLogger implements GeyserLogger { + + private Logger logger; + private boolean debugMode; @Override public void severe(String message) { @@ -71,8 +70,12 @@ public class GeyserSpigotLogger implements GeyserLogger { @Override public void debug(String message) { - if (debug) { + if (debugMode) info(message); - } + } + + @Override + public void setDebug(boolean debug) { + debugMode = debug; } } diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitMain.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitMain.java new file mode 100644 index 00000000..b6da66c1 --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitMain.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.platform.bukkit; + +import org.geysermc.common.main.IGeyserMain; + +public class GeyserBukkitMain extends IGeyserMain { + + public static void main(String[] args) { + new GeyserBukkitMain().displayMessage(); + } + + public String getPluginType() { + return "Spigot or Paper (recommended)"; + } + + public String getPluginFolder() { + return "plugins"; + } +} diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java new file mode 100644 index 00000000..812467be --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPingPassthrough.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.platform.bukkit; + +import lombok.AllArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.server.ServerListPingEvent; +import org.bukkit.util.CachedServerIcon; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.ping.IGeyserPingPassthrough; + +import java.net.InetAddress; +import java.util.Collections; +import java.util.Iterator; + +@AllArgsConstructor +public class GeyserBukkitPingPassthrough implements IGeyserPingPassthrough { + + private final GeyserBukkitLogger logger; + + @Override + public GeyserPingInfo getPingInformation() { + try { + ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); + Bukkit.getPluginManager().callEvent(event); + GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers()); + Bukkit.getOnlinePlayers().forEach(player -> { + geyserPingInfo.addPlayer(player.getName()); + }); + return geyserPingInfo; + } catch (Exception e) { + logger.debug("Error while getting Bukkit ping passthrough: " + e.toString()); + return new GeyserPingInfo(null, 0, 0); + } + } + + // These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain + private static class GeyserPingEvent extends ServerListPingEvent { + + public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) { + super(address, motd, numPlayers, maxPlayers); + } + + @Override + public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException { + } + + @Override + public Iterator iterator() throws UnsupportedOperationException { + return Collections.EMPTY_LIST.iterator(); + } + } + +} diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java new file mode 100644 index 00000000..5f0e967a --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/GeyserBukkitPlugin.java @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.platform.bukkit; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; +import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.bootstrap.GeyserBootstrap; +import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.network.translators.world.WorldManager; +import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.ping.IGeyserPingPassthrough; +import org.geysermc.platform.bukkit.command.GeyserBukkitCommandExecutor; +import org.geysermc.platform.bukkit.command.GeyserBukkitCommandManager; +import org.geysermc.platform.bukkit.world.GeyserBukkitBlockPlaceListener; +import org.geysermc.platform.bukkit.world.GeyserBukkitWorldManager; +import us.myles.ViaVersion.api.Via; + +import java.util.UUID; + +public class GeyserBukkitPlugin extends JavaPlugin implements GeyserBootstrap { + + private GeyserBukkitCommandManager geyserCommandManager; + private GeyserBukkitConfiguration geyserConfig; + private GeyserBukkitLogger geyserLogger; + private IGeyserPingPassthrough geyserBukkitPingPassthrough; + private GeyserBukkitBlockPlaceListener blockPlaceListener; + private GeyserBukkitWorldManager geyserWorldManager; + + private GeyserConnector connector; + + @Override + public void onEnable() { + saveDefaultConfig(); + + this.geyserConfig = new GeyserBukkitConfiguration(getDataFolder(), getConfig()); + if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) { + getConfig().set("metrics.uuid", UUID.randomUUID().toString()); + saveConfig(); + } + + // Don't change the ip if its listening on all interfaces + // By default this should be 127.0.0.1 but may need to be changed in some circumstances + if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { + getConfig().set("remote.address", Bukkit.getIp()); + } + + getConfig().set("remote.port", Bukkit.getPort()); + saveConfig(); + + this.geyserLogger = new GeyserBukkitLogger(getLogger(), geyserConfig.isDebugMode()); + GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); + + geyserConfig.loadFloodgate(this); + + this.connector = GeyserConnector.start(PlatformType.BUKKIT, this); + + if (geyserConfig.isLegacyPingPassthrough()) { + this.geyserBukkitPingPassthrough = GeyserLegacyPingPassthrough.init(connector); + } else { + this.geyserBukkitPingPassthrough = new GeyserBukkitPingPassthrough(geyserLogger); + } + + this.geyserCommandManager = new GeyserBukkitCommandManager(this, connector); + + boolean isViaVersion = false; + // Used to determine if Block.getBlockData() is present. + boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0"); + if (isLegacy) + geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected."); + + if (Bukkit.getPluginManager().getPlugin("ViaVersion") != null) { + // TODO: Update when ViaVersion updates + // API changes between 2.2.3 and 3.0.0-SNAPSHOT require this check + if (!Via.getAPI().getVersion().equals("3.0.0-SNAPSHOT") && isLegacy) { + geyserLogger.info("ViaVersion detected but not ViaVersion-ABSTRACTION. Please update your ViaVersion plugin for compatibility with Geyser."); + } else { + isViaVersion = true; + } + } + + this.geyserWorldManager = new GeyserBukkitWorldManager(isLegacy, isViaVersion); + this.blockPlaceListener = new GeyserBukkitBlockPlaceListener(connector, isLegacy, isViaVersion); + Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); + + this.getCommand("geyser").setExecutor(new GeyserBukkitCommandExecutor(connector)); + } + + @Override + public void onDisable() { + connector.shutdown(); + } + + @Override + public GeyserBukkitConfiguration getGeyserConfig() { + return geyserConfig; + } + + @Override + public GeyserBukkitLogger getGeyserLogger() { + return geyserLogger; + } + + @Override + public CommandManager getGeyserCommandManager() { + return this.geyserCommandManager; + } + + @Override + public IGeyserPingPassthrough getGeyserPingPassthrough() { + return geyserBukkitPingPassthrough; + } + + @Override + public WorldManager getWorldManager() { + return this.geyserWorldManager; + } + + public boolean isCompatible(String version, String whichVersion) { + int[] currentVersion = parseVersion(version); + int[] otherVersion = parseVersion(whichVersion); + int length = Math.max(currentVersion.length, otherVersion.length); + for (int index = 0; index < length; index = index + 1) { + int self = (index < currentVersion.length) ? currentVersion[index] : 0; + int other = (index < otherVersion.length) ? otherVersion[index] : 0; + + if (self != other) { + return (self - other) > 0; + } + } + return true; + } + + private int[] parseVersion(String versionParam) { + versionParam = (versionParam == null) ? "" : versionParam; + if (versionParam.contains("(MC: ")) { + versionParam = versionParam.split("\\(MC: ")[1]; + versionParam = versionParam.split("\\)")[0]; + } + String[] stringArray = versionParam.split("[_.-]"); + int[] temp = new int[stringArray.length]; + for (int index = 0; index <= (stringArray.length - 1); index = index + 1) { + String t = stringArray[index].replaceAll("\\D", ""); + try { + temp[index] = Integer.parseInt(t); + } catch(NumberFormatException ex) { + temp[index] = 0; + } + } + return temp; + } +} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/BukkitCommandSender.java similarity index 64% rename from bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java rename to bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/BukkitCommandSender.java index 3e410f60..05e371e5 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/BukkitCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,21 +23,30 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.spigot; +package org.geysermc.platform.bukkit.command; -import org.geysermc.connector.common.main.IGeyserMain; +import lombok.AllArgsConstructor; -public class GeyserSpigotMain extends IGeyserMain { +import org.bukkit.command.ConsoleCommandSender; +import org.geysermc.connector.command.CommandSender; - public static void main(String[] args) { - new GeyserSpigotMain().displayMessage(); +@AllArgsConstructor +public class BukkitCommandSender implements CommandSender { + + private org.bukkit.command.CommandSender handle; + + @Override + public String getName() { + return handle.getName(); } - public String getPluginType() { - return "Spigot or Paper (recommended)"; + @Override + public void sendMessage(String message) { + handle.sendMessage(message); } - public String getPluginFolder() { - return "plugins"; + @Override + public boolean isConsole() { + return handle instanceof ConsoleCommandSender; } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/GeyserBukkitCommandExecutor.java similarity index 72% rename from bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java rename to bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/GeyserBukkitCommandExecutor.java index 1db86856..d2603f7c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/GeyserBukkitCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,42 +23,39 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.spigot.command; +package org.geysermc.platform.bukkit.command; import lombok.AllArgsConstructor; + import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.utils.LanguageUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @AllArgsConstructor -public class GeyserSpigotCommandExecutor implements TabExecutor { +public class GeyserBukkitCommandExecutor implements TabExecutor { - private final GeyserConnector connector; + private GeyserConnector connector; @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { if (args.length > 0) { if (getCommand(args[0]) != null) { if (!sender.hasPermission(getCommand(args[0]).getPermission())) { - SpigotCommandSender commandSender = new SpigotCommandSender(sender); - String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale());; - - commandSender.sendMessage(ChatColor.RED + message); + sender.sendMessage(ChatColor.RED + "You do not have permission to execute this command!"); return true; } - getCommand(args[0]).execute(new SpigotCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + getCommand(args[0]).execute(new BukkitCommandSender(sender), args); return true; } } else { - getCommand("help").execute(new SpigotCommandSender(sender), new String[0]); + getCommand("help").execute(new BukkitCommandSender(sender), args); return true; } return true; @@ -67,7 +64,7 @@ public class GeyserSpigotCommandExecutor implements TabExecutor { @Override public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { if (args.length == 1) { - return connector.getCommandManager().getCommandNames(); + return Arrays.asList("?", "help", "reload", "shutdown", "stop"); } return new ArrayList<>(); } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandManager.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/GeyserBukkitCommandManager.java similarity index 86% rename from bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandManager.java rename to bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/GeyserBukkitCommandManager.java index c0c239b0..b826ab1f 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandManager.java +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/command/GeyserBukkitCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 +23,18 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.platform.spigot.command; +package org.geysermc.platform.bukkit.command; import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandMap; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandManager; -import org.geysermc.platform.spigot.GeyserSpigotPlugin; +import org.geysermc.platform.bukkit.GeyserBukkitPlugin; import java.lang.reflect.Field; -public class GeyserSpigotCommandManager extends CommandManager { +public class GeyserBukkitCommandManager extends CommandManager { private static CommandMap COMMAND_MAP; @@ -48,9 +48,9 @@ public class GeyserSpigotCommandManager extends CommandManager { } } - private GeyserSpigotPlugin plugin; + private GeyserBukkitPlugin plugin; - public GeyserSpigotCommandManager(GeyserSpigotPlugin plugin, GeyserConnector connector) { + public GeyserBukkitCommandManager(GeyserBukkitPlugin plugin, GeyserConnector connector) { super(connector); this.plugin = plugin; diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/world/GeyserBukkitBlockPlaceListener.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/world/GeyserBukkitBlockPlaceListener.java new file mode 100644 index 00000000..76d1564e --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/world/GeyserBukkitBlockPlaceListener.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.platform.bukkit.world; + +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.data.SoundEvent; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; +import lombok.AllArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockPlaceEvent; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +@AllArgsConstructor +public class GeyserBukkitBlockPlaceListener implements Listener { + + private final GeyserConnector connector; + private final boolean isLegacy; + private final boolean isViaVersion; + + @EventHandler + public void place(final BlockPlaceEvent event) { + for (GeyserSession session : connector.getPlayers().values()) { + if (event.getPlayer() == Bukkit.getPlayer(session.getPlayerEntity().getUsername())) { + LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket(); + placeBlockSoundPacket.setSound(SoundEvent.PLACE); + placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())); + placeBlockSoundPacket.setBabySound(false); + String javaBlockId; + if (isLegacy) { + javaBlockId = BlockTranslator.getJavaIdBlockMap().inverse().get(GeyserBukkitWorldManager.getLegacyBlock(session, + event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ(), isViaVersion)); + } else { + javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); + } + placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().get(javaBlockId))); + placeBlockSoundPacket.setIdentifier(":"); + session.sendUpstreamPacket(placeBlockSoundPacket); + session.setLastBlockPlacePosition(null); + session.setLastBlockPlacedId(null); + break; + } + } + } + +} diff --git a/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/world/GeyserBukkitWorldManager.java b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/world/GeyserBukkitWorldManager.java new file mode 100644 index 00000000..fbdf2a47 --- /dev/null +++ b/bootstrap/bukkit/src/main/java/org/geysermc/platform/bukkit/world/GeyserBukkitWorldManager.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.platform.bukkit.world; + +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.world.WorldManager; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.platform.bukkit.GeyserBukkitPlugin; +import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13; +import us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData; + +@AllArgsConstructor +public class GeyserBukkitWorldManager extends WorldManager { + + private final boolean isLegacy; + // You need ViaVersion to connect to an older server with Geyser. + // However, we still check for ViaVersion in case there's some other way that gets Geyser on a pre-1.13 Bukkit server + private final boolean isViaVersion; + + @Override + public BlockState getBlockAt(GeyserSession session, int x, int y, int z) { + if (session.getPlayerEntity() == null) { + return BlockTranslator.AIR; + } + if (isLegacy) { + return getLegacyBlock(session, x, y, z, isViaVersion); + } + return BlockTranslator.getJavaIdBlockMap().get(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z).getBlockData().getAsString()); + } + + @SuppressWarnings("deprecation") + public static BlockState getLegacyBlock(GeyserSession session, int x, int y, int z, boolean isViaVersion) { + if (isViaVersion) { + Block block = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z); + // Black magic that gets the old block state ID + int oldBlockId = (block.getType().getId() << 4) | (block.getData() & 0xF); + // Convert block state from old version -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 + int thirteenBlockId = us.myles.ViaVersion.protocols.protocol1_13to1_12_2.data.MappingData.blockMappings.getNewId(oldBlockId); + int thirteenPointOneBlockId = Protocol1_13_1To1_13.getNewBlockStateId(thirteenBlockId); + int fourteenBlockId = us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData.blockStateMappings.getNewId(thirteenPointOneBlockId); + return new BlockState(MappingData.blockStateMappings.getNewId(fourteenBlockId)); + } else { + return BlockTranslator.AIR; + } + } +} diff --git a/bootstrap/spigot/src/main/resources/plugin.yml b/bootstrap/bukkit/src/main/resources/plugin.yml similarity index 67% rename from bootstrap/spigot/src/main/resources/plugin.yml rename to bootstrap/bukkit/src/main/resources/plugin.yml index fee71ab1..89c90789 100644 --- a/bootstrap/spigot/src/main/resources/plugin.yml +++ b/bootstrap/bukkit/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ -main: org.geysermc.platform.spigot.GeyserSpigotPlugin -name: ${outputName}-Spigot +main: org.geysermc.platform.bukkit.GeyserBukkitPlugin +name: ${outputName}-Bukkit author: ${project.organization.name} website: ${project.organization.url} version: ${project.version} diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 54e0d56e..dd66db32 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,15 +6,15 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT + ../ bootstrap-bungeecord - org.geysermc connector - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT compile @@ -61,34 +61,10 @@ net.md_5.bungee.jni org.geysermc.platform.bungeecord.shaded.jni - - com.fasterxml.jackson - org.geysermc.platform.bungeecord.shaded.jackson - io.netty org.geysermc.platform.bungeecord.shaded.netty - - org.reflections - org.geysermc.platform.bungeecord.shaded.reflections - - - com.google.common - org.geysermc.platform.bungeecord.shaded.google.common - - - com.google.guava - org.geysermc.platform.bungeecord.shaded.google.guava - - - org.dom4j - org.geysermc.platform.bungeecord.shaded.dom4j - - - net.kyori - org.geysermc.platform.bungeecord.shaded.kyori - diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java index af246f6f..d983aec1 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,26 +25,216 @@ package org.geysermc.platform.bungeecord; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Getter; import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.config.Configuration; import org.geysermc.connector.FloodgateKeyLoader; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; +import org.geysermc.connector.GeyserConfiguration; +import java.io.File; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.Map; -@Getter -@JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration { - @JsonIgnore - private Path floodgateKeyPath; +public class GeyserBungeeConfiguration implements GeyserConfiguration { + + private File dataFolder; + private Configuration config; + + private BungeeBedrockConfiguration bedrockConfig; + private BungeeRemoteConfiguration remoteConfig; + private BungeeMetricsInfo metricsInfo; + + private Map userAuthInfo = new HashMap<>(); + + private Path floodgateKey; + + public GeyserBungeeConfiguration(File dataFolder, Configuration config) { + this.dataFolder = dataFolder; + this.config = config; + + bedrockConfig = new BungeeBedrockConfiguration(); + remoteConfig = new BungeeRemoteConfiguration(); + metricsInfo = new BungeeMetricsInfo(); + + if (!config.contains("userAuths")) + return; + + for (String key : config.getSection("userAuths").getKeys()) { + userAuthInfo.put(key, new BungeeUserAuthenticationInfo(key)); + } + } public void loadFloodgate(GeyserBungeePlugin plugin) { Plugin floodgate = plugin.getProxy().getPluginManager().getPlugin("floodgate-bungee"); - Path geyserDataFolder = plugin.getDataFolder().toPath(); - Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null; + floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), config.getString("floodgate-key-file", "public-key.pem")), floodgate, floodgate != null ? floodgate.getDataFolder().toPath() : null); + } - floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger()); + @Override + public BungeeBedrockConfiguration getBedrock() { + return bedrockConfig; + } + + @Override + public BungeeRemoteConfiguration getRemote() { + return remoteConfig; + } + + @Override + public Map getUserAuths() { + return userAuthInfo; + } + + @Override + public boolean isCommandSuggestions() { + return config.getBoolean("command-suggestions", true); + } + + @Override + public boolean isPassthroughMotd() { + return config.getBoolean("passthrough-motd", false); + } + + @Override + public boolean isPassthroughPlayerCounts() { + return config.getBoolean("passthrough-player-counts", false); + } + + @Override + public boolean isLegacyPingPassthrough() { + return config.getBoolean("legacy-ping-passthrough", false); + } + + @Override + public int getPingPassthroughInterval() { + return config.getInt("ping-passthrough-interval", 3); + } + + @Override + public int getMaxPlayers() { + return config.getInt("max-players", 10); + } + + @Override + public boolean isDebugMode() { + return config.getBoolean("debug-mode", false); + } + + @Override + public int getGeneralThreadPool() { + return config.getInt("general-thread-pool", 32); + } + + @Override + public boolean isAllowThirdPartyCapes() { + return config.getBoolean("allow-third-party-capes", true); + } + + @Override + public boolean isAllowThirdPartyEars() { + return config.getBoolean("allow-third-party-ears", false); + } + + @Override + public String getDefaultLocale() { + return config.getString("default-locale", "en_us"); + } + + @Override + public Path getFloodgateKeyFile() { + return floodgateKey; + } + + @Override + public boolean isCacheChunks() { + return config.getBoolean("cache-chunks", false); + } + + @Override + public boolean isAboveBedrockNetherBuilding() { + return config.getBoolean("above-bedrock-nether-building", false); + } + + @Override + public BungeeMetricsInfo getMetrics() { + return metricsInfo; + } + + public class BungeeBedrockConfiguration implements IBedrockConfiguration { + + @Override + public String getAddress() { + return config.getString("bedrock.address", "0.0.0.0"); + } + + @Override + public int getPort() { + return config.getInt("bedrock.port", 25565); + } + + @Override + public String getMotd1() { + return config.getString("bedrock.motd1", "GeyserMC"); + } + + @Override + public String getMotd2() { + return config.getString("bedrock.motd2", "GeyserMC"); + } + } + + public class BungeeRemoteConfiguration implements IRemoteConfiguration { + + @Override + public String getAddress() { + return config.getString("remote.address", "127.0.0.1"); + } + + @Override + public int getPort() { + return config.getInt("remote.port", 25565); + } + + @Override + public String getAuthType() { + return config.getString("remote.auth-type", "online"); + } + } + + public class BungeeUserAuthenticationInfo implements IUserAuthenticationInfo { + + private String key; + + public BungeeUserAuthenticationInfo(String key) { + this.key = key; + } + + @Override + public String getEmail() { + return config.getString("userAuths." + key + ".email"); + } + + @Override + public String getPassword() { + return config.getString("userAuths." + key + ".password"); + } + } + + public class BungeeMetricsInfo implements IMetricsInfo { + + @Override + public boolean isEnabled() { + return config.getBoolean("metrics.enabled", true); + } + + @Override + public String getUniqueId() { + return config.getString("metrics.uuid", "generateduuid"); + } + } + + @Override + public int getConfigVersion() { + return config.getInt("config-version", 0); } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeDumpInfo.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeDumpInfo.java deleted file mode 100644 index 12429d75..00000000 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeDumpInfo.java +++ /dev/null @@ -1,69 +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.platform.bungeecord; - -import lombok.Getter; -import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.plugin.Plugin; -import org.geysermc.connector.common.serializer.AsteriskSerializer; -import org.geysermc.connector.dump.BootstrapDumpInfo; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -@Getter -public class GeyserBungeeDumpInfo extends BootstrapDumpInfo { - - private String platformName; - private String platformVersion; - private boolean onlineMode; - private List listeners; - private List plugins; - - GeyserBungeeDumpInfo(ProxyServer proxy) { - super(); - this.platformName = proxy.getName(); - this.platformVersion = proxy.getVersion(); - this.onlineMode = proxy.getConfig().isOnlineMode(); - this.listeners = new ArrayList<>(); - this.plugins = new ArrayList<>(); - - for (net.md_5.bungee.api.config.ListenerInfo listener : proxy.getConfig().getListeners()) { - String hostname; - if (AsteriskSerializer.showSensitive || (listener.getHost().getHostString().equals("") || listener.getHost().getHostString().equals("0.0.0.0"))) { - hostname = listener.getHost().getHostString(); - } else { - hostname = "***"; - } - this.listeners.add(new ListenerInfo(hostname, listener.getHost().getPort())); - } - - for (Plugin plugin : proxy.getPluginManager().getPlugins()) { - this.plugins.add(new PluginInfo(true, plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getMain(), Arrays.asList(plugin.getDescription().getAuthor()))); - } - } -} diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeLogger.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeLogger.java index 1903bb86..cd07b333 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeLogger.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 @@ package org.geysermc.platform.bungeecord; -import lombok.Getter; -import lombok.Setter; import org.geysermc.connector.GeyserLogger; import java.util.logging.Level; import java.util.logging.Logger; public class GeyserBungeeLogger implements GeyserLogger { - private final Logger logger; - @Getter @Setter - private boolean debug; - public GeyserBungeeLogger(Logger logger, boolean debug) { + private Logger logger; + private boolean debugMode; + + public GeyserBungeeLogger(Logger logger, boolean debugMode) { this.logger = logger; - this.debug = debug; + this.debugMode = debugMode; } @Override @@ -74,8 +72,12 @@ public class GeyserBungeeLogger implements GeyserLogger { @Override public void debug(String message) { - if (debug) { + if (debugMode) info(message); - } + } + + @Override + public void setDebug(boolean debug) { + debugMode = debug; } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeMain.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeMain.java index b69c3573..eabbcc69 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeMain.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeMain.java @@ -1,31 +1,32 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.bungeecord; -import org.geysermc.connector.common.main.IGeyserMain; +import org.geysermc.common.main.IGeyserMain; public class GeyserBungeeMain extends IGeyserMain { diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java index 6eea2591..c7f8f276 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.bungeecord; @@ -34,7 +35,7 @@ import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.event.ProxyPingEvent; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.protocol.ProtocolConstants; -import org.geysermc.connector.common.ping.GeyserPingInfo; +import org.geysermc.common.ping.GeyserPingInfo; import org.geysermc.connector.ping.IGeyserPingPassthrough; import java.net.Inet4Address; @@ -47,25 +48,26 @@ import java.util.concurrent.CompletableFuture; @AllArgsConstructor public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, Listener { + private static final GeyserPendingConnection PENDING_CONNECTION = new GeyserPendingConnection(); + private final ProxyServer proxyServer; @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + public GeyserPingInfo getPingInformation() { CompletableFuture future = new CompletableFuture<>(); - proxyServer.getPluginManager().callEvent(new ProxyPingEvent(new GeyserPendingConnection(inetSocketAddress), getPingInfo(), (event, throwable) -> { + proxyServer.getPluginManager().callEvent(new ProxyPingEvent(PENDING_CONNECTION, getPingInfo(), (event, throwable) -> { if (throwable != null) future.completeExceptionally(throwable); else future.complete(event); })); ProxyPingEvent event = future.join(); - ServerPing response = event.getResponse(); GeyserPingInfo geyserPingInfo = new GeyserPingInfo( - response.getDescriptionComponent().toLegacyText(), - new GeyserPingInfo.Players(response.getPlayers().getMax(), response.getPlayers().getOnline()), - new GeyserPingInfo.Version(response.getVersion().getName(), response.getVersion().getProtocol()) + event.getResponse().getDescription(), + event.getResponse().getPlayers().getOnline(), + event.getResponse().getPlayers().getMax() ); if (event.getResponse().getPlayers().getSample() != null) { Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> { - geyserPingInfo.getPlayerList().add(proxiedPlayer.getName()); + geyserPingInfo.addPlayer(proxiedPlayer.getName()); }); } return geyserPingInfo; @@ -87,12 +89,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List private static class GeyserPendingConnection implements PendingConnection { private static final UUID FAKE_UUID = UUID.nameUUIDFromBytes("geyser!internal".getBytes()); - - private final InetSocketAddress remote; - - public GeyserPendingConnection(InetSocketAddress remote) { - this.remote = remote; - } + private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); @Override public String getName() { @@ -146,7 +143,7 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List @Override public InetSocketAddress getAddress() { - return remote; + return FAKE_REMOTE; } @Override diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java index 8d37bffb..525b9b6d 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,24 @@ package org.geysermc.platform.bungeecord; import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.plugin.Plugin; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandExecutor; import org.geysermc.platform.bungeecord.command.GeyserBungeeCommandManager; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.net.InetSocketAddress; -import java.nio.file.Path; +import java.nio.file.Files; import java.util.UUID; import java.util.logging.Level; @@ -61,48 +62,66 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { if (!getDataFolder().exists()) getDataFolder().mkdir(); - try { - if (!getDataFolder().exists()) - getDataFolder().mkdir(); - File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); - this.geyserConfig = FileUtils.loadConfig(configFile, GeyserBungeeConfiguration.class); - } catch (IOException ex) { - getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); - ex.printStackTrace(); + File file = new File(getDataFolder(), "config.yml"); + Configuration configuration = null; + + if (!file.exists()) { + try (InputStream in = getResourceAsStream("config.yml")) { + Files.copy(in, file.toPath()); + } catch (IOException ex) { + getLogger().log(Level.SEVERE, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex); + return; + } } + try { + configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml")); + } catch(IOException e) { + e.printStackTrace(); + } + + if (configuration == null) { + getLogger().severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!"); + return; + } + + this.geyserConfig = new GeyserBungeeConfiguration(getDataFolder(), configuration); + + boolean configHasChanged = false; if (getProxy().getConfig().getListeners().size() == 1) { ListenerInfo listener = getProxy().getConfig().getListeners().toArray(new ListenerInfo[0])[0]; InetSocketAddress javaAddr = listener.getHost(); - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { - this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); - } - this.geyserConfig.getRemote().setPort(javaAddr.getPort()); + // Don't change the ip if its listening on all interfaces + // By default this should be 127.0.0.1 but may need to be changed in some circumstances + if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { + configuration.set("remote.address", javaAddr.getHostString()); } - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(javaAddr.getPort()); + configuration.set("remote.port", javaAddr.getPort()); + + configHasChanged = true; + } + + if (geyserConfig.getMetrics().getUniqueId().equals("generateduuid")) { + configuration.set("metrics.uuid", UUID.randomUUID().toString()); + + configHasChanged = true; + } + + if (configHasChanged) { + try { + ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration, new File(getDataFolder(), "config.yml")); + } catch (IOException ex) { + getLogger().log(Level.SEVERE, "Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex); + return; } } this.geyserLogger = new GeyserBungeeLogger(getLogger(), geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - if (geyserConfig.getRemote().getAuthType().equals("floodgate") && getProxy().getPluginManager().getPlugin("floodgate-bungee") == null) { - geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && getProxy().getPluginManager().getPlugin("floodgate-bungee") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType("floodgate"); - } - geyserConfig.loadFloodgate(this); this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this); @@ -142,14 +161,4 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { public IGeyserPingPassthrough getGeyserPingPassthrough() { return geyserBungeePingPassthrough; } - - @Override - public Path getConfigFolder() { - return getDataFolder().toPath(); - } - - @Override - public BootstrapDumpInfo getDumpInfo() { - return new GeyserBungeeDumpInfo(getProxy()); - } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/BungeeCommandSender.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/BungeeCommandSender.java index 807cf478..d40dc902 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/BungeeCommandSender.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/BungeeCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 @@ package org.geysermc.platform.bungeecord.command; +import lombok.AllArgsConstructor; + import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.command.CommandSender; + +@AllArgsConstructor public class BungeeCommandSender implements CommandSender { - private final net.md_5.bungee.api.CommandSender handle; - - public BungeeCommandSender(net.md_5.bungee.api.CommandSender handle) { - this.handle = handle; - // Ensure even Java players' languages are loaded - LanguageUtils.loadGeyserLocale(getLocale()); - } + private net.md_5.bungee.api.CommandSender handle; @Override public String getName() { @@ -54,14 +51,4 @@ public class BungeeCommandSender implements CommandSender { public boolean isConsole() { return !(handle instanceof ProxiedPlayer); } - - @Override - public String getLocale() { - if (handle instanceof ProxiedPlayer) { - ProxiedPlayer player = (ProxiedPlayer) handle; - String locale = player.getLocale().getLanguage() + "_" + player.getLocale().getCountry(); - return LanguageUtils.formatLocale(locale); - } - return LanguageUtils.getDefaultLocale(); - } } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandExecutor.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandExecutor.java index 2431f0a4..d1c8473b 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandExecutor.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 +27,19 @@ package org.geysermc.platform.bungeecord.command; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.plugin.Command; import net.md_5.bungee.api.plugin.TabExecutor; + import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.utils.LanguageUtils; import java.util.ArrayList; import java.util.Arrays; public class GeyserBungeeCommandExecutor extends Command implements TabExecutor { - private final GeyserConnector connector; + private GeyserConnector connector; public GeyserBungeeCommandExecutor(GeyserConnector connector) { super("geyser"); @@ -51,23 +52,20 @@ public class GeyserBungeeCommandExecutor extends Command implements TabExecutor if (args.length > 0) { if (getCommand(args[0]) != null) { if (!sender.hasPermission(getCommand(args[0]).getPermission())) { - BungeeCommandSender commandSender = new BungeeCommandSender(sender); - String message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", commandSender.getLocale()); - - commandSender.sendMessage(ChatColor.RED + message); + sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + "You do not have permission to execute this command!")); return; } - getCommand(args[0]).execute(new BungeeCommandSender(sender), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + getCommand(args[0]).execute(new BungeeCommandSender(sender), args); } } else { - getCommand("help").execute(new BungeeCommandSender(sender), new String[0]); + getCommand("help").execute(new BungeeCommandSender(sender), args); } } @Override public Iterable onTabComplete(CommandSender sender, String[] args) { if (args.length == 1) { - return connector.getCommandManager().getCommandNames(); + return Arrays.asList("?", "help", "reload", "shutdown", "stop"); } return new ArrayList<>(); } diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandManager.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandManager.java index bc5c6a59..bb79c577 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandManager.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/command/GeyserBungeeCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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 a5ad53cb..6d12b673 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -6,11 +6,12 @@ org.geysermc geyser-parent - 1.2.0-SNAPSHOT + parent + ../ bootstrap-parent + 1.0-SNAPSHOT pom - spigot-public @@ -34,8 +35,8 @@ + bukkit bungeecord - spigot sponge standalone velocity diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotConfiguration.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotConfiguration.java deleted file mode 100644 index 2dbdbf83..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotConfiguration.java +++ /dev/null @@ -1,56 +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.platform.spigot; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Getter; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; -import org.geysermc.connector.FloodgateKeyLoader; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; - -import java.nio.file.Path; - -@Getter -@JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration { - @JsonIgnore - private Path floodgateKeyPath; - - public void loadFloodgate(GeyserSpigotPlugin plugin) { - Plugin floodgate = Bukkit.getPluginManager().getPlugin("floodgate-bukkit"); - Path geyserDataFolder = plugin.getDataFolder().toPath(); - Path floodgateDataFolder = floodgate != null ? floodgate.getDataFolder().toPath() : null; - - floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, floodgateDataFolder, geyserDataFolder, plugin.getGeyserLogger()); - } - - @Override - public boolean isCacheChunks() { - return true; // We override this as with Bukkit, we have direct access to the server implementation - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotDumpInfo.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotDumpInfo.java deleted file mode 100644 index 03fa0850..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotDumpInfo.java +++ /dev/null @@ -1,66 +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.platform.spigot; - -import lombok.Getter; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; -import org.geysermc.connector.common.serializer.AsteriskSerializer; -import org.geysermc.connector.dump.BootstrapDumpInfo; - -import java.util.ArrayList; -import java.util.List; - -@Getter -public class GeyserSpigotDumpInfo extends BootstrapDumpInfo { - - private String platformName; - private String platformVersion; - private String platformAPIVersion; - private boolean onlineMode; - private String serverIP; - private int serverPort; - private List plugins; - - GeyserSpigotDumpInfo() { - super(); - this.platformName = Bukkit.getName(); - this.platformVersion = Bukkit.getVersion(); - this.platformAPIVersion = Bukkit.getBukkitVersion(); - this.onlineMode = Bukkit.getOnlineMode(); - if (AsteriskSerializer.showSensitive || (Bukkit.getIp().equals("") || Bukkit.getIp().equals("0.0.0.0"))) { - this.serverIP = Bukkit.getIp(); - } else { - this.serverIP = "***"; - } - this.serverPort = Bukkit.getPort(); - this.plugins = new ArrayList<>(); - - for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { - this.plugins.add(new PluginInfo(plugin.isEnabled(), plugin.getName(), plugin.getDescription().getVersion(), plugin.getDescription().getMain(), plugin.getDescription().getAuthors())); - } - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java deleted file mode 100644 index 20bfecb6..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java +++ /dev/null @@ -1,81 +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.platform.spigot; - -import com.github.steveice10.mc.protocol.MinecraftConstants; -import lombok.AllArgsConstructor; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.server.ServerListPingEvent; -import org.bukkit.util.CachedServerIcon; -import org.geysermc.connector.common.ping.GeyserPingInfo; -import org.geysermc.connector.ping.IGeyserPingPassthrough; - -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.Collections; -import java.util.Iterator; - -@AllArgsConstructor -public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough { - - private final GeyserSpigotLogger logger; - - @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { - try { - ServerListPingEvent event = new GeyserPingEvent(inetSocketAddress.getAddress(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); - Bukkit.getPluginManager().callEvent(event); - GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), - new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()), - new GeyserPingInfo.Version(Bukkit.getVersion(), MinecraftConstants.PROTOCOL_VERSION) // thanks Spigot for not exposing this, just default to latest - ); - 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); - } - } - - // These methods are unimplemented on spigot api by default so we add stubs so plugins don't complain - private static class GeyserPingEvent extends ServerListPingEvent { - - public GeyserPingEvent(InetAddress address, String motd, int numPlayers, int maxPlayers) { - super(address, motd, numPlayers, maxPlayers); - } - - @Override - public void setServerIcon(CachedServerIcon icon) throws IllegalArgumentException, UnsupportedOperationException { - } - - @Override - public Iterator iterator() throws UnsupportedOperationException { - return Collections.EMPTY_LIST.iterator(); - } - } - -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java deleted file mode 100644 index b85aa313..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java +++ /dev/null @@ -1,308 +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.platform.spigot; - -import com.github.steveice10.mc.protocol.MinecraftConstants; -import org.bukkit.Bukkit; -import org.bukkit.plugin.java.JavaPlugin; -import org.geysermc.adapters.spigot.SpigotAdapters; -import org.geysermc.common.PlatformType; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.bootstrap.GeyserBootstrap; -import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.dump.BootstrapDumpInfo; -import org.geysermc.connector.network.translators.world.WorldManager; -import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; -import org.geysermc.connector.ping.IGeyserPingPassthrough; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; -import org.geysermc.platform.spigot.command.GeyserSpigotCommandExecutor; -import org.geysermc.platform.spigot.command.GeyserSpigotCommandManager; -import org.geysermc.platform.spigot.command.SpigotCommandSender; -import org.geysermc.platform.spigot.world.GeyserSpigotBlockPlaceListener; -import org.geysermc.platform.spigot.world.manager.*; -import us.myles.ViaVersion.api.Pair; -import us.myles.ViaVersion.api.Via; -import us.myles.ViaVersion.api.data.MappingData; -import us.myles.ViaVersion.api.protocol.Protocol; -import us.myles.ViaVersion.api.protocol.ProtocolRegistry; -import us.myles.ViaVersion.api.protocol.ProtocolVersion; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.UUID; -import java.util.logging.Level; - -public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { - private GeyserSpigotCommandManager geyserCommandManager; - private GeyserSpigotConfiguration geyserConfig; - private GeyserSpigotLogger geyserLogger; - private IGeyserPingPassthrough geyserSpigotPingPassthrough; - private GeyserSpigotWorldManager geyserWorldManager; - - private GeyserConnector connector; - - @Override - public void onEnable() { - // This is manually done instead of using Bukkit methods to save the config because otherwise comments get removed - try { - if (!getDataFolder().exists()) { - getDataFolder().mkdir(); - File bukkitConfig = new File("plugins/Geyser-Bukkit/config.yml"); - if (bukkitConfig.exists()) { // Copy over old configs - getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copy_bukkit_config")); - Files.copy(bukkitConfig.toPath(), new File(getDataFolder().toString() + "/config.yml").toPath()); - getLogger().log(Level.INFO, LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.copied_bukkit_config")); - } - } - File configFile = FileUtils.fileOrCopiedFromResource(new File(getDataFolder(), "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); - this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpigotConfiguration.class); - } catch (IOException ex) { - getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); - ex.printStackTrace(); - } - - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!Bukkit.getIp().equals("0.0.0.0") && !Bukkit.getIp().equals("")) { - geyserConfig.getRemote().setAddress(Bukkit.getIp()); - } - geyserConfig.getRemote().setPort(Bukkit.getPort()); - } - - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(Bukkit.getPort()); - } - - this.geyserLogger = new GeyserSpigotLogger(getLogger(), geyserConfig.isDebugMode()); - GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - - if (geyserConfig.getRemote().getAuthType().equals("floodgate") && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") == null) { - geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - this.getPluginLoader().disablePlugin(this); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType("floodgate"); - } - - geyserConfig.loadFloodgate(this); - - this.connector = GeyserConnector.start(PlatformType.SPIGOT, this); - - if (geyserConfig.isLegacyPingPassthrough()) { - this.geyserSpigotPingPassthrough = GeyserLegacyPingPassthrough.init(connector); - } else { - this.geyserSpigotPingPassthrough = new GeyserSpigotPingPassthrough(geyserLogger); - } - - this.geyserCommandManager = new GeyserSpigotCommandManager(this, connector); - - boolean isViaVersion = (Bukkit.getPluginManager().getPlugin("ViaVersion") != null); - if (isViaVersion) { - if (!isCompatible(Via.getAPI().getVersion().replace("-SNAPSHOT", ""), "3.2.0")) { - geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.viaversion.too_old", - "https://ci.viaversion.com/job/ViaVersion/")); - isViaVersion = false; - } - } - // Used to determine if Block.getBlockData() is present. - boolean isLegacy = !isCompatible(Bukkit.getServer().getVersion(), "1.13.0"); - if (isLegacy) - geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected; falling back to ViaVersion for block state retrieval."); - - boolean use3dBiomes = isCompatible(Bukkit.getServer().getVersion(), "1.16.0"); - if (!use3dBiomes) { - geyserLogger.debug("Legacy version of Minecraft (1.15.2 or older) detected; not using 3D biomes."); - } - - // Set if we need to use a different method for getting a player's locale - SpigotCommandSender.setUseLegacyLocaleMethod(!isCompatible(Bukkit.getServer().getVersion(), "1.12.0")); - - if (connector.getConfig().isUseAdapters()) { - try { - String name = Bukkit.getServer().getClass().getPackage().getName(); - String nmsVersion = name.substring(name.lastIndexOf('.') + 1); - SpigotAdapters.registerWorldAdapter(nmsVersion); - if (isViaVersion && isViaVersionNeeded()) { - if (isLegacy) { - // Pre-1.13 - this.geyserWorldManager = new GeyserSpigot1_12NativeWorldManager(); - } else { - // Post-1.13 - this.geyserWorldManager = new GeyserSpigotLegacyNativeWorldManager(this, use3dBiomes); - } - } else { - // No ViaVersion - this.geyserWorldManager = new GeyserSpigotNativeWorldManager(use3dBiomes); - } - geyserLogger.debug("Using NMS adapter: " + this.geyserWorldManager.getClass() + ", " + nmsVersion); - } catch (Exception e) { - if (geyserConfig.isDebugMode()) { - geyserLogger.debug("Error while attempting to find NMS adapter. Most likely, this can be safely ignored. :)"); - e.printStackTrace(); - } - } - } else { - geyserLogger.debug("Not using NMS adapter as it is disabled in the config."); - } - if (this.geyserWorldManager == null) { - // No NMS adapter - if (isLegacy && isViaVersion) { - // Use ViaVersion for converting pre-1.13 block states - this.geyserWorldManager = new GeyserSpigot1_12WorldManager(); - } else if (isLegacy) { - // Not sure how this happens - without ViaVersion, we don't know any block states, so just assume everything is air - this.geyserWorldManager = new GeyserSpigotFallbackWorldManager(); - } else { - // Post-1.13 - this.geyserWorldManager = new GeyserSpigotWorldManager(use3dBiomes); - } - geyserLogger.debug("Using default world manager: " + this.geyserWorldManager.getClass()); - } - GeyserSpigotBlockPlaceListener blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, this.geyserWorldManager); - - Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); - - this.getCommand("geyser").setExecutor(new GeyserSpigotCommandExecutor(connector)); - } - - @Override - public void onDisable() { - if (connector != null) { - connector.shutdown(); - } - } - - @Override - public GeyserSpigotConfiguration getGeyserConfig() { - return geyserConfig; - } - - @Override - public GeyserSpigotLogger getGeyserLogger() { - return geyserLogger; - } - - @Override - public CommandManager getGeyserCommandManager() { - return this.geyserCommandManager; - } - - @Override - public IGeyserPingPassthrough getGeyserPingPassthrough() { - return geyserSpigotPingPassthrough; - } - - @Override - public WorldManager getWorldManager() { - return this.geyserWorldManager; - } - - @Override - public Path getConfigFolder() { - return getDataFolder().toPath(); - } - - @Override - public BootstrapDumpInfo getDumpInfo() { - return new GeyserSpigotDumpInfo(); - } - - public boolean isCompatible(String version, String whichVersion) { - int[] currentVersion = parseVersion(version); - int[] otherVersion = parseVersion(whichVersion); - int length = Math.max(currentVersion.length, otherVersion.length); - for (int index = 0; index < length; index = index + 1) { - int self = (index < currentVersion.length) ? currentVersion[index] : 0; - int other = (index < otherVersion.length) ? otherVersion[index] : 0; - - if (self != other) { - return (self - other) > 0; - } - } - return true; - } - - private int[] parseVersion(String versionParam) { - versionParam = (versionParam == null) ? "" : versionParam; - if (versionParam.contains("(MC: ")) { - versionParam = versionParam.split("\\(MC: ")[1]; - versionParam = versionParam.split("\\)")[0]; - } - String[] stringArray = versionParam.split("[_.-]"); - int[] temp = new int[stringArray.length]; - for (int index = 0; index <= (stringArray.length - 1); index = index + 1) { - String t = stringArray[index].replaceAll("\\D", ""); - try { - temp[index] = Integer.parseInt(t); - } catch (NumberFormatException ex) { - temp[index] = 0; - } - } - return temp; - } - - /** - * @return the server version before ViaVersion finishes initializing - */ - public ProtocolVersion getServerProtocolVersion() { - String bukkitVersion = Bukkit.getServer().getVersion(); - // Turn "(MC: 1.16.4)" into 1.16.4. - String version = bukkitVersion.split("\\(MC: ")[1].split("\\)")[0]; - return ProtocolVersion.getClosest(version); - } - - /** - * This function should not run unless ViaVersion is installed on the server. - * - * @return true if there is any block mappings difference between the server and client. - */ - private boolean isViaVersionNeeded() { - ProtocolVersion serverVersion = getServerProtocolVersion(); - List> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION, - serverVersion.getVersion()); - if (protocolList == null) { - // No translation needed! - return false; - } - for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getValue().getMappingData(); - if (mappingData != null) { - return true; - } - } - // All mapping data is null, which means client and server block states are the same - return false; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/SpigotCommandSender.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/SpigotCommandSender.java deleted file mode 100644 index c1c2b2c7..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/SpigotCommandSender.java +++ /dev/null @@ -1,115 +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.platform.spigot.command; - -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.Player; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.utils.LanguageUtils; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class SpigotCommandSender implements CommandSender { - - /** - * Whether to use {@code Player.getLocale()} or {@code Player.spigot().getLocale()}, depending on version. - * 1.12 or greater should not use the legacy method. - */ - private static boolean USE_LEGACY_METHOD = false; - private static Method LOCALE_METHOD; - - private final org.bukkit.command.CommandSender handle; - private final String locale; - - public SpigotCommandSender(org.bukkit.command.CommandSender handle) { - this.handle = handle; - this.locale = getSpigotLocale(); - // Ensure even Java players' languages are loaded - LanguageUtils.loadGeyserLocale(locale); - } - - @Override - public String getName() { - return handle.getName(); - } - - @Override - public void sendMessage(String message) { - handle.sendMessage(message); - } - - @Override - public boolean isConsole() { - return handle instanceof ConsoleCommandSender; - } - - @Override - public String getLocale() { - return locale; - } - - /** - * Set if we are on pre-1.12, and therefore {@code player.getLocale()} doesn't exist and we have to get - * {@code player.spigot().getLocale()}. - * - * @param useLegacyMethod if we are running pre-1.12 and therefore need to use reflection to get the player locale - */ - public static void setUseLegacyLocaleMethod(boolean useLegacyMethod) { - USE_LEGACY_METHOD = useLegacyMethod; - if (USE_LEGACY_METHOD) { - try { - //noinspection JavaReflectionMemberAccess - of course it doesn't exist; that's why we're doing it - LOCALE_METHOD = Player.Spigot.class.getMethod("getLocale"); - } catch (NoSuchMethodException e) { - GeyserConnector.getInstance().getLogger().debug("Player.Spigot.getLocale() doesn't exist? Not a big deal but if you're seeing this please report it to the developers!"); - } - } - } - - /** - * So we only have to do nasty reflection stuff once per command - * - * @return the locale of the Spigot player - */ - private String getSpigotLocale() { - if (handle instanceof Player) { - Player player = (Player) handle; - if (USE_LEGACY_METHOD) { - try { - // sigh - // This was the only option on older Spigot instances and now it's gone - return (String) LOCALE_METHOD.invoke(player.spigot()); - } catch (IllegalAccessException | InvocationTargetException ignored) { - } - } else { - return player.getLocale(); - } - } - return LanguageUtils.getDefaultLocale(); - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java deleted file mode 100644 index 56fa7581..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotBlockPlaceListener.java +++ /dev/null @@ -1,71 +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.platform.spigot.world; - -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import lombok.AllArgsConstructor; -import org.bukkit.Bukkit; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockPlaceEvent; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.platform.spigot.world.manager.GeyserSpigotWorldManager; - -@AllArgsConstructor -public class GeyserSpigotBlockPlaceListener implements Listener { - - private final GeyserConnector connector; - private final GeyserSpigotWorldManager worldManager; - - @EventHandler - public void place(final BlockPlaceEvent event) { - for (GeyserSession session : connector.getPlayers()) { - if (event.getPlayer() == Bukkit.getPlayer(session.getPlayerEntity().getUsername())) { - LevelSoundEventPacket placeBlockSoundPacket = new LevelSoundEventPacket(); - placeBlockSoundPacket.setSound(SoundEvent.PLACE); - placeBlockSoundPacket.setPosition(Vector3f.from(event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ())); - placeBlockSoundPacket.setBabySound(false); - if (worldManager.isLegacy()) { - placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(worldManager.getBlockAt(session, - event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ()))); - } else { - String javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); - placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID))); - } - placeBlockSoundPacket.setIdentifier(":"); - session.sendUpstreamPacket(placeBlockSoundPacket); - session.setLastBlockPlacePosition(null); - session.setLastBlockPlacedId(null); - break; - } - } - } - -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java deleted file mode 100644 index ae199272..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12NativeWorldManager.java +++ /dev/null @@ -1,59 +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.platform.spigot.world.manager; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.geysermc.adapters.spigot.SpigotAdapters; -import org.geysermc.adapters.spigot.SpigotWorldAdapter; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import us.myles.ViaVersion.api.Via; -import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage; - -/** - * Used with ViaVersion and pre-1.13. - */ -public class GeyserSpigot1_12NativeWorldManager extends GeyserSpigot1_12WorldManager { - private final SpigotWorldAdapter adapter; - - public GeyserSpigot1_12NativeWorldManager() { - this.adapter = SpigotAdapters.getWorldAdapter(); - // Unlike post-1.13, we can't build up a cache of block states, because block entities need some special conversion - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); - if (player == null) { - return BlockTranslator.JAVA_AIR_ID; - } - // Get block entity storage - BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class); - int blockId = adapter.getBlockAt(player.getWorld(), x, y, z); - return getLegacyBlock(storage, blockId, x, y, z); - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java deleted file mode 100644 index cb450f7f..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigot1_12WorldManager.java +++ /dev/null @@ -1,141 +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.platform.spigot.world.manager; - -import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import us.myles.ViaVersion.api.Pair; -import us.myles.ViaVersion.api.Via; -import us.myles.ViaVersion.api.data.MappingData; -import us.myles.ViaVersion.api.minecraft.Position; -import us.myles.ViaVersion.api.protocol.Protocol; -import us.myles.ViaVersion.api.protocol.ProtocolRegistry; -import us.myles.ViaVersion.api.protocol.ProtocolVersion; -import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2; -import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.storage.BlockStorage; - -import java.util.List; - -/** - * Should be used when ViaVersion is present, no NMS adapter is being used, and we are pre-1.13. - * - * You need ViaVersion to connect to an older server with the Geyser-Spigot plugin. - */ -public class GeyserSpigot1_12WorldManager extends GeyserSpigotWorldManager { - /** - * Specific mapping data for 1.12 to 1.13. Used to convert the 1.12 block into the 1.13 block state. - * (Block IDs did not change between server versions until 1.13 and after) - */ - 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_12WorldManager() { - super(false); - this.mappingData1_12to1_13 = ProtocolRegistry.getProtocol(Protocol1_13To1_12_2.class).getMappingData(); - this.protocolList = ProtocolRegistry.getProtocolPath(CLIENT_PROTOCOL_VERSION, - ProtocolVersion.v1_13.getVersion()); - } - - @Override - @SuppressWarnings("deprecation") - public int getBlockAt(GeyserSession session, int x, int y, int z) { - Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); - if (player == null) { - return BlockTranslator.JAVA_AIR_ID; - } - // Get block entity storage - BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class); - Block block = player.getWorld().getBlockAt(x, y, z); - // Black magic that gets the old block state ID - int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF); - return getLegacyBlock(storage, blockId, x, y, z); - } - - /** - * - * @param storage ViaVersion's block entity storage (used to fix block entity state differences) - * @param blockId the pre-1.13 block id - * @param x X coordinate of block - * @param y Y coordinate of block - * @param z Z coordinate of block - * @return the block state updated to the latest Minecraft version - */ - @SuppressWarnings("deprecation") - public int getLegacyBlock(BlockStorage storage, int blockId, int x, int y, int z) { - // Convert block state from old version (1.12.2) -> 1.13 -> 1.13.1 -> 1.14 -> 1.15 -> 1.16 -> 1.16.2 - blockId = mappingData1_12to1_13.getNewBlockId(blockId); - // Translate block entity differences - some information was stored in block tags and not block states - if (storage.isWelcome(blockId)) { // No getOrDefault method - BlockStorage.ReplacementData data = storage.get(new Position(x, (short) y, z)); - if (data != null && data.getReplacement() != -1) { - blockId = data.getReplacement(); - } - } - for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getValue().getMappingData(); - if (mappingData != null) { - blockId = mappingData.getNewBlockStateId(blockId); - } - } - return blockId; - } - - @SuppressWarnings("deprecation") - @Override - public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) { - Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); - if (player == null) { - return; - } - World world = player.getWorld(); - // Get block entity storage - BlockStorage storage = Via.getManager().getConnection(player.getUniqueId()).get(BlockStorage.class); - for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order - for (int blockZ = 0; blockZ < 16; blockZ++) { - for (int blockX = 0; blockX < 16; blockX++) { - Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ); - // Black magic that gets the old block state ID - int blockId = (block.getType().getId() << 4) | (block.getData() & 0xF); - chunk.set(blockX, blockY, blockZ, getLegacyBlock(storage, blockId, (x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ)); - } - } - } - } - - @Override - public boolean isLegacy() { - return true; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java deleted file mode 100644 index f2ae8a64..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotFallbackWorldManager.java +++ /dev/null @@ -1,62 +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.platform.spigot.world.manager; - -import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; - -/** - * Should only be used when we know {@link GeyserSpigotWorldManager#getBlockAt(GeyserSession, int, int, int)} - * cannot be accurate. Typically, this is when ViaVersion is not installed but a client still manages to connect. - * If this occurs to you somehow, please let us know!! - */ -public class GeyserSpigotFallbackWorldManager extends GeyserSpigotWorldManager { - public GeyserSpigotFallbackWorldManager() { - // Since this is pre-1.13 (and thus pre-1.15), there will never be 3D biomes. - super(false); - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - return BlockTranslator.JAVA_AIR_ID; - } - - @Override - public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) { - // Do nothing, since we can't do anything with the chunk - } - - @Override - public boolean hasMoreBlockDataThanChunkCache() { - return false; - } - - @Override - public boolean isLegacy() { - return true; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java deleted file mode 100644 index 8ed1b388..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotLegacyNativeWorldManager.java +++ /dev/null @@ -1,79 +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.platform.spigot.world.manager; - -import com.github.steveice10.mc.protocol.MinecraftConstants; -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntList; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.platform.spigot.GeyserSpigotPlugin; -import us.myles.ViaVersion.api.Pair; -import us.myles.ViaVersion.api.data.MappingData; -import us.myles.ViaVersion.api.protocol.Protocol; -import us.myles.ViaVersion.api.protocol.ProtocolRegistry; -import us.myles.ViaVersion.api.protocol.ProtocolVersion; - -import java.util.List; - -/** - * Used when block IDs need to be translated to the latest version - */ -public class GeyserSpigotLegacyNativeWorldManager extends GeyserSpigotNativeWorldManager { - - private final Int2IntMap oldToNewBlockId; - - public GeyserSpigotLegacyNativeWorldManager(GeyserSpigotPlugin plugin, boolean use3dBiomes) { - super(use3dBiomes); - IntList allBlockStates = adapter.getAllBlockStates(); - oldToNewBlockId = new Int2IntOpenHashMap(allBlockStates.size()); - ProtocolVersion serverVersion = plugin.getServerProtocolVersion(); - List> protocolList = ProtocolRegistry.getProtocolPath(MinecraftConstants.PROTOCOL_VERSION, - serverVersion.getVersion()); - for (int oldBlockId : allBlockStates) { - int newBlockId = oldBlockId; - // protocolList should *not* be null; we checked for that before initializing this class - for (int i = protocolList.size() - 1; i >= 0; i--) { - MappingData mappingData = protocolList.get(i).getValue().getMappingData(); - if (mappingData != null) { - newBlockId = mappingData.getNewBlockStateId(newBlockId); - } - } - oldToNewBlockId.put(oldBlockId, newBlockId); - } - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - int nativeBlockId = super.getBlockAt(session, x, y, z); - return oldToNewBlockId.getOrDefault(nativeBlockId, nativeBlockId); - } - - @Override - public boolean isLegacy() { - return true; - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java deleted file mode 100644 index c7e3a3d4..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotNativeWorldManager.java +++ /dev/null @@ -1,51 +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.platform.spigot.world.manager; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.geysermc.adapters.spigot.SpigotAdapters; -import org.geysermc.adapters.spigot.SpigotWorldAdapter; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; - -public class GeyserSpigotNativeWorldManager extends GeyserSpigotWorldManager { - protected final SpigotWorldAdapter adapter; - - public GeyserSpigotNativeWorldManager(boolean use3dBiomes) { - super(use3dBiomes); - adapter = SpigotAdapters.getWorldAdapter(); - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - Player player = Bukkit.getPlayer(session.getPlayerEntity().getUsername()); - if (player == null) { - return BlockTranslator.JAVA_AIR_ID; - } - return adapter.getBlockAt(player.getWorld(), x, y, z); - } -} diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java deleted file mode 100644 index 748d0f1e..00000000 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/manager/GeyserSpigotWorldManager.java +++ /dev/null @@ -1,195 +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.platform.spigot.world.manager; - -import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.MinecraftConstants; -import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; -import it.unimi.dsi.fastutil.ints.Int2IntMap; -import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -import org.bukkit.Bukkit; -import org.bukkit.World; -import org.bukkit.block.Biome; -import org.bukkit.block.Block; -import org.bukkit.block.data.BlockData; -import org.bukkit.entity.Player; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.GeyserWorldManager; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.GameRule; -import org.geysermc.connector.utils.LanguageUtils; - -import java.io.InputStream; - -/** - * The base world manager to use when there is no supported NMS revision - */ -public class GeyserSpigotWorldManager extends GeyserWorldManager { - /** - * The current client protocol version for ViaVersion usage. - */ - protected static final int CLIENT_PROTOCOL_VERSION = MinecraftConstants.PROTOCOL_VERSION; - - /** - * Whether the server is pre-1.16 and therefore does not support 3D biomes on an API level guaranteed. - */ - private final boolean use3dBiomes; - /** - * Stores a list of {@link Biome} ordinal numbers to Minecraft biome numeric IDs. - * - * Working with the Biome enum in Spigot poses two problems: - * 1: The Biome enum values change in both order and names over the years. - * 2: There is no way to get the Minecraft biome ID from the name itself with Spigot. - * To solve both of these problems, we store a JSON file of every Biome enum that has existed, - * along with its 1.16 biome number. - * - * The key is the Spigot Biome ordinal; the value is the Minecraft Java biome numerical ID - */ - private final Int2IntMap biomeToIdMap = new Int2IntOpenHashMap(Biome.values().length); - - public GeyserSpigotWorldManager(boolean use3dBiomes) { - this.use3dBiomes = use3dBiomes; - - // Load the values into the biome-to-ID map - InputStream biomeStream = FileUtils.getResource("biomes.json"); - JsonNode biomes; - try { - biomes = GeyserConnector.JSON_MAPPER.readTree(biomeStream); - } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); - } - // Only load in the biomes that are present in this version of Minecraft - for (Biome enumBiome : Biome.values()) { - JsonNode biome = biomes.get(enumBiome.toString()); - if (biome != null) { - biomeToIdMap.put(enumBiome.ordinal(), biome.intValue()); - } else { - GeyserConnector.getInstance().getLogger().debug("No biome mapping found for " + enumBiome.toString() + - ", defaulting to 0"); - biomeToIdMap.put(enumBiome.ordinal(), 0); - } - } - } - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return BlockTranslator.JAVA_AIR_ID; - } - World world = bukkitPlayer.getWorld(); - return BlockTranslator.getJavaIdBlockMap().getOrDefault(world.getBlockAt(x, y, z).getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID); - } - - @Override - public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) { - Player bukkitPlayer; - if ((bukkitPlayer = Bukkit.getPlayer(session.getPlayerEntity().getUsername())) == null) { - return; - } - World world = bukkitPlayer.getWorld(); - for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order - for (int blockZ = 0; blockZ < 16; blockZ++) { - for (int blockX = 0; blockX < 16; blockX++) { - Block block = world.getBlockAt((x << 4) + blockX, (y << 4) + blockY, (z << 4) + blockZ); - int id = BlockTranslator.getJavaIdBlockMap().getOrDefault(block.getBlockData().getAsString(), BlockTranslator.JAVA_AIR_ID); - chunk.set(blockX, blockY, blockZ, id); - } - } - } - } - - @Override - public boolean hasMoreBlockDataThanChunkCache() { - return true; - } - - @Override - @SuppressWarnings("deprecation") - public int[] getBiomeDataAt(GeyserSession session, int x, int z) { - if (session.getPlayerEntity() == null) { - return new int[1024]; - } - int[] biomeData = new int[1024]; - World world = Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld(); - int chunkX = x << 4; - int chunkZ = z << 4; - int chunkXmax = chunkX + 16; - int chunkZmax = chunkZ + 16; - // 3D biomes didn't exist until 1.15 - if (use3dBiomes) { - for (int localX = chunkX; localX < chunkXmax; localX += 4) { - for (int localY = 0; localY < 255; localY += + 4) { - for (int localZ = chunkZ; localZ < chunkZmax; localZ += 4) { - // Index is based on wiki.vg's index requirements - final int i = ((localY >> 2) & 63) << 4 | ((localZ >> 2) & 3) << 2 | ((localX >> 2) & 3); - biomeData[i] = biomeToIdMap.getOrDefault(world.getBiome(localX, localY, localZ).ordinal(), 0); - } - } - } - } else { - // Looks like the same code, but we're not checking the Y coordinate here - for (int localX = chunkX; localX < chunkXmax; localX += 4) { - for (int localY = 0; localY < 255; localY += + 4) { - for (int localZ = chunkZ; localZ < chunkZmax; localZ += 4) { - // Index is based on wiki.vg's index requirements - final int i = ((localY >> 2) & 63) << 4 | ((localZ >> 2) & 3) << 2 | ((localX >> 2) & 3); - biomeData[i] = biomeToIdMap.getOrDefault(world.getBiome(localX, localZ).ordinal(), 0); - } - } - } - } - return biomeData; - } - - public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { - return Boolean.parseBoolean(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID())); - } - - @Override - public int getGameRuleInt(GeyserSession session, GameRule gameRule) { - return Integer.parseInt(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getGameRuleValue(gameRule.getJavaID())); - } - - @Override - public boolean hasPermission(GeyserSession session, String permission) { - return Bukkit.getPlayer(session.getPlayerEntity().getUsername()).hasPermission(permission); - } - - /** - * This must be set to true if we are pre-1.13, and {@link BlockData#getAsString() does not exist}. - * - * This should be set to true if we are post-1.13 but before the latest version, and we should convert the old block state id - * to the current one. - * - * @return whether there is a difference between client block state and server block state that requires extra processing - */ - public boolean isLegacy() { - return false; - } -} diff --git a/bootstrap/spigot/src/main/resources/biomes.json b/bootstrap/spigot/src/main/resources/biomes.json deleted file mode 100644 index 56520e91..00000000 --- a/bootstrap/spigot/src/main/resources/biomes.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "MUTATED_ICE_FLATS" : 140, - "MUTATED_TAIGA" : 133, - "SAVANNA_PLATEAU_MOUNTAINS" : 164, - "DEEP_WARM_OCEAN" : 47, - "REDWOOD_TAIGA_HILLS" : 33, - "THE_VOID" : 127, - "COLD_TAIGA_MOUNTAINS" : 158, - "BAMBOO_JUNGLE_HILLS" : 169, - "MOUNTAINS" : 3, - "MESA_PLATEAU" : 39, - "SNOWY_TAIGA_HILLS" : 31, - "DEEP_FROZEN_OCEAN" : 50, - "EXTREME_HILLS" : 3, - "BIRCH_FOREST_MOUNTAINS" : 155, - "FOREST" : 4, - "BIRCH_FOREST" : 27, - "SNOWY_TUNDRA" : 12, - "ICE_SPIKES" : 140, - "FROZEN_OCEAN" : 10, - "WARPED_FOREST" : 172, - "WOODED_BADLANDS_PLATEAU" : 38, - "BADLANDS_PLATEAU" : 39, - "ICE_PLAINS_SPIKES" : 140, - "MEGA_TAIGA" : 32, - "MUTATED_SAVANNA_ROCK" : 164, - "SAVANNA_PLATEAU" : 36, - "DARK_FOREST_HILLS" : 157, - "END_MIDLANDS" : 41, - "SHATTERED_SAVANNA_PLATEAU" : 164, - "SAVANNA" : 35, - "MUSHROOM_ISLAND_SHORE" : 15, - "SWAMP" : 6, - "ICE_MOUNTAINS" : 13, - "BEACH" : 16, - "MUTATED_MESA_CLEAR_ROCK" : 167, - "END_HIGHLANDS" : 42, - "COLD_BEACH" : 26, - "JUNGLE" : 21, - "MUTATED_TAIGA_COLD" : 158, - "TALL_BIRCH_HILLS" : 156, - "DARK_FOREST" : 29, - "WOODED_HILLS" : 18, - "HELL" : 8, - "MUTATED_REDWOOD_TAIGA" : 160, - "MESA_PLATEAU_FOREST" : 38, - "MUSHROOM_ISLAND" : 14, - "BADLANDS" : 37, - "END_BARRENS" : 43, - "MUTATED_EXTREME_HILLS_WITH_TREES" : 162, - "MUTATED_JUNGLE_EDGE" : 151, - "MODIFIED_BADLANDS_PLATEAU" : 167, - "ROOFED_FOREST_MOUNTAINS" : 157, - "SOUL_SAND_VALLEY" : 170, - "DESERT" : 2, - "MUTATED_PLAINS" : 129, - "MUTATED_BIRCH_FOREST" : 155, - "WOODED_MOUNTAINS" : 34, - "TAIGA_HILLS" : 19, - "BAMBOO_JUNGLE" : 168, - "SWAMPLAND_MOUNTAINS" : 134, - "DESERT_MOUNTAINS" : 130, - "REDWOOD_TAIGA" : 32, - "MUSHROOM_FIELDS" : 14, - "GIANT_TREE_TAIGA_HILLS" : 33, - "PLAINS" : 1, - "JUNGLE_EDGE" : 23, - "SAVANNA_MOUNTAINS" : 163, - "DEEP_COLD_OCEAN" : 49, - "DESERT_LAKES" : 130, - "MOUNTAIN_EDGE" : 20, - "SNOWY_MOUNTAINS" : 13, - "MESA_PLATEAU_MOUNTAINS" : 167, - "JUNGLE_MOUNTAINS" : 149, - "SMALLER_EXTREME_HILLS" : 20, - "MESA_PLATEAU_FOREST_MOUNTAINS" : 166, - "NETHER_WASTES" : 8, - "BIRCH_FOREST_HILLS_MOUNTAINS" : 156, - "MUTATED_JUNGLE" : 149, - "WARM_OCEAN" : 44, - "DEEP_OCEAN" : 24, - "STONE_BEACH" : 25, - "MODIFIED_JUNGLE" : 149, - "MUTATED_SAVANNA" : 163, - "TAIGA_COLD_HILLS" : 31, - "OCEAN" : 0, - "SMALL_END_ISLANDS" : 40, - "MUSHROOM_FIELD_SHORE" : 15, - "GRAVELLY_MOUNTAINS" : 131, - "FROZEN_RIVER" : 11, - "TAIGA_COLD" : 30, - "BASALT_DELTAS" : 173, - "EXTREME_HILLS_WITH_TREES" : 34, - "MEGA_TAIGA_HILLS" : 33, - "MUTATED_FOREST" : 132, - "MUTATED_BIRCH_FOREST_HILLS" : 156, - "SKY" : 9, - "LUKEWARM_OCEAN" : 45, - "EXTREME_HILLS_MOUNTAINS" : 131, - "COLD_TAIGA_HILLS" : 31, - "THE_END" : 9, - "SUNFLOWER_PLAINS" : 129, - "SAVANNA_ROCK" : 36, - "ERODED_BADLANDS" : 165, - "STONE_SHORE" : 25, - "EXTREME_HILLS_PLUS_MOUNTAINS" : 162, - "CRIMSON_FOREST" : 171, - "VOID" : 127, - "SNOWY_TAIGA" : 30, - "SNOWY_TAIGA_MOUNTAINS" : 158, - "FLOWER_FOREST" : 132, - "COLD_OCEAN" : 46, - "BEACHES" : 16, - "MESA" : 37, - "MUSHROOM_SHORE" : 15, - "MESA_CLEAR_ROCK" : 39, - "NETHER" : 8, - "ICE_PLAINS" : 12, - "SHATTERED_SAVANNA" : 163, - "ROOFED_FOREST" : 29, - "GIANT_SPRUCE_TAIGA_HILLS" : 161, - "SNOWY_BEACH" : 26, - "MESA_BRYCE" : 165, - "JUNGLE_EDGE_MOUNTAINS" : 151, - "MUTATED_DESERT" : 130, - "MODIFIED_GRAVELLY_MOUNTAINS" : 158, - "MEGA_SPRUCE_TAIGA" : 160, - "TAIGA_MOUNTAINS" : 133, - "SMALL_MOUNTAINS" : 20, - "EXTREME_HILLS_PLUS" : 34, - "GIANT_SPRUCE_TAIGA" : 160, - "FOREST_HILLS" : 18, - "DESERT_HILLS" : 17, - "MUTATED_REDWOOD_TAIGA_HILLS" : 161, - "MEGA_SPRUCE_TAIGA_HILLS" : 161, - "RIVER" : 7, - "GIANT_TREE_TAIGA" : 32, - "SWAMPLAND" : 6, - "JUNGLE_HILLS" : 22, - "TALL_BIRCH_FOREST" : 155, - "DEEP_LUKEWARM_OCEAN" : 48, - "MESA_ROCK" : 38, - "SWAMP_HILLS" : 134, - "MODIFIED_WOODED_BADLANDS_PLATEAU" : 166, - "MODIFIED_JUNGLE_EDGE" : 151, - "BIRCH_FOREST_HILLS" : 28, - "COLD_TAIGA" : 30, - "TAIGA" : 5, - "MUTATED_MESA_ROCK" : 166, - "MUTATED_SWAMPLAND" : 134, - "ICE_FLATS" : 12, - "MUTATED_ROOFED_FOREST" : 157, - "MUTATED_MESA" : 165, - "MUTATED_EXTREME_HILLS" : 131 -} diff --git a/bootstrap/sponge/pom.xml b/bootstrap/sponge/pom.xml index 97c4ac8a..c9abbe3e 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,15 +6,15 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT + ../ bootstrap-sponge - org.geysermc connector - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT compile @@ -69,26 +69,6 @@ it.unimi.dsi.fastutil org.geysermc.platform.sponge.shaded.fastutil - - org.reflections - org.geysermc.platform.sponge.shaded.reflections - - - com.google.common - org.geysermc.platform.sponge.shaded.google.common - - - com.google.guava - org.geysermc.platform.sponge.shaded.google.guava - - - org.dom4j - org.geysermc.platform.sponge.shaded.dom4j - - - net.kyori - org.geysermc.platform.sponge.shaded.kyori - diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java index 5a0496ca..fc148470 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 +25,216 @@ package org.geysermc.platform.sponge; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; +import lombok.AllArgsConstructor; +import ninja.leaping.configurate.ConfigurationNode; + +import org.geysermc.connector.GeyserConfiguration; + +import java.io.File; import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +public class GeyserSpongeConfiguration implements GeyserConfiguration { + + private File dataFolder; + private ConfigurationNode node; + + private SpongeBedrockConfiguration bedrockConfig; + private SpongeRemoteConfiguration remoteConfig; + private SpongeMetricsInfo metricsInfo; + + private Map userAuthInfo = new HashMap<>(); + + public GeyserSpongeConfiguration(File dataFolder, ConfigurationNode node) { + this.dataFolder = dataFolder; + this.node = node; + + this.bedrockConfig = new SpongeBedrockConfiguration(node.getNode("bedrock")); + this.remoteConfig = new SpongeRemoteConfiguration(node.getNode("remote")); + this.metricsInfo = new SpongeMetricsInfo(); + + if (node.getNode("userAuths").getValue() == null) + return; + + List userAuths = new ArrayList(((LinkedHashMap)node.getNode("userAuths").getValue()).keySet()); + for (String key : userAuths) { + userAuthInfo.put(key, new SpongeUserAuthenticationInfo(key)); + } + } -public final class GeyserSpongeConfiguration extends GeyserJacksonConfiguration { @Override - public Path getFloodgateKeyPath() { - return null; //floodgate isn't available for Sponge + public SpongeBedrockConfiguration getBedrock() { + return bedrockConfig; + } + + @Override + public SpongeRemoteConfiguration getRemote() { + return remoteConfig; + } + + @Override + public Map getUserAuths() { + return userAuthInfo; + } + + @Override + public boolean isCommandSuggestions() { + return node.getNode("command-suggestions").getBoolean(true); + } + + @Override + public boolean isPassthroughMotd() { + return node.getNode("passthrough-motd").getBoolean(false); + } + + @Override + public boolean isPassthroughPlayerCounts() { + return node.getNode("passthrough-player-counts").getBoolean(false); + } + + @Override + public boolean isLegacyPingPassthrough() { + return node.getNode("legacy-ping-passthrough").getBoolean(false); + } + + @Override + public int getPingPassthroughInterval() { + return node.getNode("ping-passthrough-interval").getInt(3); + } + + @Override + public int getMaxPlayers() { + return node.getNode("max-players").getInt(100); + } + + @Override + public boolean isDebugMode() { + return node.getNode("debug-mode").getBoolean(false); + } + + @Override + public int getGeneralThreadPool() { + return node.getNode("genereal-thread-pool").getInt(32); + } + + @Override + public boolean isAllowThirdPartyCapes() { + return node.getNode("allow-third-party-capes").getBoolean(true); + } + + @Override + public boolean isAllowThirdPartyEars() { + return node.getNode("allow-third-party-ears").getBoolean(false); + } + + @Override + public String getDefaultLocale() { + return node.getNode("default-locale").getString("en_us"); + } + + @Override + public Path getFloodgateKeyFile() { + return Paths.get(dataFolder.toString(), node.getNode("floodgate-key-file").getString("public-key.pem")); + } + + @Override + public boolean isCacheChunks() { + return node.getNode("cache-chunks").getBoolean(false); + } + + @Override + public boolean isAboveBedrockNetherBuilding() { + return node.getNode("above-bedrock-nether-building").getBoolean(false); + } + + @Override + public SpongeMetricsInfo getMetrics() { + return metricsInfo; + } + + @AllArgsConstructor + public class SpongeBedrockConfiguration implements IBedrockConfiguration { + + private ConfigurationNode node; + + @Override + public String getAddress() { + return node.getNode("address").getString("0.0.0.0"); + } + + @Override + public int getPort() { + return node.getNode("port").getInt(19132); + } + + @Override + public String getMotd1() { + return node.getNode("motd1").getString("GeyserMC"); + } + + @Override + public String getMotd2() { + return node.getNode("motd2").getString("GeyserMC"); + } + } + + @AllArgsConstructor + public class SpongeRemoteConfiguration implements IRemoteConfiguration { + + private ConfigurationNode node; + + @Override + public String getAddress() { + return node.getNode("address").getString("127.0.0.1"); + } + + @Override + public int getPort() { + return node.getNode("port").getInt(25565); + } + + @Override + public String getAuthType() { + return node.getNode("auth-type").getString("online"); + } + } + + public class SpongeUserAuthenticationInfo implements IUserAuthenticationInfo { + + private String key; + + public SpongeUserAuthenticationInfo(String key) { + this.key = key; + } + + @Override + public String getEmail() { + return node.getNode("userAuths").getNode(key).getNode("email").getString(); + } + + @Override + public String getPassword() { + return node.getNode("userAuths").getNode(key).getNode("password").getString(); + } + } + + public class SpongeMetricsInfo implements IMetricsInfo { + + @Override + public boolean isEnabled() { + return node.getNode("metrics").getNode("enabled").getBoolean(true); + } + + @Override + public String getUniqueId() { + return node.getNode("metrics").getNode("uuid").getString("generateduuid"); + } + } + + @Override + public int getConfigVersion() { + return node.getNode("config-version").getInt(0); } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeDumpInfo.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeDumpInfo.java deleted file mode 100644 index d36ba311..00000000 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeDumpInfo.java +++ /dev/null @@ -1,62 +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.platform.sponge; - -import lombok.Getter; -import org.geysermc.connector.dump.BootstrapDumpInfo; -import org.spongepowered.api.Platform; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.plugin.PluginContainer; - -import java.util.ArrayList; -import java.util.List; - -@Getter -public class GeyserSpongeDumpInfo extends BootstrapDumpInfo { - - private String platformName; - private String platformVersion; - private boolean onlineMode; - private String serverIP; - private int serverPort; - private List plugins; - - GeyserSpongeDumpInfo() { - super(); - PluginContainer container = Sponge.getPlatform().getContainer(Platform.Component.IMPLEMENTATION); - this.platformName = container.getName(); - this.platformVersion = container.getVersion().get(); - this.onlineMode = Sponge.getServer().getOnlineMode(); - this.serverIP = Sponge.getServer().getBoundAddress().get().getHostString(); - this.serverPort = Sponge.getServer().getBoundAddress().get().getPort(); - this.plugins = new ArrayList<>(); - - for (PluginContainer plugin : Sponge.getPluginManager().getPlugins()) { - String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown"); - this.plugins.add(new PluginInfo(true, plugin.getName(), plugin.getVersion().get(), pluginClass, plugin.getAuthors())); - } - } -} diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeLogger.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeLogger.java index b560c4dd..fb7cb54b 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeLogger.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,15 @@ package org.geysermc.platform.sponge; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; + import org.geysermc.connector.GeyserLogger; import org.slf4j.Logger; @AllArgsConstructor public class GeyserSpongeLogger implements GeyserLogger { - private final Logger logger; - @Getter @Setter - private boolean debug; + + private Logger logger; + private boolean debugMode; @Override public void severe(String message) { @@ -69,8 +68,12 @@ public class GeyserSpongeLogger implements GeyserLogger { @Override public void debug(String message) { - if (debug) { + if (debugMode) info(message); - } + } + + @Override + public void setDebug(boolean debugMode) { + this.debugMode = debugMode; } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeMain.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeMain.java index f6643a5c..11b9583f 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeMain.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeMain.java @@ -1,31 +1,32 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.sponge; -import org.geysermc.connector.common.main.IGeyserMain; +import org.geysermc.common.main.IGeyserMain; public class GeyserSpongeMain extends IGeyserMain { diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java index 8d63fca6..31b6dc7f 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java @@ -1,32 +1,32 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.sponge; -import com.github.steveice10.mc.protocol.MinecraftConstants; -import org.geysermc.connector.common.ping.GeyserPingInfo; +import org.geysermc.common.ping.GeyserPingInfo; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.spongepowered.api.MinecraftVersion; import org.spongepowered.api.Sponge; @@ -35,65 +35,55 @@ import org.spongepowered.api.event.cause.Cause; import org.spongepowered.api.event.cause.EventContext; import org.spongepowered.api.event.server.ClientPingServerEvent; import org.spongepowered.api.network.status.StatusClient; -import org.spongepowered.api.profile.GameProfile; import java.lang.reflect.Method; +import java.net.Inet4Address; import java.net.InetSocketAddress; import java.util.Optional; public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { + private static final GeyserStatusClient STATUS_CLIENT = new GeyserStatusClient(); private static final Cause CAUSE = Cause.of(EventContext.empty(), Sponge.getServer()); private static Method SpongeStatusResponse_create; @SuppressWarnings({"unchecked", "rawtypes"}) @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + public GeyserPingInfo getPingInformation() { // come on Sponge, this is in commons, why not expose it :( ClientPingServerEvent event; try { - if (SpongeStatusResponse_create == null) { + if(SpongeStatusResponse_create == null) { Class SpongeStatusResponse = Class.forName("org.spongepowered.common.network.status.SpongeStatusResponse"); Class MinecraftServer = Class.forName("net.minecraft.server.MinecraftServer"); SpongeStatusResponse_create = SpongeStatusResponse.getDeclaredMethod("create", MinecraftServer); } Object response = SpongeStatusResponse_create.invoke(null, Sponge.getServer()); - event = SpongeEventFactory.createClientPingServerEvent(CAUSE, new GeyserStatusClient(inetSocketAddress), (ClientPingServerEvent.Response) response); + event = SpongeEventFactory.createClientPingServerEvent(CAUSE, STATUS_CLIENT, (ClientPingServerEvent.Response) response); } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } Sponge.getEventManager().post(event); GeyserPingInfo geyserPingInfo = new GeyserPingInfo( event.getResponse().getDescription().toPlain(), - new GeyserPingInfo.Players( - event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(), - event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline() - ), - new GeyserPingInfo.Version( - event.getResponse().getVersion().getName(), - MinecraftConstants.PROTOCOL_VERSION) // thanks for also not exposing this sponge - ); - event.getResponse().getPlayers().get().getProfiles().stream() - .map(GameProfile::getName) - .map(op -> op.orElseThrow(IllegalStateException::new)) - .forEach(geyserPingInfo.getPlayerList()::add); + event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(), + event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax()); + event.getResponse().getPlayers().get().getProfiles().forEach(player -> { + geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new)); + }); return geyserPingInfo; } @SuppressWarnings("NullableProblems") private static class GeyserStatusClient implements StatusClient { - private final InetSocketAddress remote; - - public GeyserStatusClient(InetSocketAddress remote) { - this.remote = remote; - } + private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); @Override public InetSocketAddress getAddress() { - return this.remote; + return FAKE_REMOTE; } @Override diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java index 5b8bf54b..d226add7 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 @@ package org.geysermc.platform.sponge; import com.google.inject.Inject; +import ninja.leaping.configurate.ConfigurationNode; +import ninja.leaping.configurate.loader.ConfigurationLoader; +import ninja.leaping.configurate.yaml.YAMLConfigurationLoader; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.sponge.command.GeyserSpongeCommandExecutor; import org.geysermc.platform.sponge.command.GeyserSpongeCommandManager; import org.slf4j.Logger; @@ -49,7 +50,6 @@ import org.spongepowered.api.plugin.Plugin; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; -import java.nio.file.Path; import java.util.UUID; @Plugin(id = "geyser", name = GeyserConnector.NAME + "-Sponge", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC") @@ -78,31 +78,34 @@ public class GeyserSpongePlugin implements GeyserBootstrap { try { configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (file) -> file.replaceAll("generateduuid", UUID.randomUUID().toString())); } catch (IOException ex) { - logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed")); + logger.warn("Failed to copy config.yml from jar path!"); ex.printStackTrace(); } + ConfigurationLoader loader = YAMLConfigurationLoader.builder().setPath(configFile.toPath()).build(); + ConfigurationNode config; try { - this.geyserConfig = FileUtils.loadConfig(configFile, GeyserSpongeConfiguration.class); + config = loader.load(); + this.geyserConfig = new GeyserSpongeConfiguration(configDir, config); } catch (IOException ex) { - logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed")); + logger.warn("Failed to load config.yml!"); ex.printStackTrace(); return; } + ConfigurationNode serverIP = config.getNode("remote").getNode("address"); + ConfigurationNode serverPort = config.getNode("remote").getNode("port"); + if (Sponge.getServer().getBoundAddress().isPresent()) { InetSocketAddress javaAddr = Sponge.getServer().getBoundAddress().get(); // Don't change the ip if its listening on all interfaces // By default this should be 127.0.0.1 but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - geyserConfig.getRemote().setPort(javaAddr.getPort()); + if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { + serverIP.setValue("127.0.0.1"); } - } - if (geyserConfig.getBedrock().isCloneRemotePort()){ - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); + serverPort.setValue(javaAddr.getPort()); } this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); @@ -144,11 +147,6 @@ public class GeyserSpongePlugin implements GeyserBootstrap { return geyserSpongePingPassthrough; } - @Override - public Path getConfigFolder() { - return configDir.toPath(); - } - @Listener public void onServerStart(GameStartedServerEvent event) { onEnable(); @@ -158,9 +156,4 @@ public class GeyserSpongePlugin implements GeyserBootstrap { public void onServerStop(GameStoppedEvent event) { onDisable(); } - - @Override - public BootstrapDumpInfo getDumpInfo() { - return new GeyserSpongeDumpInfo(); - } } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandExecutor.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandExecutor.java index 938d1992..91cb59b0 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandExecutor.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 @@ package org.geysermc.platform.sponge.command; import lombok.AllArgsConstructor; + +import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.ChatColor; import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.utils.LanguageUtils; import org.spongepowered.api.command.CommandCallable; import org.spongepowered.api.command.CommandException; import org.spongepowered.api.command.CommandResult; @@ -55,14 +55,13 @@ public class GeyserSpongeCommandExecutor implements CommandCallable { if (args.length > 0) { if (getCommand(args[0]) != null) { if (!source.hasPermission(getCommand(args[0]).getPermission())) { - // Not ideal to use log here but we dont get a session - source.sendMessage(Text.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); + source.sendMessage(Text.of(ChatColor.RED + "You do not have permission to execute this command!")); return CommandResult.success(); } - getCommand(args[0]).execute(new SpongeCommandSender(source), args.length > 1 ? Arrays.copyOfRange(args, 1, args.length) : new String[0]); + getCommand(args[0]).execute(new SpongeCommandSender(source), args); } } else { - getCommand("help").execute(new SpongeCommandSender(source), new String[0]); + getCommand("help").execute(new SpongeCommandSender(source), args); } return CommandResult.success(); } @@ -70,7 +69,7 @@ public class GeyserSpongeCommandExecutor implements CommandCallable { @Override public List getSuggestions(CommandSource source, String arguments, @Nullable Location targetPosition) throws CommandException { if (arguments.split(" ").length == 1) { - return connector.getCommandManager().getCommandNames(); + return Arrays.asList("?", "help", "reload", "shutdown", "stop"); } return new ArrayList<>(); } diff --git a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandManager.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandManager.java index 1f6eaa69..c36511a4 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandManager.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/GeyserSpongeCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/platform/sponge/command/SpongeCommandSender.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/SpongeCommandSender.java index 4616e400..a309a26f 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/SpongeCommandSender.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/command/SpongeCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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 831239f6..770ca100 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,21 +6,21 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT + ../ bootstrap-standalone - org.geysermc connector - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT compile net.minecrell terminalconsoleappender - 1.2.0 + 1.1.1 org.apache.logging.log4j @@ -63,7 +63,7 @@ org.apache.logging.log4j log4j-core - 2.13.2 + 2.13.1 org.apache.logging.log4j diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java index 5aa15635..aa0d2392 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,39 +25,19 @@ package org.geysermc.platform.standalone; -import com.fasterxml.jackson.databind.BeanDescription; -import com.fasterxml.jackson.databind.JavaType; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.introspect.AnnotatedField; -import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition; -import lombok.Getter; -import net.minecrell.terminalconsole.TerminalConsoleAppender; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.Appender; -import org.apache.logging.log4j.core.Logger; -import org.apache.logging.log4j.core.appender.ConsoleAppender; import org.geysermc.common.PlatformType; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.bootstrap.GeyserBootstrap; -import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; -import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; +import org.geysermc.connector.GeyserConfiguration; +import org.geysermc.connector.bootstrap.GeyserBootstrap; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.standalone.command.GeyserCommandManager; -import org.geysermc.platform.standalone.gui.GeyserStandaloneGUI; import java.io.File; import java.io.IOException; -import java.lang.reflect.Method; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.text.MessageFormat; -import java.util.*; -import java.util.stream.Collectors; +import java.util.UUID; public class GeyserStandaloneBootstrap implements GeyserBootstrap { @@ -66,180 +46,33 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { private GeyserStandaloneLogger geyserLogger; private IGeyserPingPassthrough geyserPingPassthrough; - private GeyserStandaloneGUI gui; - - @Getter - private boolean useGui = System.console() == null && !isHeadless(); - private String configFilename = "config.yml"; - private GeyserConnector connector; - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - - private static final Map argsConfigKeys = new HashMap<>(); - public static void main(String[] args) { - GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap(); - // Set defaults - boolean useGuiOpts = bootstrap.useGui; - String configFilenameOpt = bootstrap.configFilename; - - List availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class); - - for (int i = 0; i < args.length; i++) { - // By default, standalone Geyser will check if it should open the GUI based on if the GUI is null - // Optionally, you can force the use of a GUI or no GUI by specifying args - // Allows gui and nogui without options, for backwards compatibility - String arg = args[i]; - switch (arg) { - case "--gui": - case "gui": - useGuiOpts = true; - break; - case "--nogui": - case "nogui": - useGuiOpts = false; - break; - case "--config": - case "-c": - if (i >= args.length - 1) { - System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c")); - return; - } - configFilenameOpt = args[i+1]; i++; - System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt)); - break; - case "--help": - case "-h": - System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.usage"), "[java -jar] Geyser.jar [opts]")); - System.out.println(" " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.options")); - System.out.println(" -c, --config [file] " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config")); - System.out.println(" -h, --help " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.help")); - System.out.println(" --gui, --nogui " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.gui")); - return; - default: - // We have likely added a config option argument - if (arg.startsWith("--")) { - // Split the argument by an = - String[] argParts = arg.substring(2).split("="); - if (argParts.length == 2) { - // Split the config key by . to allow for nested options - String[] configKeyParts = argParts[0].split("\\."); - - // Loop the possible config options to check the passed key is valid - boolean found = false; - for (BeanPropertyDefinition property : availableProperties) { - if (configKeyParts[0].equals(property.getName())) { - if (configKeyParts.length > 1) { - // Loop sub-section options to check the passed key is valid - for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) { - if (configKeyParts[1].equals(subProperty.getName())) { - found = true; - break; - } - } - } else { - found = true; - } - - break; - } - } - - // Add the found key to the stored list for later usage - if (found) { - argsConfigKeys.put(argParts[0], argParts[1]); - break; - } - } - } - - System.err.println(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised", arg)); - return; - } - } - bootstrap.onEnable(useGuiOpts, configFilenameOpt); - } - - public void onEnable(boolean useGui, String configFilename) { - this.configFilename = configFilename; - this.useGui = useGui; - this.onEnable(); - } - - public void onEnable(boolean useGui) { - this.useGui = useGui; - this.onEnable(); + new GeyserStandaloneBootstrap().onEnable(); } @Override public void onEnable() { - Logger logger = (Logger) LogManager.getRootLogger(); - for (Appender appender : logger.getAppenders().values()) { - // Remove the appender that is not in use - // Prevents multiple appenders/double logging and removes harmless errors - if ((useGui && appender instanceof TerminalConsoleAppender) || (!useGui && appender instanceof ConsoleAppender)) { - logger.removeAppender(appender); - } - } - if (useGui && gui == null) { - gui = new GeyserStandaloneGUI(); - gui.redirectSystemStreams(); - gui.startUpdateThread(); - } - geyserLogger = new GeyserStandaloneLogger(); LoopbackUtil.checkLoopback(geyserLogger); try { - File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); + File configFile = FileUtils.fileOrCopiedFromResource("config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); geyserConfig = FileUtils.loadConfig(configFile, GeyserStandaloneConfiguration.class); - - handleArgsConfigOptions(); - - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - geyserConfig.setAutoconfiguredRemote(true); // Doesn't really need to be set but /shrug - geyserConfig.getRemote().setAddress("127.0.0.1"); - } } catch (IOException ex) { - geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); - if (gui == null) { - System.exit(1); - } else { - // Leave the process running so the GUI is still visible - return; - } + geyserLogger.severe("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex); + System.exit(0); } GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); connector = GeyserConnector.start(PlatformType.STANDALONE, this); geyserCommandManager = new GeyserCommandManager(connector); - if (gui != null) { - gui.setupInterface(geyserLogger, geyserCommandManager); - } - geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); - if (!useGui) { - geyserLogger.start(); // Throws an error otherwise - } - } - - /** - * Check using {@link java.awt.GraphicsEnvironment} that we are a headless client - * - * @return If the current environment is headless - */ - private boolean isHeadless() { - try { - Class graphicsEnv = Class.forName("java.awt.GraphicsEnvironment"); - Method isHeadless = graphicsEnv.getDeclaredMethod("isHeadless"); - return (boolean) isHeadless.invoke(null); - } catch (Exception ignore) { } - - return true; + geyserLogger.start(); } @Override @@ -267,110 +100,4 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { public IGeyserPingPassthrough getGeyserPingPassthrough() { return geyserPingPassthrough; } - - @Override - public Path getConfigFolder() { - // Return the current working directory - return Paths.get(System.getProperty("user.dir")); - } - - @Override - public BootstrapDumpInfo getDumpInfo() { - return new GeyserStandaloneDumpInfo(this); - } - - /** - * Get the {@link BeanPropertyDefinition}s for the given class - * - * @param clazz The class to get the definitions for - * @return A list of {@link BeanPropertyDefinition} for the given class - */ - public static List getPOJOForClass(Class clazz) { - JavaType javaType = OBJECT_MAPPER.getTypeFactory().constructType(clazz); - - // Introspect the given type - BeanDescription beanDescription = OBJECT_MAPPER.getSerializationConfig().introspect(javaType); - - // Find properties - List properties = beanDescription.findProperties(); - - // Get the ignored properties - Set ignoredProperties = OBJECT_MAPPER.getSerializationConfig().getAnnotationIntrospector() - .findPropertyIgnorals(beanDescription.getClassInfo()).getIgnored(); - - // Filter properties removing the ignored ones - return properties.stream() - .filter(property -> !ignoredProperties.contains(property.getName())) - .collect(Collectors.toList()); - } - - /** - * Set a POJO property value on an object - * - * @param property The {@link BeanPropertyDefinition} to set - * @param parentObject The object to alter - * @param value The new value of the property - */ - private static void setConfigOption(BeanPropertyDefinition property, Object parentObject, Object value) { - Object parsedValue = value; - - // Change the values type if needed - if (int.class.equals(property.getRawPrimaryType())) { - parsedValue = Integer.valueOf((String) parsedValue); - } else if (boolean.class.equals(property.getRawPrimaryType())) { - parsedValue = Boolean.valueOf((String) parsedValue); - } - - // Force the value to be set - AnnotatedField field = property.getField(); - field.fixAccess(true); - field.setValue(parentObject, parsedValue); - } - - /** - * Update the loaded {@link GeyserStandaloneConfiguration} with any values passed in the command line arguments - */ - private void handleArgsConfigOptions() { - // Get the available properties from the class - List availableProperties = getPOJOForClass(GeyserJacksonConfiguration.class); - - for (Map.Entry configKey : argsConfigKeys.entrySet()) { - String[] configKeyParts = configKey.getKey().split("\\."); - - // Loop over the properties looking for any matches against the stored one from the argument - for (BeanPropertyDefinition property : availableProperties) { - if (configKeyParts[0].equals(property.getName())) { - if (configKeyParts.length > 1) { - // Loop through the sub property if the first part matches - for (BeanPropertyDefinition subProperty : getPOJOForClass(property.getRawPrimaryType())) { - if (configKeyParts[1].equals(subProperty.getName())) { - geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue())); - - // Set the sub property value on the config - try { - Object subConfig = property.getGetter().callOn(geyserConfig); - setConfigOption(subProperty, subConfig, configKey.getValue()); - } catch (Exception e) { - geyserLogger.error("Failed to set config option: " + property.getFullName()); - } - - break; - } - } - } else { - geyserLogger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.set_config_option", configKey.getKey(), configKey.getValue())); - - // Set the property value on the config - try { - setConfigOption(property, geyserConfig, configKey.getValue()); - } catch (Exception e) { - geyserLogger.error("Failed to set config option: " + property.getFullName()); - } - } - - break; - } - } - } - } } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java index fad05d9d..bd029204 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,111 @@ package org.geysermc.platform.standalone; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + import lombok.Getter; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; +import org.geysermc.connector.GeyserConfiguration; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; -@Getter @JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration { +@Getter +public class GeyserStandaloneConfiguration implements GeyserConfiguration { + + private BedrockConfiguration bedrock; + private RemoteConfiguration remote; + + @JsonProperty("floodgate-key-file") + private String floodgateKeyFile; + + private Map userAuths; + + @JsonProperty("command-suggestions") + private boolean isCommandSuggestions; + + @JsonProperty("passthrough-motd") + private boolean isPassthroughMotd; + + @JsonProperty("passthrough-player-counts") + private boolean isPassthroughPlayerCounts; + + @JsonProperty("legacy-ping-passthrough") + private boolean isLegacyPingPassthrough; + + @JsonProperty("ping-passthrough-interval") + private int pingPassthroughInterval; + + @JsonProperty("max-players") + private int maxPlayers; + + @JsonProperty("debug-mode") + private boolean debugMode; + + @JsonProperty("general-thread-pool") + private int generalThreadPool; + + @JsonProperty("allow-third-party-capes") + private boolean allowThirdPartyCapes; + + @JsonProperty("allow-third-party-ears") + private boolean allowThirdPartyEars; + + @JsonProperty("default-locale") + private String defaultLocale; + + @JsonProperty("cache-chunks") + private boolean cacheChunks; + + @JsonProperty("above-bedrock-nether-building") + private boolean isAboveBedrockNetherBuilding; + + private MetricsInfo metrics; + @Override - public Path getFloodgateKeyPath() { - return Paths.get(getFloodgateKeyFile()); + public Path getFloodgateKeyFile() { + return Paths.get(floodgateKeyFile); } + + @Getter + public static class BedrockConfiguration implements IBedrockConfiguration { + + private String address; + private int port; + + private String motd1; + private String motd2; + } + + @Getter + public static class RemoteConfiguration implements IRemoteConfiguration { + + private String address; + private int port; + + private String motd1; + private String motd2; + + @JsonProperty("auth-type") + private String authType; + } + + @Getter + public static class UserAuthenticationInfo implements IUserAuthenticationInfo { + private String email; + private String password; + } + + @Getter + public static class MetricsInfo implements IMetricsInfo { + + private boolean enabled; + + @JsonProperty("uuid") + private String uniqueId; + } + + @JsonProperty("config-version") + private int configVersion; } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneDumpInfo.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneDumpInfo.java deleted file mode 100644 index 2577ce03..00000000 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneDumpInfo.java +++ /dev/null @@ -1,40 +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.platform.standalone; - -import lombok.Getter; -import org.geysermc.connector.dump.BootstrapDumpInfo; - -@Getter -public class GeyserStandaloneDumpInfo extends BootstrapDumpInfo { - - private boolean isGui; - - GeyserStandaloneDumpInfo(GeyserStandaloneBootstrap bootstrap) { - super(); - this.isGui = bootstrap.isUseGui(); - } -} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneLogger.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneLogger.java index 64e5b5e8..ffb252b2 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneLogger.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneLogger.java @@ -1,41 +1,43 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.standalone; import lombok.extern.log4j.Log4j2; + import net.minecrell.terminalconsole.SimpleTerminalConsole; -import org.apache.logging.log4j.Level; + import org.apache.logging.log4j.core.config.Configurator; +import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.common.ChatColor; @Log4j2 -public class GeyserStandaloneLogger extends SimpleTerminalConsole implements GeyserLogger, CommandSender { +public class GeyserStandaloneLogger extends SimpleTerminalConsole implements org.geysermc.connector.GeyserLogger, CommandSender { + private boolean colored = true; @Override @@ -80,7 +82,7 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey @Override public void info(String message) { - log.info(printConsole(ChatColor.RESET + ChatColor.BOLD + message, colored)); + log.info(printConsole(ChatColor.WHITE + message, colored)); } @Override @@ -94,11 +96,7 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey @Override public void setDebug(boolean debug) { - Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO); - } - - public boolean isDebug() { - return log.isDebugEnabled(); + Configurator.setLevel(log.getName(), debug ? org.apache.logging.log4j.Level.DEBUG : log.getLevel()); } @Override diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java index 9c10234f..03c49705 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/LoopbackUtil.java @@ -1,38 +1,12 @@ -/* - * 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.platform.standalone; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.utils.LanguageUtils; - import java.io.InputStream; import java.nio.file.Files; import java.nio.file.OpenOption; import java.nio.file.Paths; +import org.geysermc.common.ChatColor; + public class LoopbackUtil { private static final String checkExemption = "powershell -Command \"CheckNetIsolation LoopbackExempt -s\""; // Java's Exec feature runs as CMD, NetIsolation is only accessible from PowerShell. private static final String loopbackCommand = "powershell -Command \"CheckNetIsolation LoopbackExempt -a -n='Microsoft.MinecraftUWP_8wekyb3d8bbwe'\""; @@ -57,12 +31,12 @@ public class LoopbackUtil { Files.write(Paths.get(System.getenv("temp") + "/loopback_minecraft.bat"), loopbackCommand.getBytes(), new OpenOption[0]); process = Runtime.getRuntime().exec(startScript); - geyserLogger.info(ChatColor.AQUA + LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.added")); + geyserLogger.info(ChatColor.AQUA + "Added loopback exemption to Windows!"); } } catch (Exception e) { e.printStackTrace(); - geyserLogger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.loopback.failed")); + geyserLogger.error("Couldn't auto add loopback exemption to Windows!"); } } } diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/command/GeyserCommandManager.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/command/GeyserCommandManager.java index 85b2798f..41bf61c1 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/command/GeyserCommandManager.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/command/GeyserCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/platform/standalone/gui/ANSIColor.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/ANSIColor.java deleted file mode 100644 index eb64a969..00000000 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/ANSIColor.java +++ /dev/null @@ -1,78 +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.platform.standalone.gui; - -import lombok.Getter; - -import java.awt.*; -import java.util.regex.Pattern; - -public enum ANSIColor { - // Normal colors - BLACK("(0;)?30(0;)?m", Color.getHSBColor(0.000f, 0.000f, 0.000f)), - RED("(0;)?31(0;)?m", Color.getHSBColor(0.000f, 1.000f, 0.502f)), - GREEN("(0;)?32(0;)?m", Color.getHSBColor(0.333f, 1.000f, 0.502f)), - YELLOW("(0;)?33(0;)?m", Color.getHSBColor(0.167f, 1.000f, 0.502f)), - BLUE("(0;)?34(0;)?m", Color.getHSBColor(0.667f, 1.000f, 0.502f)), - MAGENTA("(0;)?35(0;)?m", Color.getHSBColor(0.833f, 1.000f, 0.502f)), - CYAN("(0;)?36(0;)?m", Color.getHSBColor(0.500f, 1.000f, 0.502f)), - WHITE("(0;)?37(0;)?m", Color.getHSBColor(0.000f, 0.000f, 0.753f)), - - // Bold colors - B_BLACK("(1;30|30;1)m", Color.getHSBColor(0.000f, 0.000f, 0.502f)), - B_RED("(1;31|31;1)m", Color.getHSBColor(0.000f, 1.000f, 1.000f)), - B_GREEN("(1;32|32;1)m", Color.getHSBColor(0.333f, 1.000f, 1.000f)), - B_YELLOW("(1;33|33;1)m", Color.getHSBColor(0.167f, 1.000f, 1.000f)), - B_BLUE("(1;34|34;1)m", Color.getHSBColor(0.667f, 1.000f, 1.000f)), - B_MAGENTA("(1;35|35;1)m", Color.getHSBColor(0.833f, 1.000f, 1.000f)), - B_CYAN("(1;36|36;1)m", Color.getHSBColor(0.500f, 1.000f, 1.000f)), - B_WHITE("(1;37|37;1)m", Color.getHSBColor(0.000f, 0.000f, 1.000f)), - - RESET("0m", Color.getHSBColor(0.000f, 0.000f, 1.000f)); - - private static final ANSIColor[] VALUES = values(); - private static final String PREFIX = Pattern.quote("\u001B["); - - private final String ANSICode; - - @Getter - private final Color color; - - ANSIColor(String ANSICode, Color color) { - this.ANSICode = ANSICode; - this.color = color; - } - - public static ANSIColor fromANSI(String code) { - for (ANSIColor value : VALUES) { - if (code.matches(PREFIX + value.ANSICode)) { - return value; - } - } - - return B_WHITE; - } -} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/ColorPane.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/ColorPane.java deleted file mode 100644 index 10309395..00000000 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/ColorPane.java +++ /dev/null @@ -1,117 +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.platform.standalone.gui; - -import javax.swing.*; -import javax.swing.text.*; -import java.awt.*; - -/** - * This class was based on this code: https://stackoverflow.com/a/6899478/5299903 - */ -public class ColorPane extends JTextPane { - private static Color colorCurrent = ANSIColor.RESET.getColor(); - private String remaining = ""; - - /** - * Append the given string in the given color to the text pane - * @param c The color - * @param s The text - */ - private void append(Color c, String s) { - StyleContext sc = StyleContext.getDefaultStyleContext(); - AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c); - int len = getDocument().getLength(); - - try { - getDocument().insertString(len, s, aset); - } catch (BadLocationException e) { - e.printStackTrace(); - } - } - - /** - * Extract the ANSI color codes from the string and add each part to the text pane - * - * @param s The text to parse - */ - public void appendANSI(String s) { // convert ANSI color codes first - int aPos = 0; // current char position in addString - int aIndex = 0; // index of next Escape sequence - int mIndex = 0; // index of "m" terminating Escape sequence - String tmpString = ""; - boolean stillSearching = true; // true until no more Escape sequences - String addString = remaining + s; - remaining = ""; - - if (addString.length() > 0) { - aIndex = addString.indexOf("\u001B"); // find first escape - if (aIndex == -1) { // no escape/color change in this string, so just send it with current color - append(colorCurrent, addString); - return; - } - // otherwise There is an escape character in the string, so we must process it - - if (aIndex > 0) { // Escape is not first char, so send text up to first escape - tmpString = addString.substring(0, aIndex); - append(colorCurrent, tmpString); - aPos = aIndex; // aPos is now at the beginning of the first escape sequence - } - - - // while there's text in the input buffer - stillSearching = true; - while (stillSearching) { - mIndex = addString.indexOf("m", aPos); // find the end of the escape sequence - if (mIndex < 0) { // the buffer ends halfway through the ansi string! - remaining = addString.substring(aPos, addString.length()); - stillSearching = false; - continue; - } else { - tmpString = addString.substring(aPos, mIndex+1); - colorCurrent = ANSIColor.fromANSI(tmpString).getColor(); - } - aPos = mIndex + 1; - // now we have the color, send text that is in that color (up to next escape) - - aIndex = addString.indexOf("\u001B", aPos); - - if (aIndex == -1) { // if that was the last sequence of the input, send remaining text - tmpString = addString.substring(aPos, addString.length()); - append(colorCurrent, tmpString); - stillSearching = false; - continue; // jump out of loop early, as the whole string has been sent now - } - - // there is another escape sequence, so send part of the string and prepare for the next - tmpString = addString.substring(aPos, aIndex); - aPos = aIndex; - append(colorCurrent, tmpString); - - } - } - } -} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GeyserStandaloneGUI.java deleted file mode 100644 index fb6a46f9..00000000 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GeyserStandaloneGUI.java +++ /dev/null @@ -1,355 +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.platform.standalone.gui; - -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; -import org.geysermc.platform.standalone.GeyserStandaloneLogger; -import org.geysermc.platform.standalone.command.GeyserCommandManager; - -import javax.swing.*; -import javax.swing.table.DefaultTableModel; -import javax.swing.text.Document; -import java.awt.*; -import java.awt.event.*; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Vector; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -public class GeyserStandaloneGUI { - - private static final DefaultTableModel playerTableModel = new DefaultTableModel(); - private static final List ramValues = new ArrayList<>(); - - private static final ColorPane consolePane = new ColorPane(); - private static final GraphPanel ramGraph = new GraphPanel(); - private static final JTable playerTable = new JTable(playerTableModel); - private static final int originalFontSize = consolePane.getFont().getSize(); - - private static final long MEGABYTE = 1024L * 1024L; - - private final JMenu commandsMenu; - private final JMenu optionsMenu; - - public GeyserStandaloneGUI() { - // Create the frame and setup basic settings - JFrame frame = new JFrame(LanguageUtils.getLocaleStringLog("geyser.gui.title")); - frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); - frame.setSize(800, 400); - frame.setMinimumSize(frame.getSize()); - - // Remove Java UI look - try { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception ignored) { } - - // Show a confirm dialog on close - frame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent we) - { - String[] buttons = {LanguageUtils.getLocaleStringLog("geyser.gui.exit.confirm"), LanguageUtils.getLocaleStringLog("geyser.gui.exit.deny")}; - int result = JOptionPane.showOptionDialog(frame, LanguageUtils.getLocaleStringLog("geyser.gui.exit.message"), frame.getTitle(), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, buttons, buttons[1]); - if (result == JOptionPane.YES_OPTION) { - System.exit(0); - } - } - }); - - Container cp = frame.getContentPane(); - - // Fetch and set the icon for the frame - URL image = getClass().getClassLoader().getResource("icon.png"); - if (image != null) { - ImageIcon icon = new ImageIcon(image); - frame.setIconImage(icon.getImage()); - } - - // Setup the split pane and event listeners - JSplitPane splitPane = new JSplitPane(); - splitPane.setDividerLocation(600); - splitPane.addPropertyChangeListener("dividerLocation", e -> splitPaneLimit((JSplitPane)e.getSource())); - splitPane.addComponentListener(new ComponentAdapter() { - public void componentResized(ComponentEvent e) { - splitPaneLimit((JSplitPane)e.getSource()); - } - }); - - cp.add(splitPane, BorderLayout.CENTER); - - // Set the background and disable input for the text pane - consolePane.setBackground(Color.BLACK); - consolePane.setEditable(false); - - // Wrap the text pane in a scroll pane and add it to the form - JScrollPane consoleScrollPane = new JScrollPane(consolePane); - //cp.add(consoleScrollPane, BorderLayout.CENTER); - splitPane.setLeftComponent(consoleScrollPane); - - // Create a new menu bar for the top of the frame - JMenuBar menuBar = new JMenuBar(); - - // Create 'File' - JMenu fileMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file")); - fileMenu.setMnemonic(KeyEvent.VK_F); - menuBar.add(fileMenu); - - // 'Open Geyser folder' button - JMenuItem openButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file.open_folder"), KeyEvent.VK_O); - openButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK)); - openButton.addActionListener(e -> { - try { - Desktop.getDesktop().open(new File("./")); - } catch (IOException ignored) { } - }); - fileMenu.add(openButton); - - fileMenu.addSeparator(); - - // 'Exit' button - JMenuItem exitButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.file.exit"), KeyEvent.VK_X); - exitButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.ALT_MASK)); - exitButton.addActionListener(e -> System.exit(0)); - fileMenu.add(exitButton); - - // Create 'Commands' - commandsMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.commands")); - commandsMenu.setMnemonic(KeyEvent.VK_C); - menuBar.add(commandsMenu); - - // Create 'View' - JMenu viewMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view")); - viewMenu.setMnemonic(KeyEvent.VK_V); - menuBar.add(viewMenu); - - // 'Zoom in' button - JMenuItem zoomInButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.zoom_in")); - zoomInButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_DOWN_MASK)); - zoomInButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() + 1))); - viewMenu.add(zoomInButton); - - // 'Zoom in' button - JMenuItem zoomOutButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.zoom_out")); - zoomOutButton.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_DOWN_MASK)); - zoomOutButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), consolePane.getFont().getSize() - 1))); - viewMenu.add(zoomOutButton); - - // 'Reset Zoom' button - JMenuItem resetZoomButton = new JMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.view.reset_zoom")); - resetZoomButton.addActionListener(e -> consolePane.setFont(new Font(consolePane.getFont().getName(), consolePane.getFont().getStyle(), originalFontSize))); - viewMenu.add(resetZoomButton); - - // create 'Options' - optionsMenu = new JMenu(LanguageUtils.getLocaleStringLog("geyser.gui.menu.options")); - viewMenu.setMnemonic(KeyEvent.VK_O); - menuBar.add(optionsMenu); - - // Set the frames menu bar - frame.setJMenuBar(menuBar); - - JPanel rightPane = new JPanel(); - rightPane.setLayout(new CardLayout(5, 5)); - //cp.add(rightPane, BorderLayout.EAST); - splitPane.setRightComponent(rightPane); - - JPanel rightContentPane = new JPanel(); - rightContentPane.setLayout(new GridLayout(2, 1, 5, 5)); - rightPane.add(rightContentPane); - - // Set the ram graph to 0 - for (int i = 0; i < 10; i++) { - ramValues.add(0); - } - ramGraph.setValues(ramValues); - ramGraph.setXLabel(LanguageUtils.getLocaleStringLog("geyser.gui.graph.loading")); - rightContentPane.add(ramGraph); - - playerTableModel.addColumn(LanguageUtils.getLocaleStringLog("geyser.gui.table.ip")); - playerTableModel.addColumn(LanguageUtils.getLocaleStringLog("geyser.gui.table.username")); - - JScrollPane playerScrollPane = new JScrollPane(playerTable); - rightContentPane.add(playerScrollPane); - - // This has to be done last - frame.setVisible(true); - } - - /** - * Queue up an update to the text pane so we don't block the main thread - * - * @param text The text to append - */ - private void updateTextPane(final String text) { - SwingUtilities.invokeLater(() -> { - consolePane.appendANSI(text); - Document doc = consolePane.getDocument(); - consolePane.setCaretPosition(doc.getLength()); - }); - } - - /** - * Redirect the default io streams to the text pane - */ - public void redirectSystemStreams() { - // Setup a new output stream to forward it to the text pane - OutputStream out = new OutputStream() { - @Override - public void write(final int b) { - updateTextPane(String.valueOf((char) b)); - } - - @Override - public void write(byte[] b, int off, int len) { - updateTextPane(new String(b, off, len)); - } - - @Override - public void write(byte[] b) { - write(b, 0, b.length); - } - }; - - // Override the system output streams - System.setOut(new PrintStream(out, true)); - System.setErr(new PrintStream(out, true)); - - } - - /** - * Add all the Geyser commands to the commands menu, and setup the debug mode toggle - * - * @param geyserStandaloneLogger The current logger - * @param geyserCommandManager The commands manager - */ - public void setupInterface(GeyserStandaloneLogger geyserStandaloneLogger, GeyserCommandManager geyserCommandManager) { - commandsMenu.removeAll(); - optionsMenu.removeAll(); - - for (Map.Entry command : geyserCommandManager.getCommands().entrySet()) { - // Remove the offhand command and any alias commands to prevent duplicates in the list - if (!command.getValue().isExecutableOnConsole() || command.getValue().getAliases().contains(command.getKey())) { - continue; - } - - // Create the button that runs the command - boolean hasSubCommands = command.getValue().hasSubCommands(); - // Add an extra menu if there are more commands that can be run - JMenuItem commandButton = hasSubCommands ? new JMenu(command.getValue().getName()) : new JMenuItem(command.getValue().getName()); - commandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription()); - if (!hasSubCommands) { - commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ })); - } else { - // Add a submenu that's the same name as the menu can't be pressed - JMenuItem otherCommandButton = new JMenuItem(command.getValue().getName()); - otherCommandButton.getAccessibleContext().setAccessibleDescription(command.getValue().getDescription()); - otherCommandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ })); - commandButton.add(otherCommandButton); - // Add a menu option for all possible subcommands - for (String subCommandName : command.getValue().getSubCommands()) { - JMenuItem item = new JMenuItem(subCommandName); - item.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{subCommandName})); - commandButton.add(item); - } - } - commandsMenu.add(commandButton); - } - - // 'Debug Mode' toggle - JCheckBoxMenuItem debugMode = new JCheckBoxMenuItem(LanguageUtils.getLocaleStringLog("geyser.gui.menu.options.toggle_debug_mode")); - debugMode.setSelected(geyserStandaloneLogger.isDebug()); - debugMode.addActionListener(e -> geyserStandaloneLogger.setDebug(!geyserStandaloneLogger.isDebug())); - optionsMenu.add(debugMode); - } - - /** - * Start the thread to update the form information every 1s - */ - public void startUpdateThread() { - ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor(); - - Runnable periodicTask = () -> { - if (GeyserConnector.getInstance() != null) { - // Update player table - playerTableModel.getDataVector().removeAllElements(); - - for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) { - Vector row = new Vector<>(); - row.add(player.getSocketAddress().getHostName()); - row.add(player.getPlayerEntity().getUsername()); - - playerTableModel.addRow(row); - } - - playerTableModel.fireTableDataChanged(); - } - - // Update ram graph - final long freeMemory = Runtime.getRuntime().freeMemory(); - final long totalMemory = Runtime.getRuntime().totalMemory(); - final int freePercent = (int)(freeMemory * 100.0 / totalMemory + 0.5); - ramValues.add(100 - freePercent); - - ramGraph.setXLabel(LanguageUtils.getLocaleStringLog("geyser.gui.graph.usage", String.format("%,d", (totalMemory - freeMemory) / MEGABYTE), freePercent)); - - // Trim the list - int k = ramValues.size(); - if ( k > 10 ) - ramValues.subList(0, k - 10).clear(); - - // Update the graph - ramGraph.setValues(ramValues); - }; - - // SwingUtilities.invokeLater is called so we don't run into threading issues with the GUI - executor.scheduleAtFixedRate(() -> SwingUtilities.invokeLater(periodicTask), 0, 1, TimeUnit.SECONDS); - } - - /** - * Make sure the JSplitPane divider is within a set of bounds - * - * @param splitPane The JSplitPane to check - */ - private void splitPaneLimit(JSplitPane splitPane) { - JRootPane frame = splitPane.getRootPane(); - int location = splitPane.getDividerLocation(); - if (location < frame.getWidth() - frame.getWidth() * 0.4f) { - splitPane.setDividerLocation(Math.round(frame.getWidth() - frame.getWidth() * 0.4f)); - } else if (location > frame.getWidth() - 200) { - splitPane.setDividerLocation(frame.getWidth() - 200); - } - } -} diff --git a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GraphPanel.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GraphPanel.java deleted file mode 100644 index ebcc8f82..00000000 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GraphPanel.java +++ /dev/null @@ -1,187 +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.platform.standalone.gui; - -import lombok.Setter; - -import javax.swing.*; -import java.awt.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * This has been modified to fit Geyser more but is based on - * https://gist.github.com/roooodcastro/6325153#gistcomment-3107524 - */ -public final class GraphPanel extends JPanel { - private final static int padding = 10; - private final static int labelPadding = 25; - private final static int pointWidth = 4; - private final static int numberYDivisions = 10; - private final static Color lineColor = new Color(44, 102, 230, 255); - private final static Color pointColor = new Color(100, 100, 100, 255); - private final static Color gridColor = new Color(200, 200, 200, 255); - private static final Stroke graphStroke = new BasicStroke(2f); - private List values = new ArrayList<>(10); - - @Setter - private String xLabel = ""; - - public GraphPanel() { - setPreferredSize(new Dimension(200 - (padding * 2), 150 - (padding * 2))); - } - - public void setValues(Collection newValues) { - values.clear(); - addValues(newValues); - } - - public void addValues(Collection newValues) { - values.addAll(newValues); - updateUI(); - } - - @Override - protected void paintComponent(Graphics graphics) { - super.paintComponent(graphics); - if (!(graphics instanceof Graphics2D)) { - graphics.drawString("Graphics is not Graphics2D, unable to render", 0, 0); - return; - } - final Graphics2D g = (Graphics2D) graphics; - g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - - final int length = values.size(); - final int width = getWidth(); - final int height = getHeight(); - final int maxScore = getMaxScore(); - final int minScore = getMinScore(); - final int scoreRange = maxScore - minScore; - - // draw white background - g.setColor(Color.WHITE); - g.fillRect( - padding + labelPadding, - padding, - width - (2 * padding) - labelPadding, - height - 2 * padding - labelPadding); - g.setColor(Color.BLACK); - - final FontMetrics fontMetrics = g.getFontMetrics(); - final int fontHeight = fontMetrics.getHeight(); - - // create hatch marks and grid lines for y axis. - for (int i = 0; i < numberYDivisions + 1; i++) { - final int x1 = padding + labelPadding; - final int x2 = pointWidth + padding + labelPadding; - final int y = height - ((i * (height - padding * 2 - labelPadding)) / numberYDivisions + padding + labelPadding); - if (length > 0) { - g.setColor(gridColor); - g.drawLine(padding + labelPadding + 1 + pointWidth, y, width - padding, y); - - g.setColor(Color.BLACK); - final int tickValue = (int) (minScore + ((scoreRange * i) / numberYDivisions)); - final String yLabel = tickValue + ""; - final int labelWidth = fontMetrics.stringWidth(yLabel); - g.drawString(yLabel, x1 - labelWidth - 5, y + (fontHeight / 2) - 3); - } - g.drawLine(x1, y, x2, y); - } - - // and for x axis - if (length > 1) { - for (int i = 0; i < length; i++) { - final int x = i * (width - padding * 2 - labelPadding) / (length - 1) + padding + labelPadding; - final int y1 = height - padding - labelPadding; - final int y2 = y1 - pointWidth; - if ((i % ((int) ((length / 20.0)) + 1)) == 0) { - g.setColor(gridColor); - g.drawLine(x, height - padding - labelPadding - 1 - pointWidth, x, padding); - - g.setColor(Color.BLACK); - - /*g.setColor(Color.BLACK); - final String xLabel = i + ""; - final int labelWidth = fontMetrics.stringWidth(xLabel); - g.drawString(xLabel, x - labelWidth / 2, y1 + fontHeight + 3);*/ - } - g.drawLine(x, y1, x, y2); - } - } - - // create x and y axes - g.drawLine(padding + labelPadding, height - padding - labelPadding, padding + labelPadding, padding); - g.drawLine(padding + labelPadding, height - padding - labelPadding, width - padding, height - padding - labelPadding); - - g.setColor(Color.BLACK); - final int labelWidth = fontMetrics.stringWidth(xLabel); - final int labelX = ((padding + labelPadding) + (width - padding)) / 2; - final int labelY = height - padding - labelPadding; - g.drawString(xLabel, labelX - labelWidth / 2, labelY + fontHeight + 3); - - final Stroke oldStroke = g.getStroke(); - g.setColor(lineColor); - g.setStroke(graphStroke); - - final double xScale = ((double) width - (2 * padding) - labelPadding) / (length - 1); - final double yScale = ((double) height - 2 * padding - labelPadding) / scoreRange; - - final List graphPoints = new ArrayList<>(length); - for (int i = 0; i < length; i++) { - final int x1 = (int) (i * xScale + padding + labelPadding); - final int y1 = (int) ((maxScore - values.get(i)) * yScale + padding); - graphPoints.add(new Point(x1, y1)); - } - - for (int i = 0; i < graphPoints.size() - 1; i++) { - final int x1 = graphPoints.get(i).x; - final int y1 = graphPoints.get(i).y; - final int x2 = graphPoints.get(i + 1).x; - final int y2 = graphPoints.get(i + 1).y; - g.drawLine(x1, y1, x2, y2); - } - - boolean drawDots = width > (length * pointWidth); - if (drawDots) { - g.setStroke(oldStroke); - g.setColor(pointColor); - for (Point graphPoint : graphPoints) { - final int x = graphPoint.x - pointWidth / 2; - final int y = graphPoint.y - pointWidth / 2; - g.fillOval(x, y, pointWidth, pointWidth); - } - } - } - - private int getMinScore() { - return 0; - } - - private int getMaxScore() { - return 100; - } -} diff --git a/bootstrap/standalone/src/main/resources/icon.png b/bootstrap/standalone/src/main/resources/icon.png deleted file mode 100644 index 4e6a38a7..00000000 Binary files a/bootstrap/standalone/src/main/resources/icon.png and /dev/null differ diff --git a/bootstrap/standalone/src/main/resources/log4j2.xml b/bootstrap/standalone/src/main/resources/log4j2.xml index 238a27da..95741540 100644 --- a/bootstrap/standalone/src/main/resources/log4j2.xml +++ b/bootstrap/standalone/src/main/resources/log4j2.xml @@ -1,12 +1,9 @@ - + - - - @@ -17,7 +14,6 @@ - diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 5c0824de..fb06767e 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,21 +6,21 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT + ../ bootstrap-velocity - org.geysermc connector - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT compile com.velocitypowered velocity-api - 1.1.0 + 1.0.0-SNAPSHOT provided @@ -57,34 +57,10 @@ - - com.fasterxml.jackson - org.geysermc.platform.velocity.shaded.jackson - it.unimi.dsi.fastutil org.geysermc.platform.velocity.shaded.fastutil - - org.reflections - org.geysermc.platform.velocity.shaded.reflections - - - com.google.common - org.geysermc.platform.velocity.shaded.google.common - - - com.google.guava - org.geysermc.platform.velocity.shaded.google.guava - - - org.dom4j - org.geysermc.platform.velocity.shaded.dom4j - - - net.kyori - org.geysermc.platform.velocity.shaded.kyori - @@ -93,16 +69,7 @@ com.google.code.gson:* - - io.netty:netty-transport-native-epoll:* - io.netty:netty-transport-native-unix-common:* - io.netty:netty-transport-native-kqueue:* - io.netty:netty-handler:* - io.netty:netty-common:* - io.netty:netty-buffer:* - io.netty:netty-resolver:* - io.netty:netty-transport:* - io.netty:netty-codec:* + io.netty:* org.slf4j:* org.ow2.asm:* diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java index 53b87370..aef0edaa 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,26 +25,127 @@ package org.geysermc.platform.velocity; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import com.velocitypowered.api.plugin.PluginContainer; import com.velocitypowered.api.proxy.ProxyServer; import lombok.Getter; +import lombok.Setter; import org.geysermc.connector.FloodgateKeyLoader; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; +import org.geysermc.connector.GeyserConfiguration; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Map; +import java.util.Optional; -@Getter @JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserVelocityConfiguration extends GeyserJacksonConfiguration { - @JsonIgnore - private Path floodgateKeyPath; +@Getter +public class GeyserVelocityConfiguration implements GeyserConfiguration { + + private BedrockConfiguration bedrock; + private RemoteConfiguration remote; + + @JsonProperty("floodgate-key-file") + private String floodgateKeyFile; + + private Map userAuths; + + @JsonProperty("command-suggestions") + private boolean commandSuggestions; + + @JsonProperty("passthrough-motd") + private boolean isPassthroughMotd; + + @JsonProperty("passthrough-player-counts") + private boolean isPassthroughPlayerCounts; + + @JsonProperty("legacy-ping-passthrough") + private boolean isLegacyPingPassthrough; + + @JsonProperty("ping-passthrough-interval") + private int pingPassthroughInterval; + + @JsonProperty("max-players") + private int maxPlayers; + + @JsonProperty("debug-mode") + private boolean debugMode; + + @JsonProperty("general-thread-pool") + private int generalThreadPool; + + @JsonProperty("allow-third-party-capes") + private boolean allowThirdPartyCapes; + + @JsonProperty("allow-third-party-ears") + private boolean allowThirdPartyEars; + + @JsonProperty("default-locale") + private String defaultLocale; + + @JsonProperty("cache-chunks") + private boolean cacheChunks; + + @JsonProperty("above-bedrock-nether-building") + private boolean aboveBedrockNetherBuilding; + + private MetricsInfo metrics; + + private Path floodgateKey; public void loadFloodgate(GeyserVelocityPlugin plugin, ProxyServer proxyServer, File dataFolder) { - PluginContainer floodgate = proxyServer.getPluginManager().getPlugin("floodgate").orElse(null); - floodgateKeyPath = FloodgateKeyLoader.getKeyPath(this, floodgate, Paths.get("plugins/floodgate/"), dataFolder.toPath(), plugin.getGeyserLogger()); + Optional floodgate = proxyServer.getPluginManager().getPlugin("floodgate"); + floodgate.ifPresent(it -> floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(dataFolder.toString(), floodgateKeyFile.isEmpty() ? floodgateKeyFile : "public-key.pem"), it, Paths.get("plugins/floodgate/"))); } + + @Override + public Path getFloodgateKeyFile() { + return floodgateKey; + } + + @Getter + public static class BedrockConfiguration implements IBedrockConfiguration { + + private String address; + private int port; + + private String motd1; + private String motd2; + } + + @Getter + public static class RemoteConfiguration implements IRemoteConfiguration { + + @Setter + private String address; + + @Setter + private int port; + + private String motd1; + private String motd2; + + @JsonProperty("auth-type") + private String authType; + } + + @Getter + public static class UserAuthenticationInfo implements IUserAuthenticationInfo { + private String email; + private String password; + } + + @Getter + public static class MetricsInfo implements IMetricsInfo { + + private boolean enabled; + + @JsonProperty("uuid") + private String uniqueId; + } + + @JsonProperty("config-version") + private int configVersion; } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityDumpInfo.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityDumpInfo.java deleted file mode 100644 index 261e8fef..00000000 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityDumpInfo.java +++ /dev/null @@ -1,67 +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.platform.velocity; - -import com.velocitypowered.api.plugin.PluginContainer; -import com.velocitypowered.api.proxy.ProxyServer; -import lombok.Getter; -import org.geysermc.connector.common.serializer.AsteriskSerializer; -import org.geysermc.connector.dump.BootstrapDumpInfo; - -import java.util.ArrayList; -import java.util.List; - -@Getter -public class GeyserVelocityDumpInfo extends BootstrapDumpInfo { - - private String platformName; - private String platformVersion; - private String platformVendor; - private boolean onlineMode; - private String serverIP; - private int serverPort; - private List plugins; - - GeyserVelocityDumpInfo(ProxyServer proxy) { - super(); - this.platformName = proxy.getVersion().getName(); - this.platformVersion = proxy.getVersion().getVersion(); - this.platformVendor = proxy.getVersion().getVendor(); - this.onlineMode = proxy.getConfiguration().isOnlineMode(); - if (AsteriskSerializer.showSensitive || (proxy.getBoundAddress().getHostString().equals("") || proxy.getBoundAddress().getHostString().equals("0.0.0.0"))) { - this.serverIP = proxy.getBoundAddress().getHostString(); - } else { - this.serverIP = "***"; - } - this.serverPort = proxy.getBoundAddress().getPort(); - this.plugins = new ArrayList<>(); - - for (PluginContainer plugin : proxy.getPluginManager().getPlugins()) { - String pluginClass = plugin.getInstance().map((pl) -> pl.getClass().getName()).orElse("unknown"); - this.plugins.add(new PluginInfo(true, plugin.getDescription().getName().get(), plugin.getDescription().getVersion().get(), pluginClass, plugin.getDescription().getAuthors())); - } - } -} diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityLogger.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityLogger.java index 729af50a..a935d786 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityLogger.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,15 @@ package org.geysermc.platform.velocity; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; + import org.geysermc.connector.GeyserLogger; import org.slf4j.Logger; @AllArgsConstructor public class GeyserVelocityLogger implements GeyserLogger { - private final Logger logger; - @Getter @Setter - private boolean debug; + + private Logger logger; + private boolean debugMode; @Override public void severe(String message) { @@ -69,8 +68,12 @@ public class GeyserVelocityLogger implements GeyserLogger { @Override public void debug(String message) { - if (debug) { + if (debugMode) info(message); - } + } + + @Override + public void setDebug(boolean debugMode) { + this.debugMode = debugMode; } } \ No newline at end of file diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityMain.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityMain.java index 6b337ebb..73eaddf0 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityMain.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityMain.java @@ -1,31 +1,32 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.velocity; -import org.geysermc.connector.common.main.IGeyserMain; +import org.geysermc.common.main.IGeyserMain; public class GeyserVelocityMain extends IGeyserMain { diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java index bab0e350..01be949b 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.platform.velocity; @@ -31,8 +32,9 @@ import com.velocitypowered.api.proxy.InboundConnection; import com.velocitypowered.api.proxy.ProxyServer; import com.velocitypowered.api.proxy.server.ServerPing; import lombok.AllArgsConstructor; +import net.kyori.text.TextComponent; import net.kyori.text.serializer.legacy.LegacyComponentSerializer; -import org.geysermc.connector.common.ping.GeyserPingInfo; +import org.geysermc.common.ping.GeyserPingInfo; import org.geysermc.connector.ping.IGeyserPingPassthrough; import java.net.Inet4Address; @@ -43,44 +45,38 @@ import java.util.concurrent.ExecutionException; @AllArgsConstructor public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { + private static final GeyserInboundConnection FAKE_INBOUND_CONNECTION = new GeyserInboundConnection(); + private final ProxyServer server; @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + public GeyserPingInfo getPingInformation() { ProxyPingEvent event; try { - event = server.getEventManager().fire(new ProxyPingEvent(new GeyserInboundConnection(inetSocketAddress), ServerPing.builder() + event = server.getEventManager().fire(new ProxyPingEvent(FAKE_INBOUND_CONNECTION, ServerPing.builder() .description(server.getConfiguration().getMotdComponent()).onlinePlayers(server.getPlayerCount()) .maximumPlayers(server.getConfiguration().getShowMaxPlayers()).build())).get(); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } GeyserPingInfo geyserPingInfo = new GeyserPingInfo( - LegacyComponentSerializer.legacy().serialize(event.getPing().getDescription(), '§'), - new GeyserPingInfo.Players( - event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax(), - event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline() - ), - new GeyserPingInfo.Version( - event.getPing().getVersion().getName(), - event.getPing().getVersion().getProtocol() - ) + LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'), + event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(), + event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax() ); - event.getPing().getPlayers().get().getSample().stream().map(ServerPing.SamplePlayer::getName).forEach(geyserPingInfo.getPlayerList()::add); + event.getPing().getPlayers().get().getSample().forEach(player -> { + geyserPingInfo.addPlayer(player.getName()); + }); return geyserPingInfo; } private static class GeyserInboundConnection implements InboundConnection { - private final InetSocketAddress remote; - - public GeyserInboundConnection(InetSocketAddress remote) { - this.remote = remote; - } + private static final InetSocketAddress FAKE_REMOTE = new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69); @Override public InetSocketAddress getRemoteAddress() { - return this.remote; + return FAKE_REMOTE; } @Override diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java index bcb388ca..e7b44da5 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,21 @@ package org.geysermc.platform.velocity; import com.google.inject.Inject; + import com.velocitypowered.api.command.CommandManager; import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyShutdownEvent; import com.velocitypowered.api.plugin.Plugin; + import com.velocitypowered.api.proxy.ProxyServer; -import lombok.Getter; import org.geysermc.common.PlatformType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; import org.geysermc.connector.ping.IGeyserPingPassthrough; import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import org.geysermc.platform.velocity.command.GeyserVelocityCommandExecutor; import org.geysermc.platform.velocity.command.GeyserVelocityCommandManager; import org.slf4j.Logger; @@ -49,8 +48,6 @@ import org.slf4j.Logger; import java.io.File; import java.io.IOException; import java.net.InetSocketAddress; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.UUID; @Plugin(id = "geyser", name = GeyserConnector.NAME + "-Velocity", version = GeyserConnector.VERSION, url = "https://geysermc.org", authors = "GeyserMC") @@ -72,56 +69,39 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { private GeyserConnector connector; - @Getter - private final Path configFolder = Paths.get("plugins/" + GeyserConnector.NAME + "-Velocity/"); - @Override public void onEnable() { + File configDir = new File("plugins/" + GeyserConnector.NAME + "-Velocity/"); + try { - if (!configFolder.toFile().exists()) - //noinspection ResultOfMethodCallIgnored - configFolder.toFile().mkdirs(); - File configFile = FileUtils.fileOrCopiedFromResource(configFolder.resolve("config.yml").toFile(), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); + if (!configDir.exists()) + configDir.mkdir(); + File configFile = FileUtils.fileOrCopiedFromResource(new File(configDir, "config.yml"), "config.yml", (x) -> x.replaceAll("generateduuid", UUID.randomUUID().toString())); this.geyserConfig = FileUtils.loadConfig(configFile, GeyserVelocityConfiguration.class); } catch (IOException ex) { - logger.warn(LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); + logger.warn("Failed to read/create config.yml! Make sure it's up to date and/or readable+writable!", ex); ex.printStackTrace(); } InetSocketAddress javaAddr = proxyServer.getBoundAddress(); - // By default this should be localhost but may need to be changed in some circumstances - if (this.geyserConfig.getRemote().getAddress().equalsIgnoreCase("auto")) { - this.geyserConfig.setAutoconfiguredRemote(true); - // Don't use localhost if not listening on all interfaces - if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { - this.geyserConfig.getRemote().setAddress(javaAddr.getHostString()); - } - geyserConfig.getRemote().setPort(javaAddr.getPort()); + // Don't change the ip if its listening on all interfaces + // By default this should be 127.0.0.1 but may need to be changed in some circumstances + if (!javaAddr.getHostString().equals("0.0.0.0") && !javaAddr.getHostString().equals("")) { + geyserConfig.getRemote().setAddress(javaAddr.getHostString()); } - if (geyserConfig.getBedrock().isCloneRemotePort()) { - geyserConfig.getBedrock().setPort(javaAddr.getPort()); - } + geyserConfig.getRemote().setPort(javaAddr.getPort()); this.geyserLogger = new GeyserVelocityLogger(logger, geyserConfig.isDebugMode()); GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); - if (geyserConfig.getRemote().getAuthType().equals("floodgate") && !proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) { - geyserLogger.severe(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed") + " " + LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.disabling")); - return; - } else if (geyserConfig.isAutoconfiguredRemote() && proxyServer.getPluginManager().getPlugin("floodgate").isPresent()) { - // Floodgate installed means that the user wants Floodgate authentication - geyserLogger.debug("Auto-setting to Floodgate authentication."); - geyserConfig.getRemote().setAuthType("floodgate"); - } - - geyserConfig.loadFloodgate(this, proxyServer, configFolder.toFile()); + geyserConfig.loadFloodgate(this, proxyServer, configDir); this.connector = GeyserConnector.start(PlatformType.VELOCITY, this); this.geyserCommandManager = new GeyserVelocityCommandManager(connector); - this.commandManager.register("geyser", new GeyserVelocityCommandExecutor(connector)); + this.commandManager.register(new GeyserVelocityCommandExecutor(connector), "geyser"); if (geyserConfig.isLegacyPingPassthrough()) { this.geyserPingPassthrough = GeyserLegacyPingPassthrough.init(connector); } else { @@ -163,9 +143,4 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { public void onShutdown(ProxyShutdownEvent event) { onDisable(); } - - @Override - public BootstrapDumpInfo getDumpInfo() { - return new GeyserVelocityDumpInfo(proxyServer); - } } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandExecutor.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandExecutor.java index 4aab73e5..940c5224 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandExecutor.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,48 +25,37 @@ package org.geysermc.platform.velocity.command; +import com.velocitypowered.api.command.Command; import com.velocitypowered.api.command.CommandSource; -import com.velocitypowered.api.command.SimpleCommand; -import lombok.AllArgsConstructor; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.utils.LanguageUtils; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import lombok.AllArgsConstructor; + +import net.kyori.text.TextComponent; + +import org.geysermc.common.ChatColor; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.GeyserCommand; @AllArgsConstructor -public class GeyserVelocityCommandExecutor implements SimpleCommand { +public class GeyserVelocityCommandExecutor implements Command { - private final GeyserConnector connector; + private GeyserConnector connector; @Override - public void execute(Invocation invocation) { - if (invocation.arguments().length > 0) { - if (getCommand(invocation.arguments()[0]) != null) { - if (!invocation.source().hasPermission(getCommand(invocation.arguments()[0]).getPermission())) { - CommandSender sender = new VelocityCommandSender(invocation.source()); - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", sender.getLocale())); + public void execute(CommandSource source, String[] args) { + if (args.length > 0) { + if (getCommand(args[0]) != null) { + if (!source.hasPermission(getCommand(args[0]).getPermission())) { + source.sendMessage(TextComponent.of(ChatColor.RED + "You do not have permission to execute this command!")); return; } - getCommand(invocation.arguments()[0]).execute(new VelocityCommandSender(invocation.source()), invocation.arguments().length > 1 ? Arrays.copyOfRange(invocation.arguments(), 1, invocation.arguments().length) : new String[0]); + getCommand(args[0]).execute(new VelocityCommandSender(source), args); } } else { - getCommand("help").execute(new VelocityCommandSender(invocation.source()), new String[0]); + getCommand("help").execute(new VelocityCommandSender(source), args); } } - @Override - public List suggest(Invocation invocation) { - if (invocation.arguments().length == 0) { - return connector.getCommandManager().getCommandNames(); - } - return new ArrayList<>(); - } - private GeyserCommand getCommand(String label) { return connector.getCommandManager().getCommands().get(label); } diff --git a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandManager.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandManager.java index cbf8e3df..76655d0a 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandManager.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/GeyserVelocityCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/platform/velocity/command/VelocityCommandSender.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/VelocityCommandSender.java index 8f7d98b8..1b0d6f3e 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/VelocityCommandSender.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/command/VelocityCommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,21 +28,17 @@ package org.geysermc.platform.velocity.command; import com.velocitypowered.api.command.CommandSource; import com.velocitypowered.api.proxy.ConsoleCommandSource; import com.velocitypowered.api.proxy.Player; + +import lombok.AllArgsConstructor; + import net.kyori.text.TextComponent; + import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.utils.LanguageUtils; - -import java.util.Locale; +@AllArgsConstructor public class VelocityCommandSender implements CommandSender { - private final CommandSource handle; - - public VelocityCommandSender(CommandSource handle) { - this.handle = handle; - // Ensure even Java players' languages are loaded - LanguageUtils.loadGeyserLocale(getLocale()); - } + private CommandSource handle; @Override public String getName() { @@ -63,13 +59,4 @@ public class VelocityCommandSender implements CommandSender { public boolean isConsole() { return handle instanceof ConsoleCommandSource; } - - @Override - public String getLocale() { - if (handle instanceof Player) { - Locale locale = ((Player) handle).getPlayerSettings().getLocale(); - return LanguageUtils.formatLocale(locale.getLanguage() + "_" + locale.getCountry()); - } - return LanguageUtils.getDefaultLocale(); - } } diff --git a/common/pom.xml b/common/pom.xml index 32c4b187..0a47fbca 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,10 +6,11 @@ org.geysermc geyser-parent - 1.2.0-SNAPSHOT + parent + ../ common - + 1.0-SNAPSHOT com.google.code.gson diff --git a/common/src/main/java/org/geysermc/common/AuthType.java b/common/src/main/java/org/geysermc/common/AuthType.java new file mode 100644 index 00000000..8edbc4d5 --- /dev/null +++ b/common/src/main/java/org/geysermc/common/AuthType.java @@ -0,0 +1,33 @@ +package org.geysermc.common; + +import lombok.Getter; + +@Getter +public enum AuthType { + OFFLINE, + ONLINE, + FLOODGATE; + + public static final AuthType[] VALUES = values(); + + public static AuthType getById(int id) { + return id < VALUES.length ? VALUES[id] : OFFLINE; + } + + /** + * Convert the AuthType string (from config) to the enum, OFFLINE on fail + * + * @param name AuthType string + * + * @return The converted AuthType + */ + public static AuthType getByName(String name) { + String upperCase = name.toUpperCase(); + for (AuthType type : VALUES) { + if (type.name().equals(upperCase)) { + return type; + } + } + return OFFLINE; + } +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/common/ChatColor.java b/common/src/main/java/org/geysermc/common/ChatColor.java similarity index 97% rename from connector/src/main/java/org/geysermc/connector/common/ChatColor.java rename to common/src/main/java/org/geysermc/common/ChatColor.java index 946be39c..8868b063 100644 --- a/connector/src/main/java/org/geysermc/connector/common/ChatColor.java +++ b/common/src/main/java/org/geysermc/common/ChatColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.common; +package org.geysermc.common; public class ChatColor { diff --git a/common/src/main/java/org/geysermc/common/PlatformType.java b/common/src/main/java/org/geysermc/common/PlatformType.java index a1096f34..fa6f57fd 100644 --- a/common/src/main/java/org/geysermc/common/PlatformType.java +++ b/common/src/main/java/org/geysermc/common/PlatformType.java @@ -1,28 +1,3 @@ -/* - * 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.common; import lombok.AllArgsConstructor; @@ -32,13 +7,11 @@ import lombok.Getter; @AllArgsConstructor public enum PlatformType { - ANDROID("Android"), + BUKKIT("Bukkit"), BUNGEECORD("BungeeCord"), - FABRIC("Fabric"), - SPIGOT("Spigot"), SPONGE("Sponge"), STANDALONE("Standalone"), VELOCITY("Velocity"); - private final String platformName; + private String platformName; } diff --git a/common/src/main/java/org/geysermc/common/main/IGeyserMain.java b/common/src/main/java/org/geysermc/common/main/IGeyserMain.java new file mode 100644 index 00000000..75da4e6b --- /dev/null +++ b/common/src/main/java/org/geysermc/common/main/IGeyserMain.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.common.main; + +import javax.swing.*; +import java.io.InputStream; +import java.util.Scanner; + +public class IGeyserMain { + + public void displayMessage() { + String message = createMessage(); + + if (System.console() == null) { + JOptionPane.showMessageDialog(null, message, "GeyserMC Plugin: " + this.getPluginType(), JOptionPane.ERROR_MESSAGE); + } + + printMessage(message); + } + + private String createMessage() { + String message = ""; + + InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("help.txt"); + Scanner help = new Scanner(helpStream).useDelimiter("\\Z"); + String line = ""; + while (help.hasNext()) { + line = help.next(); + + line = line.replace("${plugin_type}", this.getPluginType()); + line = line.replace("${plugin_folder}", this.getPluginFolder()); + + message += line + "\n"; + } + + return message; + } + + private void printMessage(String message) { + System.out.print(message); + } + + public String getPluginType() { + return "unknown"; + } + + public String getPluginFolder() { + return "unknown"; + } +} diff --git a/common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java b/common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java new file mode 100644 index 00000000..40ef6da6 --- /dev/null +++ b/common/src/main/java/org/geysermc/common/ping/GeyserPingInfo.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.common.ping; + +import lombok.Data; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.Collection; + +@Data +public class GeyserPingInfo { + + public final String motd; + public final int currentPlayerCount; + public final int maxPlayerCount; + + @Getter + private Collection players = new ArrayList<>(); + + public void addPlayer(String username) { + players.add(username); + } +} diff --git a/common/src/main/java/org/geysermc/common/window/CustomFormBuilder.java b/common/src/main/java/org/geysermc/common/window/CustomFormBuilder.java index f4e597f0..004b00a9 100644 --- a/common/src/main/java/org/geysermc/common/window/CustomFormBuilder.java +++ b/common/src/main/java/org/geysermc/common/window/CustomFormBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/CustomFormWindow.java b/common/src/main/java/org/geysermc/common/window/CustomFormWindow.java index 7043dda9..efc71ae8 100644 --- a/common/src/main/java/org/geysermc/common/window/CustomFormWindow.java +++ b/common/src/main/java/org/geysermc/common/window/CustomFormWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -92,7 +92,7 @@ public class CustomFormWindow extends FormWindow { } public void setResponse(String data) { - if (data == null || data.trim().equalsIgnoreCase("null") || data.isEmpty()) { + if (data == null || data.equalsIgnoreCase("null") || data.isEmpty()) { closed = true; return; } @@ -108,7 +108,7 @@ public class CustomFormWindow extends FormWindow { List componentResponses = new ArrayList<>(); try { - componentResponses = new ObjectMapper().readValue(data.trim(), new TypeReference>(){}); + componentResponses = new ObjectMapper().readValue(data, new TypeReference>(){}); } catch (IOException e) { } for (String response : componentResponses) { diff --git a/common/src/main/java/org/geysermc/common/window/FormWindow.java b/common/src/main/java/org/geysermc/common/window/FormWindow.java index efc06fe8..c3cc4258 100644 --- a/common/src/main/java/org/geysermc/common/window/FormWindow.java +++ b/common/src/main/java/org/geysermc/common/window/FormWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/ModalFormWindow.java b/common/src/main/java/org/geysermc/common/window/ModalFormWindow.java index 9d802161..bfeafa1b 100644 --- a/common/src/main/java/org/geysermc/common/window/ModalFormWindow.java +++ b/common/src/main/java/org/geysermc/common/window/ModalFormWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/SimpleFormWindow.java b/common/src/main/java/org/geysermc/common/window/SimpleFormWindow.java index 48bda0bd..7c1acc26 100644 --- a/common/src/main/java/org/geysermc/common/window/SimpleFormWindow.java +++ b/common/src/main/java/org/geysermc/common/window/SimpleFormWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -72,14 +72,14 @@ public class SimpleFormWindow extends FormWindow { } public void setResponse(String data) { - if (data == null || data.trim().equalsIgnoreCase("null")) { + if (data == null || data.equalsIgnoreCase("null")) { closed = true; return; } int buttonID; try { - buttonID = Integer.parseInt(data.trim()); + buttonID = Integer.parseInt(data); } catch (Exception ex) { return; } diff --git a/common/src/main/java/org/geysermc/common/window/button/FormButton.java b/common/src/main/java/org/geysermc/common/window/button/FormButton.java index d2075d3f..6daa2fea 100644 --- a/common/src/main/java/org/geysermc/common/window/button/FormButton.java +++ b/common/src/main/java/org/geysermc/common/window/button/FormButton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/button/FormImage.java b/common/src/main/java/org/geysermc/common/window/button/FormImage.java index 03427829..b700b046 100644 --- a/common/src/main/java/org/geysermc/common/window/button/FormImage.java +++ b/common/src/main/java/org/geysermc/common/window/button/FormImage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,14 +32,14 @@ public class FormImage { @Getter @Setter - private String type; + private FormImageType type; @Getter @Setter private String data; public FormImage(FormImageType type, String data) { - this.type = type.getName(); + this.type = type; this.data = data; } diff --git a/common/src/main/java/org/geysermc/common/window/component/DropdownComponent.java b/common/src/main/java/org/geysermc/common/window/component/DropdownComponent.java index 8ba17bb4..4dac6b04 100644 --- a/common/src/main/java/org/geysermc/common/window/component/DropdownComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/DropdownComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/component/FormComponent.java b/common/src/main/java/org/geysermc/common/window/component/FormComponent.java index 6b503eb4..5a56ae0c 100644 --- a/common/src/main/java/org/geysermc/common/window/component/FormComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/FormComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/component/InputComponent.java b/common/src/main/java/org/geysermc/common/window/component/InputComponent.java index 9dfc249a..fad6a0fe 100644 --- a/common/src/main/java/org/geysermc/common/window/component/InputComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/InputComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/component/LabelComponent.java b/common/src/main/java/org/geysermc/common/window/component/LabelComponent.java index 4608282f..a76b313f 100644 --- a/common/src/main/java/org/geysermc/common/window/component/LabelComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/LabelComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/component/SliderComponent.java b/common/src/main/java/org/geysermc/common/window/component/SliderComponent.java index 3e681664..a7a78362 100644 --- a/common/src/main/java/org/geysermc/common/window/component/SliderComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/SliderComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/component/StepSliderComponent.java b/common/src/main/java/org/geysermc/common/window/component/StepSliderComponent.java index 8e6748a9..8f128d1a 100644 --- a/common/src/main/java/org/geysermc/common/window/component/StepSliderComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/StepSliderComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/component/ToggleComponent.java b/common/src/main/java/org/geysermc/common/window/component/ToggleComponent.java index e79e7592..50a5c631 100644 --- a/common/src/main/java/org/geysermc/common/window/component/ToggleComponent.java +++ b/common/src/main/java/org/geysermc/common/window/component/ToggleComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,9 @@ package org.geysermc.common.window.component; -import lombok.Getter; -import lombok.Setter; - public class ToggleComponent extends FormComponent { - @Getter - @Setter private String text; - - @Getter - @Setter private boolean defaultValue; public ToggleComponent(String text) { diff --git a/common/src/main/java/org/geysermc/common/window/response/CustomFormResponse.java b/common/src/main/java/org/geysermc/common/window/response/CustomFormResponse.java index 252a0978..6cdd7097 100644 --- a/common/src/main/java/org/geysermc/common/window/response/CustomFormResponse.java +++ b/common/src/main/java/org/geysermc/common/window/response/CustomFormResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/response/FormResponse.java b/common/src/main/java/org/geysermc/common/window/response/FormResponse.java index 35023f16..2be64683 100644 --- a/common/src/main/java/org/geysermc/common/window/response/FormResponse.java +++ b/common/src/main/java/org/geysermc/common/window/response/FormResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/response/FormResponseData.java b/common/src/main/java/org/geysermc/common/window/response/FormResponseData.java index 013c4985..fd40be0f 100644 --- a/common/src/main/java/org/geysermc/common/window/response/FormResponseData.java +++ b/common/src/main/java/org/geysermc/common/window/response/FormResponseData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/response/ModalFormResponse.java b/common/src/main/java/org/geysermc/common/window/response/ModalFormResponse.java index 3338df4d..e1a14039 100644 --- a/common/src/main/java/org/geysermc/common/window/response/ModalFormResponse.java +++ b/common/src/main/java/org/geysermc/common/window/response/ModalFormResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/window/response/SimpleFormResponse.java b/common/src/main/java/org/geysermc/common/window/response/SimpleFormResponse.java index c24f72d0..e80d58e7 100644 --- a/common/src/main/java/org/geysermc/common/window/response/SimpleFormResponse.java +++ b/common/src/main/java/org/geysermc/common/window/response/SimpleFormResponse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/BedrockData.java b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java index 22c33f47..dc895a79 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java +++ b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java @@ -1,28 +1,3 @@ -/* - * 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.floodgate.util; import lombok.AllArgsConstructor; 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 1e0b22cf..93d3c121 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-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/EncryptionUtil.java b/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java index f4dd5d2e..881d01ba 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java +++ b/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java @@ -1,28 +1,3 @@ -/* - * 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.floodgate.util; import javax.crypto.*; diff --git a/common/src/main/resources/help.txt b/common/src/main/resources/help.txt new file mode 100644 index 00000000..3512ed83 --- /dev/null +++ b/common/src/main/resources/help.txt @@ -0,0 +1,18 @@ + +-------------------------------------------------------------------------------- + + Oops! You attempted to run a plugin version of Geyser directly! + + This jar file is a plugin for ${plugin_type}. You can run this file as a + plugin by dropping the jar file into the "${plugin_folder}" directory. + + There is also a standalone version available that doesn't need to + be installed as a plugin, you can find it on our build server: + + http://ci.geysermc.org/ + + If you need more help, you should check out our discord: + + http://discord.geysermc.org/ + +-------------------------------------------------------------------------------- \ No newline at end of file diff --git a/connector/pom.xml b/connector/pom.xml index a7001be0..91cf6f3d 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -6,15 +6,16 @@ org.geysermc geyser-parent - 1.2.0-SNAPSHOT + parent + ../ connector - + 1.0-SNAPSHOT org.geysermc common - 1.2.0-SNAPSHOT + 1.0-SNAPSHOT compile @@ -30,28 +31,17 @@ compile - com.github.CloudburstMC.Protocol - bedrock-v422 - d41b84e86c + com.nukkitx.protocol + bedrock-v390 + 2.5.6-SNAPSHOT compile net.sf.trove4j trove - - - com.nukkitx.network - raknet - - - com.nukkitx.network - raknet - 1.6.20 - compile - com.nukkitx.fastutil fastutil-int-int-maps @@ -76,12 +66,6 @@ 8.3.1 compile - - com.nukkitx.fastutil - fastutil-int-byte-maps - 8.3.1 - compile - com.nukkitx.fastutil fastutil-int-double-maps @@ -106,12 +90,6 @@ 8.3.1 compile - - com.nukkitx.fastutil - fastutil-object-object-maps - 8.3.1 - compile - com.google.guava guava @@ -121,30 +99,10 @@ com.github.steveice10 mcprotocollib - 26201a4 + 4c315aa206 compile - net.kyori - adventure-text-serializer-gson - - - com.github.steveice10 - packetlib - - - com.github.steveice10 - mcauthlib - - - - - com.github.steveice10 - PacketLib - 54f761c - compile - - io.netty netty-all @@ -156,57 +114,29 @@ 4.1.43.Final compile - - io.netty - netty-codec-haproxy - 4.1.56.Final - compile - org.reflections reflections - 0.9.11 - - - org.dom4j - dom4j - 2.1.3 + 0.9.12 net.kyori - adventure-api - 4.3.0 + text-api + 3.0.3 compile net.kyori - adventure-text-serializer-gson - 4.3.0 + text-serializer-gson + 3.0.3 compile net.kyori - adventure-text-serializer-legacy - 4.3.0 + text-serializer-legacy + 3.0.3 compile - - net.kyori - adventure-text-serializer-gson-legacy-impl - 4.3.0 - compile - - - junit - junit - 4.13.1 - test - - - com.github.GeyserMC - MCAuthLib - 0e48a094f2 - @@ -234,11 +164,6 @@ false git.user.* - git.*.user.* - git.closest.* - git.commit.id.describe - git.commit.id.describe-short - git.commit.message.short flat @@ -263,12 +188,8 @@ - String VERSION = ".*" - String VERSION = "${project.version} (" + GIT_VERSION + ")" - - - String GIT_VERSION = ".*" - String GIT_VERSION = "git-${git.branch}-${git.commit.id.abbrev}" + VERSION = ".*" + VERSION = "${project.version} (git-${git.branch}-${git.commit.id.abbrev})" @@ -286,75 +207,14 @@ - String VERSION = ".*" - String VERSION = "DEV" - - - String GIT_VERSION = ".*" - String GIT_VERSION = "DEV" + VERSION = ".*" + VERSION = "DEV" - - org.codehaus.gmavenplus - gmavenplus-plugin - 1.9.1 - - - process-classes - - execute - - - - - - - - - - - org.reflections - reflections - 0.9.11 - - - org.dom4j - dom4j - 2.1.3 - - - org.codehaus.groovy - groovy-all - 3.0.5 - runtime - pom - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.22.0 - - - -Dfile.encoding=${project.build.sourceEncoding} - - diff --git a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java index 77492fb7..0b631b2d 100644 --- a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java +++ b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java @@ -1,51 +1,47 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; -import org.geysermc.connector.utils.LanguageUtils; - import java.nio.file.Files; import java.nio.file.Path; public class FloodgateKeyLoader { - public static Path getKeyPath(GeyserJacksonConfiguration config, Object floodgate, Path floodgateDataFolder, Path geyserDataFolder, GeyserLogger logger) { - Path floodgateKey = geyserDataFolder.resolve(config.getFloodgateKeyFile()); - + public static Path getKey(GeyserLogger logger, GeyserConfiguration config, Path floodgateKey, Object floodgate, Path floodgateFolder) { if (!Files.exists(floodgateKey) && config.getRemote().getAuthType().equals("floodgate")) { if (floodgate != null) { - Path autoKey = floodgateDataFolder.resolve("public-key.pem"); + Path autoKey = floodgateFolder.resolve("public-key.pem"); if (Files.exists(autoKey)) { - logger.info(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.auto_loaded")); + logger.info("Auto-loaded floodgate key"); floodgateKey = autoKey; } else { - logger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.missing_key")); + logger.error("Auth-type set to floodgate and the public key is missing!"); } } else { - logger.error(LanguageUtils.getLocaleStringLog("geyser.bootstrap.floodgate.not_installed")); + logger.error("Auth-type set to floodgate but floodgate is not installed!"); } } diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java new file mode 100644 index 00000000..8a39323b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/GeyserConfiguration.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector; + +import java.nio.file.Path; +import java.util.Map; + +public interface GeyserConfiguration { + + // Modify this when you update the config + int CURRENT_CONFIG_VERSION = 3; + + IBedrockConfiguration getBedrock(); + + IRemoteConfiguration getRemote(); + + Map getUserAuths(); + + boolean isCommandSuggestions(); + + boolean isPassthroughMotd(); + + boolean isPassthroughPlayerCounts(); + + boolean isLegacyPingPassthrough(); + + int getPingPassthroughInterval(); + + int getMaxPlayers(); + + boolean isDebugMode(); + + int getGeneralThreadPool(); + + boolean isAllowThirdPartyCapes(); + + boolean isAllowThirdPartyEars(); + + String getDefaultLocale(); + + Path getFloodgateKeyFile(); + + boolean isAboveBedrockNetherBuilding(); + + boolean isCacheChunks(); + + IMetricsInfo getMetrics(); + + interface IBedrockConfiguration { + + String getAddress(); + + int getPort(); + + String getMotd1(); + + String getMotd2(); + } + + interface IRemoteConfiguration { + + String getAddress(); + + int getPort(); + + String getAuthType(); + } + + interface IUserAuthenticationInfo { + String getEmail(); + + String getPassword(); + } + + interface IMetricsInfo { + + boolean isEnabled(); + + String getUniqueId(); + } + + int getConfigVersion(); + + static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) { + if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) { + geyserLogger.warning("Your Geyser config is out of date! Please regenerate your config when possible."); + } else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) { + geyserLogger.warning("Your Geyser config is too new! Errors may occur."); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index d61500e0..02e0c500 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,16 @@ package org.geysermc.connector; -import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; -import com.nukkitx.network.raknet.RakNetConstants; +import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.BedrockServer; +import com.nukkitx.protocol.bedrock.v390.Bedrock_v390; import lombok.Getter; -import lombok.Setter; +import org.geysermc.common.AuthType; import org.geysermc.common.PlatformType; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.network.ConnectorServerEventHandler; import org.geysermc.connector.network.remote.RemoteServer; @@ -44,30 +42,22 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; -import org.geysermc.connector.network.translators.collision.CollisionTranslator; -import org.geysermc.connector.network.translators.effect.EffectRegistry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.item.PotionMixRegistry; -import org.geysermc.connector.network.translators.item.RecipeRegistry; import org.geysermc.connector.network.translators.sound.SoundHandlerRegistry; -import org.geysermc.connector.network.translators.sound.SoundRegistry; import org.geysermc.connector.network.translators.world.WorldManager; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.effect.EffectRegistry; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; -import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator; import org.geysermc.connector.utils.DimensionUtils; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.utils.DockerCheck; import org.geysermc.connector.utils.LocaleUtils; -import org.geysermc.connector.utils.ResourcePack; +import org.geysermc.connector.network.translators.sound.SoundRegistry; -import javax.naming.directory.Attribute; -import javax.naming.directory.InitialDirContext; -import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.UnknownHostException; import java.text.DecimalFormat; -import java.util.*; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -76,29 +66,18 @@ import java.util.concurrent.TimeUnit; @Getter public class GeyserConnector { - public static final ObjectMapper JSON_MAPPER = new ObjectMapper() - .enable(JsonParser.Feature.IGNORE_UNDEFINED) - .enable(JsonParser.Feature.ALLOW_COMMENTS) - .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) - .enable(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES); + public static final ObjectMapper JSON_MAPPER = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES); + + public static final BedrockPacketCodec BEDROCK_PACKET_CODEC = Bedrock_v390.V390_CODEC; public static final String NAME = "Geyser"; - public static final String GIT_VERSION = "DEV"; // A fallback for running in IDEs public static final String VERSION = "DEV"; // A fallback for running in IDEs - /** - * Oauth client ID for Microsoft authentication - */ - public static final String OAUTH_CLIENT_ID = "204cefd1-4818-4de1-b98d-513fae875d88"; - - private static final String IP_REGEX = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"; - - private final List players = new ArrayList<>(); + private final Map players = new HashMap<>(); private static GeyserConnector instance; private RemoteServer remoteServer; - @Setter private AuthType authType; private boolean shuttingDown = false; @@ -106,8 +85,8 @@ public class GeyserConnector { private final ScheduledExecutorService generalThreadPool; private BedrockServer bedrockServer; - private final PlatformType platformType; - private final GeyserBootstrap bootstrap; + private PlatformType platformType; + private GeyserBootstrap bootstrap; private Metrics metrics; @@ -125,7 +104,7 @@ public class GeyserConnector { logger.info("******************************************"); logger.info(""); - logger.info(LanguageUtils.getLocaleStringLog("geyser.core.load", NAME, VERSION)); + logger.info("Loading " + NAME + " version " + VERSION); logger.info(""); logger.info("******************************************"); @@ -143,144 +122,52 @@ public class GeyserConnector { EntityIdentifierRegistry.init(); ItemRegistry.init(); ItemTranslator.init(); - CollisionTranslator.init(); LocaleUtils.init(); - PotionMixRegistry.init(); - RecipeRegistry.init(); SoundRegistry.init(); SoundHandlerRegistry.init(); - ResourcePack.loadPacks(); - - if (platformType != PlatformType.STANDALONE && config.getRemote().getAddress().equals("auto")) { - // Set the remote address to localhost since that is where we are always connecting - try { - config.getRemote().setAddress(InetAddress.getLocalHost().getHostAddress()); - } catch (UnknownHostException ex) { - logger.debug("Unknown host when trying to find localhost."); - if (config.isDebugMode()) { - ex.printStackTrace(); - } - } - } - String remoteAddress = config.getRemote().getAddress(); - int remotePort = config.getRemote().getPort(); - // Filters whether it is not an IP address or localhost, because otherwise it is not possible to find out an SRV entry. - if ((config.isLegacyPingPassthrough() || platformType == PlatformType.STANDALONE) && !remoteAddress.matches(IP_REGEX) && !remoteAddress.equalsIgnoreCase("localhost")) { - try { - // Searches for a server address and a port from a SRV record of the specified host name - InitialDirContext ctx = new InitialDirContext(); - Attribute attr = ctx.getAttributes("dns:///_minecraft._tcp." + remoteAddress, new String[]{"SRV"}).get("SRV"); - // size > 0 = SRV entry found - if (attr != null && attr.size() > 0) { - String[] record = ((String) attr.get(0)).split(" "); - // Overwrites the existing address and port with that from the SRV record. - config.getRemote().setAddress(remoteAddress = record[3]); - config.getRemote().setPort(remotePort = Integer.parseInt(record[2])); - logger.debug("Found SRV record \"" + remoteAddress + ":" + remotePort + "\""); - } - } catch (Exception | NoClassDefFoundError ex) { // Check for a NoClassDefFoundError to prevent Android crashes - logger.debug("Exception while trying to find an SRV record for the remote host."); - if (config.isDebugMode()) - ex.printStackTrace(); // Otherwise we can get a stack trace for any domain that doesn't have an SRV record - } + if (platformType != PlatformType.STANDALONE) { + DockerCheck.check(bootstrap); } - remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort); + remoteServer = new RemoteServer(config.getRemote().getAddress(), config.getRemote().getPort()); authType = AuthType.getByName(config.getRemote().getAuthType()); - DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether - SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS = config.isAllowCustomSkulls(); - - // https://github.com/GeyserMC/Geyser/issues/957 - RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu(); - logger.debug("Setting MTU to " + config.getMtu()); + if (config.isAboveBedrockNetherBuilding()) + DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether bedrockServer = new BedrockServer(new InetSocketAddress(config.getBedrock().getAddress(), config.getBedrock().getPort())); bedrockServer.setHandler(new ConnectorServerEventHandler(this)); bedrockServer.bind().whenComplete((avoid, throwable) -> { if (throwable == null) { - logger.info(LanguageUtils.getLocaleStringLog("geyser.core.start", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); + logger.info("Started Geyser on " + config.getBedrock().getAddress() + ":" + config.getBedrock().getPort()); } else { - logger.severe(LanguageUtils.getLocaleStringLog("geyser.core.fail", config.getBedrock().getAddress(), String.valueOf(config.getBedrock().getPort()))); + logger.severe("Failed to start Geyser on " + config.getBedrock().getAddress() + ":" + config.getBedrock().getPort()); throwable.printStackTrace(); } }).join(); if (config.getMetrics().isEnabled()) { metrics = new Metrics(this, "GeyserMC", config.getMetrics().getUniqueId(), false, java.util.logging.Logger.getLogger("")); + metrics.addCustomChart(new Metrics.SingleLineChart("servers", () -> 1)); metrics.addCustomChart(new Metrics.SingleLineChart("players", players::size)); - // Prevent unwanted words best we can - metrics.addCustomChart(new Metrics.SimplePie("authMode", () -> AuthType.getByName(config.getRemote().getAuthType()).toString().toLowerCase())); + metrics.addCustomChart(new Metrics.SimplePie("authMode", authType.name()::toLowerCase)); metrics.addCustomChart(new Metrics.SimplePie("platform", platformType::getPlatformName)); - metrics.addCustomChart(new Metrics.SimplePie("defaultLocale", LanguageUtils::getDefaultLocale)); - metrics.addCustomChart(new Metrics.SimplePie("version", () -> GeyserConnector.VERSION)); - metrics.addCustomChart(new Metrics.AdvancedPie("playerPlatform", () -> { - Map valueMap = new HashMap<>(); - for (GeyserSession session : players) { - if (session == null) continue; - if (session.getClientData() == null) continue; - String os = session.getClientData().getDeviceOS().toString(); - if (!valueMap.containsKey(os)) { - valueMap.put(os, 1); - } else { - valueMap.put(os, valueMap.get(os) + 1); - } - } - return valueMap; - })); - metrics.addCustomChart(new Metrics.AdvancedPie("playerVersion", () -> { - Map valueMap = new HashMap<>(); - for (GeyserSession session : players) { - if (session == null) continue; - if (session.getClientData() == null) continue; - String version = session.getClientData().getGameVersion(); - if (!valueMap.containsKey(version)) { - valueMap.put(version, 1); - } else { - valueMap.put(version, valueMap.get(version) + 1); - } - } - return valueMap; - })); - } - - 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.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 = LanguageUtils.getLocaleStringLog("geyser.core.finish.done", new DecimalFormat("#.###").format(completeTime)) + " "; - if (isGui) { - message += LanguageUtils.getLocaleStringLog("geyser.core.finish.gui"); - } else { - message += LanguageUtils.getLocaleStringLog("geyser.core.finish.console"); - } - logger.info(message); - - if (platformType == PlatformType.STANDALONE) { - logger.warning(LanguageUtils.getLocaleStringLog("geyser.core.movement_warn")); - } + logger.info(String.format("Done (%ss)! Run /geyser help for help!", new DecimalFormat("#.###").format(completeTime))); } public void shutdown() { - bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown")); + bootstrap.getGeyserLogger().info("Shutting down Geyser."); shuttingDown = true; if (players.size() >= 1) { - bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.log", players.size())); + bootstrap.getGeyserLogger().info("Kicking " + players.size() + " player(s)"); - // Make a copy to prevent ConcurrentModificationException - final List tmpPlayers = new ArrayList<>(players); - for (GeyserSession playerSession : tmpPlayers) { - playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getLocale())); + for (GeyserSession playerSession : players.values()) { + playerSession.disconnect("Geyser Proxy shutting down."); } CompletableFuture future = CompletableFuture.runAsync(new Runnable() { @@ -304,7 +191,7 @@ public class GeyserConnector { // Block and wait for the future to complete try { future.get(); - bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.kick.done")); + bootstrap.getGeyserLogger().info("Kicked all players"); } catch (Exception e) { // Quietly fail } @@ -317,47 +204,15 @@ public class GeyserConnector { authType = null; this.getCommandManager().getCommands().clear(); - bootstrap.getGeyserLogger().info(LanguageUtils.getLocaleStringLog("geyser.core.shutdown.done")); + bootstrap.getGeyserLogger().info("Geyser shutdown successfully."); } public void addPlayer(GeyserSession player) { - players.add(player); + players.put(player.getSocketAddress(), player); } public void removePlayer(GeyserSession player) { - players.remove(player); - } - - /** - * Gets a player by their current UUID - * - * @param uuid the uuid - * @return the player or null if there is no player online with this UUID - */ - public GeyserSession getPlayerByUuid(UUID uuid) { - for (GeyserSession session : players) { - if (session.getPlayerEntity().getUuid().equals(uuid)) { - return session; - } - } - - return null; - } - - /** - * Gets a player by their Xbox user identifier - * - * @param xuid the Xbox user identifier - * @return the player or null if there is no player online with this xuid - */ - public GeyserSession getPlayerByXuid(String xuid) { - for (GeyserSession session : players) { - if (session.getAuthData() != null && session.getAuthData().getXboxUUID().equals(xuid)) { - return session; - } - } - - return null; + players.remove(player.getSocketAddress()); } public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) { @@ -385,19 +240,6 @@ public class GeyserConnector { return bootstrap.getWorldManager(); } - /** - * Whether to use XML reflections in the jar or manually find the reflections. - * Will return true if the version number is not 'DEV' and the platform is not Fabric. - * On Fabric - it complains about being unable to create a default XMLReader. - * On other platforms this should only be true in compiled jars. - * - * @return whether to use XML reflections - */ - public boolean useXmlReflections() { - //noinspection ConstantConditions - return !this.getPlatformType().equals(PlatformType.FABRIC) && !"DEV".equals(GeyserConnector.VERSION); - } - public static GeyserConnector getInstance() { return instance; } diff --git a/connector/src/main/java/org/geysermc/connector/GeyserLogger.java b/connector/src/main/java/org/geysermc/connector/GeyserLogger.java index 6d36958d..4acab222 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserLogger.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserLogger.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector; @@ -36,9 +37,6 @@ public interface GeyserLogger { /** * Logs a severe message and an exception to console - * - * @param message the message to log - * @param error the error to throw */ void severe(String message, Throwable error); @@ -51,9 +49,6 @@ public interface GeyserLogger { /** * Logs an error message and an exception to console - * - * @param message the message to log - * @param error the error to throw */ void error(String message, Throwable error); @@ -84,9 +79,4 @@ public interface GeyserLogger { * @param debug if the logger should print debug messages */ void setDebug(boolean debug); - - /** - * If debug is enabled for this logger - */ - boolean isDebug(); } diff --git a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java index 7308fb67..24ce81cf 100644 --- a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java +++ b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java @@ -1,43 +1,41 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.bootstrap; -import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.IGeyserPingPassthrough; -import org.geysermc.connector.configuration.GeyserConfiguration; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.command.CommandManager; -import org.geysermc.connector.network.translators.world.GeyserWorldManager; +import org.geysermc.connector.network.translators.world.CachedChunkManager; import org.geysermc.connector.network.translators.world.WorldManager; -import java.nio.file.Path; - public interface GeyserBootstrap { - GeyserWorldManager DEFAULT_CHUNK_MANAGER = new GeyserWorldManager(); + CachedChunkManager DEFAULT_CHUNK_MANAGER = new CachedChunkManager(); /** * Called when the GeyserBootstrap is enabled @@ -85,18 +83,4 @@ public interface GeyserBootstrap { default WorldManager getWorldManager() { return DEFAULT_CHUNK_MANAGER; } - - /** - * Return the data folder where files get stored - * - * @return Path location of data folder - */ - Path getConfigFolder(); - - /** - * Information used for the bootstrap section of the debug dump - * - * @return The info about the bootstrap - */ - BootstrapDumpInfo getDumpInfo(); } diff --git a/connector/src/main/java/org/geysermc/connector/command/CommandManager.java b/connector/src/main/java/org/geysermc/connector/command/CommandManager.java index d31983eb..88b9e795 100644 --- a/connector/src/main/java/org/geysermc/connector/command/CommandManager.java +++ b/connector/src/main/java/org/geysermc/connector/command/CommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,35 +29,31 @@ import lombok.Getter; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.defaults.*; -import org.geysermc.connector.utils.LanguageUtils; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; public abstract class CommandManager { @Getter private final Map commands = Collections.synchronizedMap(new HashMap<>()); - private final GeyserConnector connector; + private GeyserConnector connector; public CommandManager(GeyserConnector connector) { this.connector = connector; - registerCommand(new HelpCommand(connector, "help", "geyser.commands.help.desc", "geyser.command.help")); - registerCommand(new ListCommand(connector, "list", "geyser.commands.list.desc", "geyser.command.list")); - registerCommand(new ReloadCommand(connector, "reload", "geyser.commands.reload.desc", "geyser.command.reload")); - registerCommand(new StopCommand(connector, "stop", "geyser.commands.stop.desc", "geyser.command.stop")); - registerCommand(new OffhandCommand(connector, "offhand", "geyser.commands.offhand.desc", "geyser.command.offhand")); - registerCommand(new DumpCommand(connector, "dump", "geyser.commands.dump.desc", "geyser.command.dump")); - registerCommand(new VersionCommand(connector, "version", "geyser.commands.version.desc", "geyser.command.version")); - registerCommand(new SettingsCommand(connector, "settings", "geyser.commands.settings.desc", "geyser.command.settings")); - registerCommand(new StatisticsCommand(connector, "statistics", "geyser.commands.statistics.desc", "geyser.command.statistics")); - registerCommand(new AdvancementsCommand(connector, "advancements", "geyser.commands.advancements.desc", "geyser.command.advancements")); + registerCommand(new HelpCommand(connector, "help", "Shows help for all registered commands.", "geyser.command.help")); + registerCommand(new ListCommand(connector, "list", "List all players connected through Geyser.", "geyser.command.list")); + registerCommand(new ReloadCommand(connector, "reload", "Reloads the Geyser configurations. Kicks all players when used!", "geyser.command.reload")); + registerCommand(new StopCommand(connector, "stop", "Shuts down Geyser.", "geyser.command.stop")); + registerCommand(new OffhandCommand(connector, "offhand", "Puts an items in your offhand.", "geyser.command.offhand")); } public void registerCommand(GeyserCommand command) { commands.put(command.getName(), command); - connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.commands.registered", command.getName())); + connector.getLogger().debug("Registered command " + command.getName()); if (command.getAliases().isEmpty()) return; @@ -79,26 +75,19 @@ public abstract class CommandManager { args = new String[0]; } else { label = command.substring(0, command.indexOf(" ")).toLowerCase(); - String argLine = command.substring(command.indexOf(" ") + 1); + String argLine = command.substring(command.indexOf(" " + 1)); args = argLine.contains(" ") ? argLine.split(" ") : new String[] { argLine }; } GeyserCommand cmd = commands.get(label); if (cmd == null) { - connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.invalid")); + connector.getLogger().error("Invalid Command! Try /geyser help for a list of commands."); return; } cmd.execute(sender, args); } - /** - * @return a list of all subcommands under {@code /geyser}. - */ - public List getCommandNames() { - return Arrays.asList(connector.getCommandManager().getCommands().keySet().toArray(new String[0])); - } - /** * Returns the description of the given command * diff --git a/connector/src/main/java/org/geysermc/connector/command/CommandSender.java b/connector/src/main/java/org/geysermc/connector/command/CommandSender.java index 78d12aad..9e4f020b 100644 --- a/connector/src/main/java/org/geysermc/connector/command/CommandSender.java +++ b/connector/src/main/java/org/geysermc/connector/command/CommandSender.java @@ -1,36 +1,5 @@ -/* - * 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.connector.command; -import org.geysermc.connector.utils.LanguageUtils; - -/** - * Implemented on top of any class that can send a command. - * For example, it wraps around Spigot's CommandSender class. - */ public interface CommandSender { String getName(); @@ -43,17 +12,5 @@ public interface CommandSender { void sendMessage(String message); - /** - * @return true if the specified sender is from the console. - */ boolean isConsole(); - - /** - * Returns the locale of the command sender. Defaults to the default locale at {@link LanguageUtils#getDefaultLocale()}. - * - * @return the locale of the command sender. - */ - default String getLocale() { - return LanguageUtils.getDefaultLocale(); - } } diff --git a/connector/src/main/java/org/geysermc/connector/command/GeyserCommand.java b/connector/src/main/java/org/geysermc/connector/command/GeyserCommand.java index c606e2e7..62bc6c73 100644 --- a/connector/src/main/java/org/geysermc/connector/command/GeyserCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/GeyserCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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 lombok.RequiredArgsConstructor; import lombok.Setter; import java.util.ArrayList; -import java.util.Collections; import java.util.List; @Getter @@ -38,9 +37,6 @@ import java.util.List; public abstract class GeyserCommand { protected final String name; - /** - * The description of the command - will attempt to be translated. - */ protected final String description; protected final String permission; @@ -48,31 +44,4 @@ public abstract class GeyserCommand { private List aliases = new ArrayList<>(); public abstract void execute(CommandSender sender, String[] args); - - /** - * If false, hides the command from being shown on the Geyser Standalone GUI. - * - * @return true if the command can be run on the server console - */ - public boolean isExecutableOnConsole() { - return true; - } - - /** - * Used in the GUI to know what subcommands can be run - * - * @return a list of all possible subcommands, or empty if none. - */ - public List getSubCommands() { - return Collections.emptyList(); - } - - /** - * Shortcut to {@link #getSubCommands()}{@code .isEmpty()}. - * - * @return true if there are subcommand present for this command. - */ - public boolean hasSubCommands() { - return !getSubCommands().isEmpty(); - } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/AdvancementsCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/AdvancementsCommand.java deleted file mode 100644 index 3067f3d5..00000000 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/AdvancementsCommand.java +++ /dev/null @@ -1,74 +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.connector.command.defaults; - -import org.geysermc.common.window.SimpleFormWindow; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.cache.AdvancementsCache; - -public class AdvancementsCommand extends GeyserCommand { - - private final GeyserConnector connector; - - public AdvancementsCommand(GeyserConnector connector, String name, String description, String permission) { - super(name, description, permission); - - this.connector = connector; - } - - @Override - public void execute(CommandSender sender, String[] args) { - if (sender.isConsole()) { - return; - } - - // Make sure the sender is a Bedrock edition client - GeyserSession session = null; - if (sender instanceof GeyserSession) { - session = (GeyserSession) sender; - } else { - // Needed for Spigot - sender is not an instance of GeyserSession - for (GeyserSession otherSession : connector.getPlayers()) { - if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) { - session = otherSession; - break; - } - } - } - if (session == null) return; - - SimpleFormWindow window = session.getAdvancementsCache().buildMenuForm(); - session.sendForm(window, AdvancementsCache.ADVANCEMENTS_MENU_FORM_ID); - } - - @Override - public boolean isExecutableOnConsole() { - return false; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java deleted file mode 100644 index 5bc3efea..00000000 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java +++ /dev/null @@ -1,138 +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.connector.command.defaults; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.common.serializer.AsteriskSerializer; -import org.geysermc.connector.dump.DumpInfo; -import org.geysermc.connector.utils.LanguageUtils; -import org.geysermc.connector.utils.WebUtils; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -public class DumpCommand extends GeyserCommand { - - private final GeyserConnector connector; - private static final ObjectMapper MAPPER = new ObjectMapper(); - private static final String DUMP_URL = "https://dump.geysermc.org/"; - - public DumpCommand(GeyserConnector connector, String name, String description, String permission) { - super(name, description, permission); - - this.connector = connector; - } - - @Override - public void execute(CommandSender sender, String[] args) { - boolean showSensitive = false; - boolean offlineDump = false; - if (args.length >= 1) { - for (String arg : args) { - switch (arg) { - case "full": - showSensitive = true; - break; - case "offline": - offlineDump = true; - break; - - } - } - } - - AsteriskSerializer.showSensitive = showSensitive; - - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collecting", sender.getLocale())); - String dumpData = ""; - try { - if (offlineDump) { - dumpData = MAPPER.writerWithDefaultPrettyPrinter().writeValueAsString(new DumpInfo()); - } else { - dumpData = MAPPER.writeValueAsString(new DumpInfo()); - } - } catch (IOException e) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale())); - connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e); - return; - } - - String uploadedDumpUrl = ""; - - if (offlineDump) { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.writing", sender.getLocale())); - - try { - FileOutputStream outputStream = new FileOutputStream(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("dump.json").toFile()); - outputStream.write(dumpData.getBytes()); - outputStream.close(); - } catch (IOException e) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.write_error", sender.getLocale())); - connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error_short"), e); - return; - } - - uploadedDumpUrl = "dump.json"; - } else { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.uploading", sender.getLocale())); - - String response; - JsonNode responseNode; - try { - response = WebUtils.post(DUMP_URL + "documents", dumpData); - responseNode = MAPPER.readTree(response); - } catch (IOException e) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error", sender.getLocale())); - connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short"), e); - return; - } - - if (!responseNode.has("key")) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.upload_error_short", sender.getLocale()) + ": " + (responseNode.has("message") ? responseNode.get("message").asText() : response)); - return; - } - - uploadedDumpUrl = DUMP_URL + responseNode.get("key").asText(); - } - - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.message", sender.getLocale()) + " " + ChatColor.DARK_AQUA + uploadedDumpUrl); - if (!sender.isConsole()) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.commands.dump.created", sender.getName(), uploadedDumpUrl)); - } - } - - @Override - public List getSubCommands() { - return Arrays.asList("offline", "full"); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/HelpCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/HelpCommand.java index 7ab3aec3..6acb7822 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/HelpCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/HelpCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 @@ package org.geysermc.connector.command.defaults; +import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.utils.LanguageUtils; import java.util.Collections; import java.util.List; @@ -49,14 +48,9 @@ public class HelpCommand extends GeyserCommand { @Override public void execute(CommandSender sender, String[] args) { - int page = 1; - int maxPage = 1; - String header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", sender.getLocale(), page, maxPage); - - sender.sendMessage(header); + sender.sendMessage("---- Showing Help For: Geyser (Page 1/1) ----"); Map cmds = connector.getCommandManager().getCommands(); List commands = connector.getCommandManager().getCommands().keySet().stream().sorted().collect(Collectors.toList()); - commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " + - LanguageUtils.getPlayerLocaleString(cmds.get(cmd).getDescription(), sender.getLocale()))); + commands.forEach(cmd -> sender.sendMessage(ChatColor.YELLOW + "/geyser " + cmd + ChatColor.WHITE + ": " + cmds.get(cmd).getDescription())); } } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/ListCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/ListCommand.java index f52ab7f3..21fa4253 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/ListCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/ListCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 @@ package org.geysermc.connector.command.defaults; +import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; import java.util.stream.Collectors; public class ListCommand extends GeyserCommand { - private final GeyserConnector connector; + private GeyserConnector connector; public ListCommand(GeyserConnector connector, String name, String description, String permission) { super(name, description, permission); @@ -45,11 +45,6 @@ public class ListCommand extends GeyserCommand { @Override public void execute(CommandSender sender, String[] args) { - String message = ""; - message = LanguageUtils.getPlayerLocaleString("geyser.commands.list.message", sender.getLocale(), - connector.getPlayers().size(), - connector.getPlayers().stream().map(GeyserSession::getName).collect(Collectors.joining(" "))); - - sender.sendMessage(message); + sender.sendMessage(ChatColor.YELLOW + "Online Players (" + connector.getPlayers().size() + "): " + ChatColor.WHITE + connector.getPlayers().values().stream().map(GeyserSession::getName).collect(Collectors.joining(" "))); } } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java index d6916700..a49506b0 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/OffhandCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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 org.geysermc.connector.network.session.GeyserSession; public class OffhandCommand extends GeyserCommand { - private final GeyserConnector connector; + private GeyserConnector connector; public OffhandCommand(GeyserConnector connector, String name, String description, String permission) { super(name, description, permission); @@ -58,8 +58,8 @@ public class OffhandCommand extends GeyserCommand { session.sendDownstreamPacket(releaseItemPacket); return; } - // Needed for Spigot - sender is not an instance of GeyserSession - for (GeyserSession session : connector.getPlayers()) { + // Needed for Bukkit - sender is not an instance of GeyserSession + for (GeyserSession session : connector.getPlayers().values()) { if (sender.getName().equals(session.getPlayerEntity().getUsername())) { ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0), BlockFace.DOWN); @@ -68,9 +68,4 @@ public class OffhandCommand extends GeyserCommand { } } } - - @Override - public boolean isExecutableOnConsole() { - return false; - } } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/ReloadCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/ReloadCommand.java index 798dd7a7..c38a0c23 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/ReloadCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/ReloadCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 +25,12 @@ package org.geysermc.connector.command.defaults; +import org.geysermc.common.ChatColor; import org.geysermc.common.PlatformType; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.GeyserCommand; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; public class ReloadCommand extends GeyserCommand { @@ -46,13 +46,9 @@ public class ReloadCommand extends GeyserCommand { if (!sender.isConsole() && connector.getPlatformType() == PlatformType.STANDALONE) { return; } - - String message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", sender.getLocale()); - - sender.sendMessage(message); - - for (GeyserSession session : connector.getPlayers()) { - session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getLocale())); + sender.sendMessage(ChatColor.YELLOW + "Reloading Geyser configurations... all connected bedrock clients will be kicked."); + for (GeyserSession session : connector.getPlayers().values()) { + session.disconnect("Geyser has been reloaded... sorry for the inconvenience!"); } connector.reload(); } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/SettingsCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/SettingsCommand.java deleted file mode 100644 index 5e28e985..00000000 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/SettingsCommand.java +++ /dev/null @@ -1,68 +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.connector.command.defaults; - -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.SettingsUtils; - -public class SettingsCommand extends GeyserCommand { - - private final GeyserConnector connector; - - public SettingsCommand(GeyserConnector connector, String name, String description, String permission) { - super(name, description, permission); - - this.connector = connector; - } - - @Override - public void execute(CommandSender sender, String[] args) { - // Make sure the sender is a Bedrock edition client - GeyserSession session = null; - if (sender instanceof GeyserSession) { - session = (GeyserSession) sender; - } else { - // Needed for Spigot - sender is not an instance of GeyserSession - for (GeyserSession otherSession : connector.getPlayers()) { - if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) { - session = otherSession; - break; - } - } - } - if (session == null) return; - SettingsUtils.buildForm(session); - session.sendForm(session.getSettingsForm(), SettingsUtils.SETTINGS_FORM_ID); - } - - @Override - public boolean isExecutableOnConsole() { - return false; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/StatisticsCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/StatisticsCommand.java deleted file mode 100644 index 920ec50c..00000000 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/StatisticsCommand.java +++ /dev/null @@ -1,74 +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.connector.command.defaults; - -import com.github.steveice10.mc.protocol.data.game.ClientRequest; -import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.network.session.GeyserSession; - -public class StatisticsCommand extends GeyserCommand { - - private final GeyserConnector connector; - - public StatisticsCommand(GeyserConnector connector, String name, String description, String permission) { - super(name, description, permission); - - this.connector = connector; - } - - @Override - public void execute(CommandSender sender, String[] args) { - if (sender.isConsole()) { - return; - } - - // Make sure the sender is a Bedrock edition client - GeyserSession session = null; - if (sender instanceof GeyserSession) { - session = (GeyserSession) sender; - } else { - // Needed for Spigot - sender is not an instance of GeyserSession - for (GeyserSession otherSession : connector.getPlayers()) { - if (sender.getName().equals(otherSession.getPlayerEntity().getUsername())) { - session = otherSession; - break; - } - } - } - if (session == null) return; - session.setWaitingForStatistics(true); - ClientRequestPacket clientRequestPacket = new ClientRequestPacket(ClientRequest.STATS); - session.sendDownstreamPacket(clientRequestPacket); - } - - @Override - public boolean isExecutableOnConsole() { - return false; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/StopCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/StopCommand.java index b192c9e9..2222cdef 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/StopCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/StopCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 +49,10 @@ public class StopCommand extends GeyserCommand { return; } - connector.getBootstrap().onDisable(); + connector.shutdown(); + + if (connector.getPlatformType() == PlatformType.STANDALONE) { + System.exit(0); + } } } diff --git a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java b/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java deleted file mode 100644 index 1f807cf6..00000000 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.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.connector.command.defaults; - -import com.github.steveice10.mc.protocol.MinecraftConstants; -import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.command.GeyserCommand; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.network.BedrockProtocol; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; -import org.geysermc.connector.utils.WebUtils; - -import java.io.IOException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Properties; - -public class VersionCommand extends GeyserCommand { - - public GeyserConnector connector; - - public VersionCommand(GeyserConnector connector, String name, String description, String permission) { - super(name, description, permission); - this.connector = connector; - } - - @Override - public void execute(CommandSender sender, String[] args) { - String bedrockVersions; - List supportedCodecs = BedrockProtocol.SUPPORTED_BEDROCK_CODECS; - if (supportedCodecs.size() > 1) { - bedrockVersions = supportedCodecs.get(0).getMinecraftVersion() + " - " + supportedCodecs.get(supportedCodecs.size() - 1).getMinecraftVersion(); - } else { - bedrockVersions = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion(); - } - - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.version", sender.getLocale(), GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftConstants.GAME_VERSION, bedrockVersions)); - - // Disable update checking in dev mode - //noinspection ConstantConditions - changes in production - if (!GeyserConnector.VERSION.equals("DEV")) { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.checking", sender.getLocale())); - try { - Properties gitProp = new Properties(); - gitProp.load(FileUtils.getResource("git.properties")); - - String buildXML = WebUtils.getBody("https://ci.opencollab.dev/job/GeyserMC/job/Geyser/job/" + URLEncoder.encode(gitProp.getProperty("git.branch"), StandardCharsets.UTF_8.toString()) + "/lastSuccessfulBuild/api/xml?xpath=//buildNumber"); - if (buildXML.startsWith("")) { - int latestBuildNum = Integer.parseInt(buildXML.replaceAll("<(\\\\)?(/)?buildNumber>", "").trim()); - int buildNum = Integer.parseInt(gitProp.getProperty("git.build.number")); - if (latestBuildNum == buildNum) { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.no_updates", sender.getLocale())); - } else { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.outdated", sender.getLocale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/")); - } - } else { - throw new AssertionError("buildNumber missing"); - } - } catch (IOException | AssertionError | NumberFormatException e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.version.failed"), e); - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.version.failed", sender.getLocale())); - } - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/common/AuthType.java b/connector/src/main/java/org/geysermc/connector/common/AuthType.java deleted file mode 100644 index 253bd6a5..00000000 --- a/connector/src/main/java/org/geysermc/connector/common/AuthType.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.connector.common; - -import lombok.Getter; - -@Getter -public enum AuthType { - OFFLINE, - ONLINE, - FLOODGATE; - - public static final AuthType[] VALUES = values(); - - public static AuthType getById(int id) { - return id < VALUES.length ? VALUES[id] : OFFLINE; - } - - /** - * Convert the AuthType string (from config) to the enum, OFFLINE on fail - * - * @param name AuthType string - * - * @return The converted AuthType - */ - public static AuthType getByName(String name) { - String upperCase = name.toUpperCase(); - for (AuthType type : VALUES) { - if (type.name().equals(upperCase)) { - return type; - } - } - return OFFLINE; - } -} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java b/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java deleted file mode 100644 index 3f674d7f..00000000 --- a/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java +++ /dev/null @@ -1,118 +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.connector.common.main; - -import javax.swing.*; -import java.io.InputStream; -import java.lang.reflect.Method; -import java.util.Locale; -import java.util.Scanner; - -public class IGeyserMain { - - /** - * Displays the run help message in the console and a message box if running with a gui - */ - public void displayMessage() { - String message = createMessage(); - - if (System.console() == null && !isHeadless()) { - JOptionPane.showMessageDialog(null, message, "GeyserMC Plugin: " + this.getPluginType(), JOptionPane.ERROR_MESSAGE); - } - - printMessage(message); - } - - /** - * Load and format the run help text - * - * @return The formatted message - */ - private String createMessage() { - String message = ""; - - InputStream helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/" + Locale.getDefault().toString() + ".txt"); - - if (helpStream == null) { - helpStream = IGeyserMain.class.getClassLoader().getResourceAsStream("languages/run-help/en_US.txt"); - } - - Scanner help = new Scanner(helpStream).useDelimiter("\\Z"); - String line = ""; - while (help.hasNext()) { - line = help.next(); - - line = line.replace("${plugin_type}", this.getPluginType()); - line = line.replace("${plugin_folder}", this.getPluginFolder()); - - message += line + "\n"; - } - - return message; - } - - /** - * Check if we are in a headless environment - * - * @return Are we in a headless environment? - */ - private boolean isHeadless() { - try { - Class graphicsEnvironment = Class.forName("java.awt.GraphicsEnvironment"); - Method isHeadless = graphicsEnvironment.getDeclaredMethod("isHeadless"); - return (Boolean)isHeadless.invoke(null); - } catch (Exception ex) { } - - return true; - } - - /** - * Simply print a message to console - * - * @param message The message to print - */ - private void printMessage(String message) { - System.out.print(message); - } - - /** - * Get the platform the plugin is for - * - * @return The string representation of the plugin platforms name - */ - public String getPluginType() { - return "unknown"; - } - - /** - * Get the folder name the plugin should go into - * - * @return The string representation of the folder - */ - public String getPluginFolder() { - return "unknown"; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/common/ping/GeyserPingInfo.java b/connector/src/main/java/org/geysermc/connector/common/ping/GeyserPingInfo.java deleted file mode 100644 index 4f86ddfb..00000000 --- a/connector/src/main/java/org/geysermc/connector/common/ping/GeyserPingInfo.java +++ /dev/null @@ -1,93 +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.connector.common.ping; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonSetter; -import com.fasterxml.jackson.databind.JsonNode; -import lombok.Data; - -import java.util.ArrayList; -import java.util.Collection; - -@Data -@JsonIgnoreProperties(ignoreUnknown = true) -public class GeyserPingInfo { - - private String description; - - private Players players; - private Version version; - - @JsonIgnore - private Collection playerList = new ArrayList<>(); - - public GeyserPingInfo() { - } - - public GeyserPingInfo(String description, Players players, Version version) { - this.description = description; - this.players = players; - this.version = version; - } - - @JsonSetter("description") - void setDescription(JsonNode description) { - this.description = description.toString(); - } - - @Data - @JsonIgnoreProperties(ignoreUnknown = true) - public static class Players { - - private int max; - private int online; - - public Players() { - } - - public Players(int max, int online) { - this.max = max; - this.online = online; - } - } - - @Data - public static class Version { - - private String name; - private int protocol; - - public Version() { - } - - public Version(String name, int protocol) { - this.name = name; - this.protocol = protocol; - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/common/serializer/AsteriskSerializer.java b/connector/src/main/java/org/geysermc/connector/common/serializer/AsteriskSerializer.java deleted file mode 100644 index 0b723817..00000000 --- a/connector/src/main/java/org/geysermc/connector/common/serializer/AsteriskSerializer.java +++ /dev/null @@ -1,87 +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.connector.common.serializer; - -import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; -import com.fasterxml.jackson.core.JsonGenerator; -import com.fasterxml.jackson.databind.BeanProperty; -import com.fasterxml.jackson.databind.JsonSerializer; -import com.fasterxml.jackson.databind.SerializerProvider; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.ContextualSerializer; -import com.fasterxml.jackson.databind.ser.std.StdSerializer; - -import java.io.IOException; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import java.util.Optional; - -public class AsteriskSerializer extends StdSerializer implements ContextualSerializer { - - public static boolean showSensitive = false; - - @Target({ElementType.FIELD}) - @Retention(RetentionPolicy.RUNTIME) - @JacksonAnnotationsInside - @JsonSerialize(using = AsteriskSerializer.class) - public @interface Asterisk { - String value() default "***"; - boolean sensitive() default false; - } - - String asterisk; - boolean sensitive; - - public AsteriskSerializer() { - super(Object.class); - } - - public AsteriskSerializer(String asterisk, boolean sensitive) { - super(Object.class); - this.asterisk = asterisk; - this.sensitive = sensitive; - } - - @Override - public JsonSerializer createContextual(SerializerProvider serializerProvider, BeanProperty property) { - Optional anno = Optional.ofNullable(property) - .map(prop -> prop.getAnnotation(Asterisk.class)); - - return new AsteriskSerializer(anno.map(Asterisk::value).orElse(null), anno.map(Asterisk::sensitive).orElse(null)); - } - - @Override - public void serialize(Object obj, JsonGenerator gen, SerializerProvider prov) throws IOException { - if (sensitive && showSensitive) { - gen.writeObject(obj); - return; - } - - gen.writeString(asterisk); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java deleted file mode 100644 index e21aa6bb..00000000 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java +++ /dev/null @@ -1,163 +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.connector.configuration; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import org.geysermc.connector.GeyserLogger; -import org.geysermc.connector.utils.LanguageUtils; - -import java.nio.file.Path; -import java.util.Map; - -public interface GeyserConfiguration { - - // Modify this when you introduce breaking changes into the config - int CURRENT_CONFIG_VERSION = 4; - - IBedrockConfiguration getBedrock(); - - IRemoteConfiguration getRemote(); - - Map getUserAuths(); - - boolean isCommandSuggestions(); - - @JsonIgnore - boolean isPassthroughMotd(); - - @JsonIgnore - boolean isPassthroughProtocolName(); - - @JsonIgnore - boolean isPassthroughPlayerCounts(); - - @JsonIgnore - boolean isLegacyPingPassthrough(); - - int getPingPassthroughInterval(); - - int getMaxPlayers(); - - boolean isDebugMode(); - - int getGeneralThreadPool(); - - boolean isAllowThirdPartyCapes(); - - boolean isAllowThirdPartyEars(); - - boolean isShowCooldown(); - - boolean isShowCoordinates(); - - String getDefaultLocale(); - - Path getFloodgateKeyPath(); - - boolean isAboveBedrockNetherBuilding(); - - boolean isCacheChunks(); - - boolean isForceResourcePacks(); - - boolean isXboxAchievementsEnabled(); - - int getCacheImages(); - - boolean isAllowCustomSkulls(); - - IMetricsInfo getMetrics(); - - interface IBedrockConfiguration { - - String getAddress(); - - int getPort(); - - boolean isCloneRemotePort(); - - String getMotd1(); - - String getMotd2(); - - String getServerName(); - } - - interface IRemoteConfiguration { - - String getAddress(); - - int getPort(); - - void setAddress(String address); - - void setPort(int port); - - String getAuthType(); - - boolean isPasswordAuthentication(); - - boolean isUseProxyProtocol(); - } - - interface IUserAuthenticationInfo { - String getEmail(); - - String getPassword(); - - /** - * Will be removed after Microsoft accounts are fully migrated - */ - @Deprecated - boolean isMicrosoftAccount(); - } - - interface IMetricsInfo { - - boolean isEnabled(); - - String getUniqueId(); - } - - int getScoreboardPacketThreshold(); - - // if u have offline mode enabled pls be safe - boolean isEnableProxyConnections(); - - int getMtu(); - - boolean isUseAdapters(); - - int getConfigVersion(); - - static void checkGeyserConfiguration(GeyserConfiguration geyserConfig, GeyserLogger geyserLogger) { - if (geyserConfig.getConfigVersion() < CURRENT_CONFIG_VERSION) { - geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.outdated")); - } else if (geyserConfig.getConfigVersion() > CURRENT_CONFIG_VERSION) { - geyserLogger.warning(LanguageUtils.getLocaleStringLog("geyser.bootstrap.config.too_new")); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java deleted file mode 100644 index 7c9532ff..00000000 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java +++ /dev/null @@ -1,194 +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.connector.configuration; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.Setter; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.serializer.AsteriskSerializer; - -import java.nio.file.Path; -import java.util.Map; -import java.util.UUID; - -@Getter -@JsonIgnoreProperties(ignoreUnknown = true) -public abstract class GeyserJacksonConfiguration implements GeyserConfiguration { - - /** - * If the config was originally 'auto' before the values changed - */ - @Setter - private boolean autoconfiguredRemote = false; - - private BedrockConfiguration bedrock = new BedrockConfiguration(); - private RemoteConfiguration remote = new RemoteConfiguration(); - - @JsonProperty("floodgate-key-file") - private String floodgateKeyFile = "public-key.pem"; - - public abstract Path getFloodgateKeyPath(); - - private Map userAuths; - - @JsonProperty("command-suggestions") - private boolean commandSuggestions = true; - - @JsonProperty("passthrough-motd") - private boolean isPassthroughMotd = false; - - @JsonProperty("passthrough-player-counts") - private boolean isPassthroughPlayerCounts = false; - - @JsonProperty("passthrough-protocol-name") - private boolean isPassthroughProtocolName = false; - - @JsonProperty("legacy-ping-passthrough") - private boolean isLegacyPingPassthrough = false; - - @JsonProperty("ping-passthrough-interval") - private int pingPassthroughInterval = 3; - - @JsonProperty("max-players") - private int maxPlayers = 100; - - @JsonProperty("debug-mode") - private boolean debugMode = false; - - @JsonProperty("general-thread-pool") - private int generalThreadPool = 32; - - @JsonProperty("allow-third-party-capes") - private boolean allowThirdPartyCapes = true; - - @JsonProperty("show-cooldown") - private boolean showCooldown = true; - - @JsonProperty("show-coordinates") - private boolean showCoordinates = true; - - @JsonProperty("allow-third-party-ears") - private boolean allowThirdPartyEars = false; - - @JsonProperty("default-locale") - private String defaultLocale = null; // is null by default so system language takes priority - - @JsonProperty("cache-chunks") - private boolean cacheChunks = false; - - @JsonProperty("cache-images") - private int cacheImages = 0; - - @JsonProperty("allow-custom-skulls") - private boolean allowCustomSkulls = true; - - @JsonProperty("above-bedrock-nether-building") - private boolean aboveBedrockNetherBuilding = false; - - @JsonProperty("force-resource-packs") - private boolean forceResourcePacks = true; - - @JsonProperty("xbox-achievements-enabled") - private boolean xboxAchievementsEnabled = false; - - private MetricsInfo metrics = new MetricsInfo(); - - @Getter - public static class BedrockConfiguration implements IBedrockConfiguration { - @AsteriskSerializer.Asterisk(sensitive = true) - private String address = "0.0.0.0"; - - @Setter - private int port = 19132; - - @JsonProperty("clone-remote-port") - private boolean cloneRemotePort = false; - - private String motd1 = "GeyserMC"; - private String motd2 = "Geyser"; - - @JsonProperty("server-name") - private String serverName = GeyserConnector.NAME; - } - - @Getter - public static class RemoteConfiguration implements IRemoteConfiguration { - @Setter - @AsteriskSerializer.Asterisk(sensitive = true) - private String address = "auto"; - - @Setter - private int port = 25565; - - @Setter - @JsonProperty("auth-type") - private String authType = "online"; - - @JsonProperty("allow-password-authentication") - private boolean passwordAuthentication = true; - - @JsonProperty("use-proxy-protocol") - private boolean useProxyProtocol = false; - } - - @Getter - @JsonIgnoreProperties(ignoreUnknown = true) // DO NOT REMOVE THIS! Otherwise, after we remove microsoft-account configs will not load - public static class UserAuthenticationInfo implements IUserAuthenticationInfo { - @AsteriskSerializer.Asterisk() - private String email; - - @AsteriskSerializer.Asterisk() - private String password; - - @JsonProperty("microsoft-account") - private boolean microsoftAccount = false; - } - - @Getter - public static class MetricsInfo implements IMetricsInfo { - private boolean enabled = true; - - @JsonProperty("uuid") - private String uniqueId = UUID.randomUUID().toString(); - } - - @JsonProperty("scoreboard-packet-threshold") - private int scoreboardPacketThreshold = 10; - - @JsonProperty("enable-proxy-connections") - private boolean enableProxyConnections = false; - - @JsonProperty("mtu") - private int mtu = 1400; - - @JsonProperty("use-adapters") - private boolean useAdapters = true; - - @JsonProperty("config-version") - private int configVersion = 0; -} diff --git a/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java b/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java deleted file mode 100644 index 4f16de90..00000000 --- a/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java +++ /dev/null @@ -1,62 +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.connector.dump; - -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.geysermc.common.PlatformType; -import org.geysermc.connector.GeyserConnector; - -import java.util.List; - -@Getter -public class BootstrapDumpInfo { - - private PlatformType platform; - - public BootstrapDumpInfo() { - this.platform = GeyserConnector.getInstance().getPlatformType(); - } - - @Getter - @AllArgsConstructor - public class PluginInfo { - - public boolean enabled; - public String name; - public String version; - public String main; - public List authors; - } - - @Getter - @AllArgsConstructor - public class ListenerInfo { - - public String ip; - public int port; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java deleted file mode 100644 index 9af740d9..00000000 --- a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java +++ /dev/null @@ -1,166 +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.connector.dump; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.github.steveice10.mc.protocol.MinecraftConstants; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import lombok.Getter; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.serializer.AsteriskSerializer; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.network.BedrockProtocol; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.DockerCheck; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.floodgate.util.DeviceOS; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.util.Properties; - -@Getter -public class DumpInfo { - - @JsonIgnore - private static final long MEGABYTE = 1024L * 1024L; - - private final DumpInfo.VersionInfo versionInfo; - private Properties gitInfo; - private final GeyserConfiguration config; - private Object2IntMap userPlatforms; - private RamInfo ramInfo; - private final BootstrapDumpInfo bootstrapInfo; - - public DumpInfo() { - this.versionInfo = new DumpInfo.VersionInfo(); - - try { - this.gitInfo = new Properties(); - this.gitInfo.load(FileUtils.getResource("git.properties")); - } catch (IOException ignored) { } - - this.config = GeyserConnector.getInstance().getConfig(); - - this.ramInfo = new DumpInfo.RamInfo(); - - this.userPlatforms = new Object2IntOpenHashMap(); - for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) { - DeviceOS device = session.getClientData().getDeviceOS(); - userPlatforms.put(device, userPlatforms.getOrDefault(device, 0) + 1); - } - - this.bootstrapInfo = GeyserConnector.getInstance().getBootstrap().getDumpInfo(); - } - - @Getter - public class VersionInfo { - - private final String name; - private final String version; - private final String javaVersion; - private final String architecture; - private final String operatingSystem; - private final String operatingSystemVersion; - - private final NetworkInfo network; - private final MCInfo mcInfo; - - VersionInfo() { - this.name = GeyserConnector.NAME; - this.version = GeyserConnector.VERSION; - this.javaVersion = System.getProperty("java.version"); - this.architecture = System.getProperty("os.arch"); // Usually gives Java architecture but still may be helpful. - this.operatingSystem = System.getProperty("os.name"); - this.operatingSystemVersion = System.getProperty("os.version"); - - this.network = new NetworkInfo(); - this.mcInfo = new MCInfo(); - } - } - - @Getter - public static class NetworkInfo { - - private String internalIP; - private final boolean dockerCheck; - - NetworkInfo() { - if (AsteriskSerializer.showSensitive) { - try { - // This is the most reliable for getting the main local IP - Socket socket = new Socket(); - socket.connect(new InetSocketAddress("geysermc.org", 80)); - this.internalIP = socket.getLocalAddress().getHostAddress(); - } catch (IOException e1) { - try { - // Fallback to the normal way of getting the local IP - this.internalIP = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException ignored) { } - } - } else { - // Sometimes the internal IP is the external IP... - this.internalIP = "***"; - } - - this.dockerCheck = DockerCheck.checkBasic(); - } - } - - @Getter - public static class MCInfo { - - private final String bedrockVersion; - private final int bedrockProtocol; - private final String javaVersion; - private final int javaProtocol; - - MCInfo() { - this.bedrockVersion = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion(); - this.bedrockProtocol = BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion(); - this.javaVersion = MinecraftConstants.GAME_VERSION; - this.javaProtocol = MinecraftConstants.PROTOCOL_VERSION; - } - } - - @Getter - public static class RamInfo { - - private final long free; - private final long total; - private final long max; - - RamInfo() { - this.free = Runtime.getRuntime().freeMemory() / MEGABYTE; - this.total = Runtime.getRuntime().totalMemory() / MEGABYTE; - this.max = Runtime.getRuntime().maxMemory() / MEGABYTE; - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java b/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java index e9a4a1f9..fa089707 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/AbstractArrowEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java index 6f3d0204..79e67f34 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/AreaEffectCloudEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.world.particle.Particle; 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.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.effect.EffectRegistry; @@ -43,26 +42,19 @@ public class AreaEffectCloudEntity extends Entity { metadata.put(EntityData.AREA_EFFECT_CLOUD_DURATION, 600); // This disabled client side shrink of the cloud - metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 0.0f); - metadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_RATE, -0.005f); - metadata.put(EntityData.AREA_EFFECT_CLOUD_CHANGE_ON_PICKUP, -0.5f); - - metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); + metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS_PER_TICK, 0.0f); } @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 7) { - metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, entityMetadata.getValue()); + metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, (float) entityMetadata.getValue()); metadata.put(EntityData.BOUNDING_BOX_WIDTH, 2.0f * (float) entityMetadata.getValue()); - } else if (entityMetadata.getId() == 8) { - metadata.put(EntityData.EFFECT_COLOR, entityMetadata.getValue()); } else if (entityMetadata.getId() == 10) { Particle particle = (Particle) entityMetadata.getValue(); - int particleId = EffectRegistry.getParticleId(particle.getType()); - if (particleId != -1) { - metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, particleId); - } + metadata.put(EntityData.AREA_EFFECT_CLOUD_PARTICLE_ID, EffectRegistry.getParticleString(particle.getType())); + } else if (entityMetadata.getId() == 8) { + metadata.put(EntityData.POTION_COLOR, entityMetadata.getValue()); } super.updateBedrockMetadata(entityMetadata, session); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java index 1afcf08d..8f79526d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/BoatEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -35,16 +35,6 @@ import java.util.concurrent.TimeUnit; public class BoatEntity extends Entity { - /** - * Required when IS_BUOYANT is sent in order for boats to work in the water.
- * - * Taken from BDS 1.16.200, with the modification of simulate_waves since Java doesn't bob the boat up and down - * like Bedrock. - */ - private static final String BUOYANCY_DATA = "{\"apply_gravity\":true,\"base_buoyancy\":1.0,\"big_wave_probability\":0.02999999932944775," + - "\"big_wave_speed\":10.0,\"drag_down_on_buoyancy_removed\":0.0,\"liquid_blocks\":[\"minecraft:water\"," + - "\"minecraft:flowing_water\"],\"simulate_waves\":false}}"; - private boolean isPaddlingLeft; private float paddleTimeLeft; private boolean isPaddlingRight; @@ -54,32 +44,19 @@ public class BoatEntity extends Entity { private final float ROWING_SPEED = 0.05f; public BoatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(90, 0, 90)); - - // Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+ - metadata.put(EntityData.IS_BUOYANT, (byte) 1); - metadata.put(EntityData.BUOYANCY_DATA, BUOYANCY_DATA); + super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation.add(0, 0, 90)); } @Override public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { + // Rotation is basically only called when entering/exiting a boat. // We don't include the rotation (y) as it causes the boat to appear sideways - super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(rotation.getX() + 90, 0, rotation.getX() + 90), isOnGround, teleported); + super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), Vector3f.from(0, 0, rotation.getZ() + 90), isOnGround, teleported); } @Override public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { - super.moveRelative(session, relX, relY, relZ, Vector3f.from(rotation.getX(), 0, rotation.getX()), isOnGround); - } - - @Override - public void updatePositionAndRotation(GeyserSession session, double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(session, moveX, moveY, moveZ, yaw + 90, pitch, isOnGround); - } - - @Override - public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) { - moveRelative(session, 0, 0, 0, Vector3f.from(yaw + 90, 0, 0), isOnGround); + super.moveRelative(session, relX, relY, relZ, Vector3f.from(0, 0, rotation.getZ()), isOnGround); } @Override @@ -106,7 +83,7 @@ public class BoatEntity extends Entity { } else if (entityMetadata.getId() == 11) { isPaddlingLeft = (boolean) entityMetadata.getValue(); if (!isPaddlingLeft) { - metadata.put(EntityData.ROW_TIME_LEFT, 0f); + metadata.put(EntityData.PADDLE_TIME_LEFT, 0f); } else { // Java sends simply "true" and "false" (is_paddling_left), Bedrock keeps sending packets as you're rowing @@ -120,7 +97,7 @@ public class BoatEntity extends Entity { else if (entityMetadata.getId() == 12) { isPaddlingRight = (boolean) entityMetadata.getValue(); if (!isPaddlingRight) { - metadata.put(EntityData.ROW_TIME_RIGHT, 0f); + metadata.put(EntityData.PADDLE_TIME_RIGHT, 0f); } else { paddleTimeRight = 0f; session.getConnector().getGeneralThreadPool().execute(() -> @@ -138,7 +115,7 @@ public class BoatEntity extends Entity { public void updateLeftPaddle(GeyserSession session, EntityMetadata entityMetadata) { if (isPaddlingLeft) { paddleTimeLeft += ROWING_SPEED; - metadata.put(EntityData.ROW_TIME_LEFT, paddleTimeLeft); + metadata.put(EntityData.PADDLE_TIME_LEFT, paddleTimeLeft); super.updateBedrockMetadata(entityMetadata, session); session.getConnector().getGeneralThreadPool().schedule(() -> updateLeftPaddle(session, entityMetadata), @@ -150,7 +127,7 @@ public class BoatEntity extends Entity { public void updateRightPaddle(GeyserSession session, EntityMetadata entityMetadata) { if (isPaddlingRight) { paddleTimeRight += ROWING_SPEED; - metadata.put(EntityData.ROW_TIME_RIGHT, paddleTimeRight); + metadata.put(EntityData.PADDLE_TIME_RIGHT, paddleTimeRight); super.updateBedrockMetadata(entityMetadata, session); session.getConnector().getGeneralThreadPool().schedule(() -> updateRightPaddle(session, entityMetadata), diff --git a/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java deleted file mode 100644 index 6ae65643..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/CommandBlockMinecartEntity.java +++ /dev/null @@ -1,67 +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.connector.entity; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import net.kyori.adventure.text.Component; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.chat.MessageTranslator; - -public class CommandBlockMinecartEntity extends DefaultBlockMinecartEntity { - - public CommandBlockMinecartEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - // Required, or else the GUI will not open - metadata.put(EntityData.CONTAINER_TYPE, (byte) 16); - metadata.put(EntityData.CONTAINER_BASE_SIZE, 1); - // Required, or else the client does not bother to send a packet back with the new information - metadata.put(EntityData.COMMAND_BLOCK_ENABLED, (byte) 1); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 13) { - metadata.put(EntityData.COMMAND_BLOCK_COMMAND, entityMetadata.getValue()); - } - if (entityMetadata.getId() == 14) { - metadata.put(EntityData.COMMAND_BLOCK_LAST_OUTPUT, MessageTranslator.convertMessage((Component) entityMetadata.getValue())); - } - super.updateBedrockMetadata(entityMetadata, session); - } - - /** - * By default, the command block shown is purple on Bedrock, which does not match Java Edition's orange. - */ - @Override - public void updateDefaultBlockMetadata() { - metadata.put(EntityData.DISPLAY_ITEM, BlockTranslator.BEDROCK_RUNTIME_COMMAND_BLOCK_ID); - metadata.put(EntityData.DISPLAY_OFFSET, 6); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java index 8ab368e7..b774af98 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/DefaultBlockMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -45,7 +45,7 @@ public class DefaultBlockMinecartEntity extends MinecartEntity { super(entityId, geyserId, entityType, position, motion, rotation); updateDefaultBlockMetadata(); - metadata.put(EntityData.CUSTOM_DISPLAY, (byte) 1); + metadata.put(EntityData.HAS_DISPLAY, (byte) 1); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java b/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java index 8997512d..727df90c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/EnderCrystalEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +29,8 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat 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; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -39,8 +39,6 @@ public class EnderCrystalEntity extends Entity { public EnderCrystalEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - // Bedrock 1.16.100+ - prevents the entity from appearing on fire itself when fire is underneath it - metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index d41578db..16e9c0a1 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,28 +32,30 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.github.steveice10.mc.protocol.data.message.TextMessage; +import com.github.steveice10.mc.protocol.data.message.TranslationMessage; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.AttributeData; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityDataMap; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlags; import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import lombok.Getter; import lombok.Setter; -import net.kyori.adventure.text.Component; import org.geysermc.connector.entity.attribute.Attribute; import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.entity.living.ArmorStandEntity; -import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.utils.AttributeUtils; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.ChunkUtils; +import org.geysermc.connector.utils.MessageUtils; import java.util.ArrayList; import java.util.HashMap; @@ -66,6 +68,8 @@ public class Entity { protected long entityId; protected long geyserId; + protected int dimension; + protected Vector3f position; protected Vector3f motion; @@ -74,11 +78,6 @@ public class Entity { */ protected Vector3f rotation; - /** - * Saves if the entity should be on the ground. Otherwise entities like parrots are flapping when rotating - */ - protected boolean onGround; - protected float scale = 1; protected EntityType entityType; @@ -97,14 +96,15 @@ public class Entity { this.rotation = rotation; this.valid = false; + this.dimension = 0; setPosition(position); metadata.put(EntityData.SCALE, 1f); metadata.put(EntityData.COLOR, 0); - metadata.put(EntityData.MAX_AIR_SUPPLY, (short) 300); - metadata.put(EntityData.AIR_SUPPLY, (short) 0); - metadata.put(EntityData.LEASH_HOLDER_EID, -1L); + metadata.put(EntityData.MAX_AIR, (short) 300); + metadata.put(EntityData.AIR, (short) 0); + metadata.put(EntityData.LEAD_HOLDER_EID, -1L); metadata.put(EntityData.BOUNDING_BOX_HEIGHT, entityType.getHeight()); metadata.put(EntityData.BOUNDING_BOX_WIDTH, entityType.getWidth()); EntityFlags flags = new EntityFlags(); @@ -141,13 +141,6 @@ public class Entity { public boolean despawnEntity(GeyserSession session) { 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.getMetadata().getOrCreateFlags().setFlag(EntityFlag.RIDING, false); - entity.updateBedrockMetadata(session); - } - RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket(); removeEntityPacket.setUniqueEntityId(geyserId); session.sendUpstreamPacket(removeEntityPacket); @@ -157,12 +150,11 @@ public class Entity { } public void moveRelative(GeyserSession session, double relX, double relY, double relZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(session, relX, relY, relZ, Vector3f.from(yaw, pitch, this.rotation.getZ()), isOnGround); + moveRelative(session, relX, relY, relZ, Vector3f.from(yaw, pitch, yaw), isOnGround); } public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { setRotation(rotation); - setOnGround(isOnGround); this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); @@ -176,13 +168,12 @@ public class Entity { } public void moveAbsolute(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround, boolean teleported) { - moveAbsolute(session, position, Vector3f.from(yaw, pitch, this.rotation.getZ()), isOnGround, teleported); + moveAbsolute(session, position, Vector3f.from(yaw, pitch, yaw), isOnGround, teleported); } public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { setPosition(position); setRotation(rotation); - setOnGround(isOnGround); MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); moveEntityPacket.setRuntimeEntityId(geyserId); @@ -194,56 +185,10 @@ public class Entity { session.sendUpstreamPacket(moveEntityPacket); } - /** - * Teleports an entity to a new location. Used in JavaEntityTeleportTranslator. - * @param session GeyserSession. - * @param position The new position of the entity. - * @param yaw The new yaw of the entity. - * @param pitch The new pitch of the entity. - * @param isOnGround Whether the entity is currently on the ground. - */ - public void teleport(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround) { - moveAbsolute(session, position, yaw, pitch, isOnGround, false); - } - - /** - * Updates an entity's head position. Used in JavaEntityHeadLookTranslator. - * @param session GeyserSession. - * @param headYaw The new head rotation of the entity. - */ - public void updateHeadLookRotation(GeyserSession session, float headYaw) { - moveRelative(session, 0, 0, 0, Vector3f.from(headYaw, rotation.getY(), rotation.getZ()), onGround); - } - - /** - * Updates an entity's position and rotation. Used in JavaEntityPositionRotationTranslator. - * @param session GeyserSession - * @param moveX The new X offset of the current position. - * @param moveY The new Y offset of the current position. - * @param moveZ The new Z offset of the current position. - * @param yaw The new yaw of the entity. - * @param pitch The new pitch of the entity. - * @param isOnGround Whether the entity is currently on the ground. - */ - public void updatePositionAndRotation(GeyserSession session, double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(session, moveX, moveY, moveZ, Vector3f.from(rotation.getX(), pitch, yaw), isOnGround); - } - - /** - * Updates an entity's rotation. Used in JavaEntityRotationTranslator. - * @param session GeyserSession. - * @param yaw The new yaw of the entity. - * @param pitch The new pitch of the entity. - * @param isOnGround Whether the entity is currently on the ground. - */ - public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) { - updatePositionAndRotation(session, 0, 0, 0, yaw, pitch, isOnGround); - } - public void updateBedrockAttributes(GeyserSession session) { if (!valid) return; - List attributes = new ArrayList<>(); + List attributes = new ArrayList<>(); for (Map.Entry entry : this.attributes.entrySet()) { if (!entry.getValue().getType().isBedrockAttribute()) continue; @@ -257,20 +202,15 @@ public class Entity { session.sendUpstreamPacket(updateAttributesPacket); } - /** - * Applies the Java metadata to the local Bedrock metadata copy - * @param entityMetadata the Java entity metadata - * @param session GeyserSession - */ public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { switch (entityMetadata.getId()) { case 0: if (entityMetadata.getType() == MetadataType.BYTE) { byte xd = (byte) entityMetadata.getValue(); - metadata.getFlags().setFlag(EntityFlag.ON_FIRE, ((xd & 0x01) == 0x01) && !metadata.getFlags().getFlag(EntityFlag.FIRE_IMMUNE)); // Otherwise immune entities sometimes flicker onfire + metadata.getFlags().setFlag(EntityFlag.ON_FIRE, (xd & 0x01) == 0x01); metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x02) == 0x02); metadata.getFlags().setFlag(EntityFlag.SPRINTING, (xd & 0x08) == 0x08); - metadata.getFlags().setFlag(EntityFlag.SWIMMING, ((xd & 0x10) == 0x10) && metadata.getFlags().getFlag(EntityFlag.SPRINTING)); // Otherwise swimming is enabled on older servers + metadata.getFlags().setFlag(EntityFlag.SWIMMING, (xd & 0x10) == 0x10); metadata.getFlags().setFlag(EntityFlag.GLIDING, (xd & 0x80) == 0x80); if ((xd & 0x20) == 0x20) { @@ -284,11 +224,11 @@ public class Entity { // Shield code if (session.getPlayerEntity().getEntityId() == entityId && metadata.getFlags().getFlag(EntityFlag.SNEAKING)) { - if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) || - (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD.getJavaId())) { + if ((session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) || + (session.getInventoryCache().getPlayerInventory().getItem(45) != null && session.getInventoryCache().getPlayerInventory().getItem(45).getId() == ItemRegistry.SHIELD)) { ClientPlayerUseItemPacket useItemPacket; metadata.getFlags().setFlag(EntityFlag.BLOCKING, true); - if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD.getJavaId()) { + if (session.getInventory().getItemInHand() != null && session.getInventory().getItemInHand().getId() == ItemRegistry.SHIELD) { useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); } // Else we just assume it's the offhand, to simplify logic and to assure the packet gets sent @@ -299,7 +239,7 @@ public class Entity { } } else if (session.getPlayerEntity().getEntityId() == entityId && !metadata.getFlags().getFlag(EntityFlag.SNEAKING) && metadata.getFlags().getFlag(EntityFlag.BLOCKING)) { metadata.getFlags().setFlag(EntityFlag.BLOCKING, false); - metadata.getFlags().setFlag(EntityFlag.IS_AVOIDING_BLOCK, true); + metadata.getFlags().setFlag(EntityFlag.DISABLE_BLOCKING, true); ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.RELEASE_USE_ITEM, new Position(0, 0, 0), BlockFace.DOWN); session.sendDownstreamPacket(releaseItemPacket); } @@ -307,22 +247,25 @@ public class Entity { break; case 1: // Air/bubbles if ((int) entityMetadata.getValue() == 300) { - metadata.put(EntityData.AIR_SUPPLY, (short) 0); // Otherwise the bubble counter remains in the UI + metadata.put(EntityData.AIR, (short) 0); // Otherwise the bubble counter remains in the UI } else { - metadata.put(EntityData.AIR_SUPPLY, (short) (int) entityMetadata.getValue()); + metadata.put(EntityData.AIR, (short) (int) entityMetadata.getValue()); } break; case 2: // custom name - if (entityMetadata.getValue() instanceof Component) { - Component message = (Component) entityMetadata.getValue(); + if (entityMetadata.getValue() instanceof TextMessage) { + TextMessage name = (TextMessage) entityMetadata.getValue(); + if (name != null) + metadata.put(EntityData.NAMETAG, MessageUtils.getBedrockMessage(name)); + } else if (entityMetadata.getValue() instanceof TranslationMessage) { + TranslationMessage message = (TranslationMessage) entityMetadata.getValue(); if (message != null) - // Always translate even if it's a TextMessage since there could be translatable parameters - metadata.put(EntityData.NAMETAG, MessageTranslator.convertMessage(message, session.getLocale())); + metadata.put(EntityData.NAMETAG, MessageUtils.getTranslatedBedrockMessage(message, session.getClientData().getLanguageCode(), true)); } break; case 3: // is custom name visible if (!this.is(PlayerEntity.class)) - metadata.put(EntityData.NAMETAG_ALWAYS_SHOW, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); + metadata.put(EntityData.ALWAYS_SHOW_NAMETAG, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); break; case 4: // silent metadata.getFlags().setFlag(EntityFlag.SILENT, (boolean) entityMetadata.getValue()); @@ -334,23 +277,39 @@ public class Entity { if (entityMetadata.getValue().equals(Pose.SLEEPING)) { metadata.getFlags().setFlag(EntityFlag.SLEEPING, true); // Has to be a byte or it does not work - metadata.put(EntityData.PLAYER_FLAGS, (byte) 2); + metadata.put(EntityData.CAN_START_SLEEP, (byte) 2); + if (entityId == session.getPlayerEntity().getEntityId()) { + Vector3i lastInteractionPos = session.getLastInteractionPosition(); + metadata.put(EntityData.BED_RESPAWN_POS, lastInteractionPos); + if (session.getConnector().getConfig().isCacheChunks()) { + BlockState bed = session.getConnector().getWorldManager().getBlockAt(session, lastInteractionPos.getX(), + lastInteractionPos.getY(), lastInteractionPos.getZ()); + // Bed has to be updated, or else player is floating in the air + ChunkUtils.updateBlock(session, bed, lastInteractionPos); + } + } else { + metadata.put(EntityData.BED_RESPAWN_POS, Vector3i.from(position.getFloorX(), position.getFloorY() - 2, position.getFloorZ())); + } metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.2f); metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.2f); } else if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) { metadata.getFlags().setFlag(EntityFlag.SLEEPING, false); metadata.put(EntityData.BOUNDING_BOX_WIDTH, getEntityType().getWidth()); metadata.put(EntityData.BOUNDING_BOX_HEIGHT, getEntityType().getHeight()); - metadata.put(EntityData.PLAYER_FLAGS, (byte) 0); + metadata.put(EntityData.CAN_START_SLEEP, (byte) 0); + } + break; + case 7: // blocking + if (entityMetadata.getType() == MetadataType.BYTE) { + byte xd = (byte) entityMetadata.getValue(); + metadata.getFlags().setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01); } break; } + + updateBedrockMetadata(session); } - /** - * Sends the Bedrock metadata to the client - * @param session GeyserSession - */ public void updateBedrockMetadata(GeyserSession session) { if (!valid) return; diff --git a/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java index 45595f50..bfd3e1ca 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ExpOrbEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java index 76ca0567..59e1d408 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FallingBlockEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 +25,9 @@ package org.geysermc.connector.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; public class FallingBlockEntity extends Entity { @@ -40,12 +37,4 @@ public class FallingBlockEntity extends Entity { this.metadata.put(EntityData.VARIANT, BlockTranslator.getBedrockBlockId(javaId)); } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - // Set the NO_AI flag based on the no gravity flag to prevent movement - if (entityMetadata.getId() == 5) { - this.metadata.getFlags().setFlag(EntityFlag.NO_AI, (boolean) entityMetadata.getValue()); - } - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java index deaf3fad..1db4f757 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FireworkEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 +31,13 @@ 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.math.vector.Vector3f; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; -import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.FireworkColor; import org.geysermc.connector.utils.MathUtils; -import org.geysermc.floodgate.util.DeviceOS; import java.util.ArrayList; import java.util.List; @@ -53,44 +49,32 @@ public class FireworkEntity extends Entity { super(entityId, geyserId, entityType, position, motion, rotation); } + @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 7) { ItemStack item = (ItemStack) entityMetadata.getValue(); - if (item == null) { - return; - } CompoundTag tag = item.getNbt(); if (tag == null) { return; } - // TODO: Remove once Mojang fixes bugs with fireworks crashing clients on these specific devices. - // https://bugs.mojang.com/browse/MCPE-89115 - if (session.getClientData().getDeviceOS() == DeviceOS.XBOX_ONE || session.getClientData().getDeviceOS() == DeviceOS.ORBIS) { - return; - } - CompoundTag fireworks = tag.get("Fireworks"); - if (fireworks == null) { - // Thank you Mineplex very cool - return; - } - NbtMapBuilder fireworksBuilder = NbtMap.builder(); + CompoundTagBuilder fireworksBuilder = CompoundTagBuilder.builder(); if (fireworks.get("Flight") != null) { - fireworksBuilder.putByte("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())); + fireworksBuilder.byteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue())); } - List explosions = new ArrayList<>(); + List explosions = new ArrayList<>(); if (fireworks.get("Explosions") != null) { for (Tag effect : ((ListTag) fireworks.get("Explosions")).getValue()) { CompoundTag effectData = (CompoundTag) effect; - NbtMapBuilder effectBuilder = NbtMap.builder(); + CompoundTagBuilder effectBuilder = CompoundTagBuilder.builder(); if (effectData.get("Type") != null) { - effectBuilder.putByte("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue())); + effectBuilder.byteTag("FireworkType", MathUtils.convertByte(effectData.get("Type").getValue())); } if (effectData.get("Colors") != null) { @@ -102,7 +86,7 @@ public class FireworkEntity extends Entity { colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); } - effectBuilder.putByteArray("FireworkColor", colors); + effectBuilder.byteArrayTag("FireworkColor", colors); } if (effectData.get("FadeColors") != null) { @@ -114,26 +98,24 @@ public class FireworkEntity extends Entity { colors[i++] = FireworkColor.fromJavaID(color).getBedrockID(); } - effectBuilder.putByteArray("FireworkFade", colors); + effectBuilder.byteArrayTag("FireworkFade", colors); } if (effectData.get("Trail") != null) { - effectBuilder.putByte("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue())); + effectBuilder.byteTag("FireworkTrail", MathUtils.convertByte(effectData.get("Trail").getValue())); } if (effectData.get("Flicker") != null) { - effectBuilder.putByte("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue())); + effectBuilder.byteTag("FireworkFlicker", MathUtils.convertByte(effectData.get("Flicker").getValue())); } - explosions.add(effectBuilder.build()); + explosions.add(effectBuilder.buildRootTag()); } } - fireworksBuilder.putList("Explosions", NbtType.COMPOUND, explosions); + fireworksBuilder.tag(new com.nukkitx.nbt.tag.ListTag<>("Explosions", com.nukkitx.nbt.tag.CompoundTag.class, explosions)); - NbtMapBuilder builder = NbtMap.builder(); - builder.put("Fireworks", fireworksBuilder.build()); - metadata.put(EntityData.DISPLAY_ITEM, builder.build()); + metadata.put(EntityData.DISPLAY_ITEM, CompoundTagBuilder.builder().tag(fireworksBuilder.build("Fireworks")).buildRootTag()); } else if (entityMetadata.getId() == 8 && !entityMetadata.getValue().equals(OptionalInt.empty()) && ((OptionalInt) entityMetadata.getValue()).getAsInt() == session.getPlayerEntity().getEntityId()) { //Checks if the firework has an entity ID (used when a player is gliding) and checks to make sure the player that is gliding is the one getting sent the packet or else every player near the gliding player will boost too. PlayerEntity entity = session.getPlayerEntity(); diff --git a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java index 9f9b7bc3..1b648f7c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FishingHookEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +28,7 @@ package org.geysermc.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.object.ProjectileData; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -37,7 +37,7 @@ public class FishingHookEntity extends Entity { public FishingHookEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, ProjectileData data) { super(entityId, geyserId, entityType, position, motion, rotation); - for (GeyserSession session : GeyserConnector.getInstance().getPlayers()) { + for (GeyserSession session : GeyserConnector.getInstance().getPlayers().values()) { Entity entity = session.getEntityCache().getEntityByJavaId(data.getOwnerId()); if (entity == null && session.getPlayerEntity().getEntityId() == data.getOwnerId()) { entity = session.getPlayerEntity(); diff --git a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java index e3af51be..29ade193 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/FurnaceMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java index ed48e267..41308a0d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,20 +36,7 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; public class ItemEntity extends Entity { public ItemEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position.add(0d, entityType.getOffset(), 0d), motion, rotation); - } - - @Override - public void setMotion(Vector3f motion) { - if (isOnGround()) - motion = Vector3f.from(motion.getX(), 0, motion.getZ()); - - super.setMotion(motion); - } - - @Override - public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { - super.moveAbsolute(session, position.add(0d, this.entityType.getOffset(), 0d), rotation, isOnGround, teleported); + super(entityId, geyserId, entityType, position, motion, rotation); } @Override @@ -57,7 +44,7 @@ public class ItemEntity extends Entity { if (entityMetadata.getId() == 7) { AddItemEntityPacket itemPacket = new AddItemEntityPacket(); itemPacket.setRuntimeEntityId(geyserId); - itemPacket.setPosition(position.add(0d, this.entityType.getOffset(), 0d)); + itemPacket.setPosition(position); itemPacket.setMotion(motion); itemPacket.setUniqueEntityId(geyserId); itemPacket.setFromFishing(false); diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java index 4f0a224e..3680945c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemFrameEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 +30,11 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.entity.object.HangingDirection; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -65,18 +66,21 @@ public class ItemFrameEntity extends Entity { /** * Cached item frame's Bedrock compound tag. */ - private NbtMap cachedTag; + private CompoundTag cachedTag; public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) { super(entityId, geyserId, entityType, position, motion, rotation); - NbtMapBuilder blockBuilder = NbtMap.builder() - .putString("name", "minecraft:frame") - .putInt("version", BlockTranslator.getBlockStateVersion()); - blockBuilder.put("states", NbtMap.builder() - .putInt("facing_direction", direction.ordinal()) - .putByte("item_frame_map_bit", (byte) 0) - .build()); - bedrockRuntimeId = BlockTranslator.getItemFrame(blockBuilder.build()); + CompoundTagBuilder builder = CompoundTag.builder(); + builder.tag(CompoundTag.builder() + .stringTag("name", "minecraft:frame") + .intTag("version", BlockTranslator.getBlockStateVersion()) + .tag(CompoundTag.builder() + .intTag("facing_direction", direction.ordinal()) + .byteTag("item_frame_map_bit", (byte) 0) + .build("states")) + .build("block")); + builder.shortTag("id", (short) 199); + bedrockRuntimeId = BlockTranslator.getItemFrame(builder.buildRootTag()); bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ()); } @@ -96,19 +100,27 @@ public class ItemFrameEntity extends Entity { if (entityMetadata.getId() == 7 && entityMetadata.getValue() != null) { ItemData itemData = ItemTranslator.translateToBedrock(session, (ItemStack) entityMetadata.getValue()); ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue()); - NbtMapBuilder builder = NbtMap.builder(); + CompoundTagBuilder builder = CompoundTag.builder(); - builder.putByte("Count", (byte) itemData.getCount()); - if (itemData.getTag() != null) { - builder.put("tag", itemData.getTag().toBuilder().build()); + String blockName = ""; + for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) { + if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) { + blockName = startGamePacketItemEntry.getIdentifier(); + break; + } } - builder.putShort("Damage", itemData.getDamage()); - builder.putString("Name", itemEntry.getBedrockIdentifier()); - NbtMapBuilder tag = getDefaultTag().toBuilder(); - tag.put("Item", builder.build()); - tag.putFloat("ItemDropChance", 1.0f); - tag.putFloat("ItemRotation", rotation); - cachedTag = tag.build(); + + builder.byteTag("Count", (byte) itemData.getCount()); + if (itemData.getTag() != null) { + builder.tag(itemData.getTag().toBuilder().build("tag")); + } + builder.shortTag("Damage", itemData.getDamage()); + builder.stringTag("Name", blockName); + CompoundTagBuilder tag = getDefaultTag().toBuilder(); + tag.tag(builder.build("Item")); + tag.floatTag("ItemDropChance", 1.0f); + tag.floatTag("ItemRotation", rotation); + cachedTag = tag.buildRootTag(); updateBlock(session); } else if (entityMetadata.getId() == 7 && entityMetadata.getValue() == null && cachedTag != null) { @@ -121,9 +133,9 @@ public class ItemFrameEntity extends Entity { updateBlock(session); return; } - NbtMapBuilder builder = cachedTag.toBuilder(); - builder.putFloat("ItemRotation", rotation); - cachedTag = builder.build(); + CompoundTagBuilder builder = cachedTag.toBuilder(); + builder.floatTag("ItemRotation", rotation); + cachedTag = builder.buildRootTag(); updateBlock(session); } else { @@ -136,9 +148,9 @@ public class ItemFrameEntity extends Entity { UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setBlockPosition(bedrockPosition); - updateBlockPacket.setRuntimeId(BlockTranslator.BEDROCK_AIR_ID); + updateBlockPacket.setRuntimeId(0); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); session.sendUpstreamPacket(updateBlockPacket); session.getItemFrameCache().remove(position, entityId); @@ -146,14 +158,14 @@ public class ItemFrameEntity extends Entity { return true; } - private NbtMap getDefaultTag() { - NbtMapBuilder builder = NbtMap.builder(); - builder.putInt("x", bedrockPosition.getX()); - builder.putInt("y", bedrockPosition.getY()); - builder.putInt("z", bedrockPosition.getZ()); - builder.putByte("isMovable", (byte) 1); - builder.putString("id", "ItemFrame"); - return builder.build(); + private CompoundTag getDefaultTag() { + CompoundTagBuilder builder = CompoundTag.builder(); + builder.intTag("x", bedrockPosition.getX()); + builder.intTag("y", bedrockPosition.getY()); + builder.intTag("z", bedrockPosition.getZ()); + builder.byteTag("isMovable", (byte) 1); + builder.stringTag("id", "ItemFrame"); + return builder.buildRootTag(); } /** @@ -166,7 +178,7 @@ public class ItemFrameEntity extends Entity { updateBlockPacket.setBlockPosition(bedrockPosition); updateBlockPacket.setRuntimeId(bedrockRuntimeId); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); session.sendUpstreamPacket(updateBlockPacket); @@ -191,6 +203,18 @@ public class ItemFrameEntity extends Entity { return session.getItemFrameCache().getOrDefault(position, -1); } + /** + * Determines if the position contains an item frame. + * Does largely the same thing as getItemFrameEntityId, but for speed purposes is implemented separately, + * since every block destroy packet has to check for an item frame. + * @param position position of block. + * @param session GeyserSession. + * @return true if position contains item frame, false if not. + */ + public static boolean positionContainsItemFrame(GeyserSession session, Vector3i position) { + return session.getItemFrameCache().containsKey(position); + } + /** * Force-remove from the position-to-ID map so it doesn't cause conflicts. * @param session GeyserSession. diff --git a/connector/src/main/java/org/geysermc/connector/entity/ItemedFireballEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ItemedFireballEntity.java index 2b411109..e04e0411 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ItemedFireballEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ItemedFireballEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,24 +27,10 @@ package org.geysermc.connector.entity; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -public class ItemedFireballEntity extends ThrowableEntity { - private final Vector3f acceleration; +public class ItemedFireballEntity extends Entity { public ItemedFireballEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, Vector3f.ZERO, rotation); - acceleration = motion; - } - - @Override - public void tick(GeyserSession session) { - position = position.add(motion); - // TODO: While this reduces latency in position updating (needed for better fireball reflecting), - // TODO: movement is incredibly stiff. - // TODO: Only use this laggy movement for fireballs that be reflected - moveAbsoluteImmediate(session, position, rotation, false, true); - float drag = getDrag(session); - motion = motion.add(acceleration).mul(drag); + super(entityId, geyserId, entityType, position, motion, rotation); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java index a10a30a8..0bec07b0 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.entity; diff --git a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java index f38f1e6b..f5aa4a54 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,29 +26,18 @@ package org.geysermc.connector.entity; 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.AttributeData; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; + import lombok.Getter; import lombok.Setter; -import org.geysermc.connector.entity.attribute.AttributeType; + import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.utils.AttributeUtils; -import org.geysermc.connector.utils.ChunkUtils; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; @Getter @Setter @@ -68,38 +57,14 @@ public class LivingEntity extends Entity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { switch (entityMetadata.getId()) { - case 7: // blocking - byte xd = (byte) entityMetadata.getValue(); - - //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 isUsingShield = (getHand().getId() == ItemRegistry.SHIELD.getBedrockId() || - getHand().equals(ItemData.AIR) && getOffHand().getId() == ItemRegistry.SHIELD.getBedrockId()); - metadata.getFlags().setFlag(EntityFlag.USING_ITEM, (xd & 0x01) == 0x01 && !isUsingShield); - metadata.getFlags().setFlag(EntityFlag.BLOCKING, (xd & 0x01) == 0x01); - - // Riptide spin attack - metadata.getFlags().setFlag(EntityFlag.DAMAGE_NEARBY_MOBS, (xd & 0x04) == 0x04); - break; case 8: - metadata.put(EntityData.HEALTH, entityMetadata.getValue()); + metadata.put(EntityData.HEALTH, (float) entityMetadata.getValue()); break; case 9: - metadata.put(EntityData.EFFECT_COLOR, entityMetadata.getValue()); + metadata.put(EntityData.POTION_COLOR, (int) entityMetadata.getValue()); break; case 10: - metadata.put(EntityData.EFFECT_AMBIENT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); - break; - case 13: // Bed Position - Position bedPosition = (Position) entityMetadata.getValue(); - if (bedPosition != null) { - metadata.put(EntityData.BED_POSITION, Vector3i.from(bedPosition.getX(), bedPosition.getY(), bedPosition.getZ())); - if (session.getConnector().getConfig().isCacheChunks()) { - int bed = session.getConnector().getWorldManager().getBlockAt(session, bedPosition); - // Bed has to be updated, or else player is floating in the air - ChunkUtils.updateBlock(session, bed, bedPosition); - } - } + metadata.put(EntityData.POTION_AMBIENT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); break; } @@ -135,38 +100,4 @@ public class LivingEntity extends Entity { session.sendUpstreamPacket(handPacket); session.sendUpstreamPacket(offHandPacket); } - - @Override - public void updateBedrockAttributes(GeyserSession session) { - if (!valid) return; - - float maxHealth = this.attributes.containsKey(AttributeType.MAX_HEALTH) ? this.attributes.get(AttributeType.MAX_HEALTH).getValue() : getDefaultMaxHealth(); - - List attributes = new ArrayList<>(); - for (Map.Entry entry : this.attributes.entrySet()) { - if (!entry.getValue().getType().isBedrockAttribute()) - continue; - if (entry.getValue().getType() == AttributeType.HEALTH) { - // Add health attribute to properly show hearts when mounting - // TODO: Not a perfect system, since it led to respawn bugs - attributes.add(new AttributeData("minecraft:health", 0.0f, maxHealth, metadata.getFloat(EntityData.HEALTH, 20f), maxHealth)); - continue; - } - - attributes.add(AttributeUtils.getBedrockAttribute(entry.getValue())); - } - - UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket(); - updateAttributesPacket.setRuntimeEntityId(geyserId); - updateAttributesPacket.setAttributes(attributes); - session.sendUpstreamPacket(updateAttributesPacket); - } - - /** - * Used for the health visual when mounting an entity. - * @return the default maximum health for the entity. - */ - protected float getDefaultMaxHealth() { - return 20f; - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java index ed5f28d1..a67c0be5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/MinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -69,7 +69,7 @@ public class MinecartEntity extends Entity { // If the custom block should be enabled if (entityMetadata.getId() == 12) { // Needs a byte based off of Java's boolean - metadata.put(EntityData.CUSTOM_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); + metadata.put(EntityData.HAS_DISPLAY, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java index dd119f1a..1711fd38 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PaintingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +52,7 @@ public class PaintingEntity extends Entity { AddPaintingPacket addPaintingPacket = new AddPaintingPacket(); addPaintingPacket.setUniqueEntityId(geyserId); addPaintingPacket.setRuntimeEntityId(geyserId); - addPaintingPacket.setMotive(paintingName.getBedrockName()); + addPaintingPacket.setName(paintingName.getBedrockName()); addPaintingPacket.setPosition(fixOffset(true)); addPaintingPacket.setDirection(direction); session.sendUpstreamPacket(addPaintingPacket); @@ -62,11 +62,6 @@ public class PaintingEntity extends Entity { session.getConnector().getLogger().debug("Spawned painting on " + position); } - @Override - public void updateHeadLookRotation(GeyserSession session, float headYaw) { - // Do nothing, as head look messes up paintings - } - public Vector3f fixOffset(boolean toBedrock) { if (toBedrock) { Vector3f position = super.position; diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java similarity index 53% rename from connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java rename to connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index fc7b867b..aa7848da 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/player/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,40 +23,30 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.entity.player; +package org.geysermc.connector.entity; import com.github.steveice10.mc.auth.data.GameProfile; +import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.message.TextMessage; 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.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.data.entity.EntityLinkData; -import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket; -import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; -import com.nukkitx.protocol.bedrock.packet.SetEntityLinkPacket; -import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; +import com.nukkitx.protocol.bedrock.data.*; +import com.nukkitx.protocol.bedrock.packet.*; + import lombok.Getter; import lombok.Setter; -import net.kyori.adventure.text.Component; -import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.LivingEntity; -import org.geysermc.connector.entity.attribute.Attribute; -import org.geysermc.connector.entity.attribute.AttributeType; -import org.geysermc.connector.entity.living.animal.tameable.ParrotEntity; + +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.scoreboard.Team; -import org.geysermc.connector.utils.AttributeUtils; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; +import org.geysermc.connector.network.session.cache.EntityEffectCache; +import org.geysermc.connector.utils.SkinUtils; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -65,16 +55,13 @@ public class PlayerEntity extends LivingEntity { private GameProfile profile; private UUID uuid; private String username; - private boolean playerList = true; // Player is in the player list + private long lastSkinUpdate = -1; + private boolean playerList = true; + private boolean onGround; + private final EntityEffectCache effectCache; - /** - * Saves the parrot currently on the player's left shoulder; otherwise null - */ - private ParrotEntity leftParrot; - /** - * Saves the parrot currently on the player's right shoulder; otherwise null - */ - private ParrotEntity rightParrot; + private Entity leftParrot; + private Entity rightParrot; public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, EntityType.PLAYER, position, motion, rotation); @@ -82,10 +69,20 @@ public class PlayerEntity extends LivingEntity { profile = gameProfile; uuid = gameProfile.getId(); username = gameProfile.getName(); + effectCache = new EntityEffectCache(); + if (geyserId == 1) valid = true; + } + + @Override + public boolean despawnEntity(GeyserSession session) { + super.despawnEntity(session); + return !playerList; // don't remove from cache when still on playerlist } @Override public void spawnEntity(GeyserSession session) { + if (geyserId == 1) return; + AddPlayerPacket addPlayerPacket = new AddPlayerPacket(); addPlayerPacket.setUuid(uuid); addPlayerPacket.setUsername(username); @@ -96,14 +93,14 @@ public class PlayerEntity extends LivingEntity { addPlayerPacket.setMotion(motion); addPlayerPacket.setHand(hand); addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.NORMAL); - addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER); + addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.VISITOR); addPlayerPacket.setDeviceId(""); addPlayerPacket.setPlatformChatId(""); addPlayerPacket.getMetadata().putAll(metadata); long linkedEntityId = session.getEntityCache().getCachedPlayerEntityLink(entityId); if (linkedEntityId != -1) { - addPlayerPacket.getEntityLinks().add(new EntityLinkData(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLinkData.Type.RIDER, false)); + addPlayerPacket.getEntityLinks().add(new EntityLink(session.getEntityCache().getEntityByJavaId(linkedEntityId).getGeyserId(), geyserId, EntityLink.Type.RIDER, false)); } valid = true; @@ -114,14 +111,32 @@ public class PlayerEntity extends LivingEntity { } public void sendPlayer(GeyserSession session) { - if (session.getEntityCache().getPlayerEntity(uuid) == null) + if(session.getEntityCache().getPlayerEntity(uuid) == null) return; + if (getLastSkinUpdate() == -1) { + if (playerList) { + PlayerListPacket playerList = new PlayerListPacket(); + playerList.setAction(PlayerListPacket.Action.ADD); + playerList.getEntries().add(SkinUtils.buildDefaultEntry(profile, geyserId)); + session.sendUpstreamPacket(playerList); + } + } if (session.getUpstream().isInitialized() && session.getEntityCache().getEntityByGeyserId(geyserId) == null) { session.getEntityCache().spawnEntity(this); } else { spawnEntity(session); } + + if (!playerList) { + // remove from playerlist if player isn't on playerlist + GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> { + PlayerListPacket playerList = new PlayerListPacket(); + playerList.setAction(PlayerListPacket.Action.REMOVE); + playerList.getEntries().add(new PlayerListPacket.Entry(uuid)); + session.sendUpstreamPacket(playerList); + }); + } } @Override @@ -129,7 +144,7 @@ public class PlayerEntity extends LivingEntity { setPosition(position); setRotation(rotation); - setOnGround(isOnGround); + this.onGround = isOnGround; MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); movePlayerPacket.setRuntimeEntityId(geyserId); @@ -156,11 +171,7 @@ public class PlayerEntity extends LivingEntity { setRotation(rotation); this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); - // If this is the player logged in through this Geyser session - if (geyserId == 1) { - session.getCollisionManager().updatePlayerBoundingBox(position); - } - setOnGround(isOnGround); + this.onGround = isOnGround; MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); movePlayerPacket.setRuntimeEntityId(geyserId); @@ -168,17 +179,6 @@ public class PlayerEntity extends LivingEntity { movePlayerPacket.setRotation(getBedrockRotation()); movePlayerPacket.setOnGround(isOnGround); movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL); - // If the player is moved while sleeping, we have to adjust their y, so it appears - // correctly on Bedrock. This fixes GSit's lay. - if (metadata.getFlags().getFlag(EntityFlag.SLEEPING)) { - Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION); - if (bedPosition != null && (bedPosition.getY() == 0 || bedPosition.distanceSquared(position.toInt()) > 4)) { - // Force the player movement by using a teleport - movePlayerPacket.setPosition(Vector3f.from(position.getX(), position.getY() - entityType.getOffset() + 0.2f, position.getZ())); - movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT); - movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.UNKNOWN); - } - } session.sendUpstreamPacket(movePlayerPacket); if (leftParrot != null) { leftParrot.moveRelative(session, relX, relY, relZ, rotation, true); @@ -188,61 +188,9 @@ public class PlayerEntity extends LivingEntity { } } - @Override - public void updateHeadLookRotation(GeyserSession session, float headYaw) { - moveRelative(session, 0, 0, 0, Vector3f.from(rotation.getX(), rotation.getY(), 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(GeyserSession session, double moveX, double moveY, double moveZ, float yaw, float pitch, boolean isOnGround) { - moveRelative(session, moveX, moveY, moveZ, yaw, pitch, isOnGround); - if (leftParrot != null) { - leftParrot.moveRelative(session, moveX, moveY, moveZ, yaw, pitch, isOnGround); - } - if (rightParrot != null) { - rightParrot.moveRelative(session, moveX, moveY, moveZ, yaw, pitch, isOnGround); - } - } - - @Override - public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) { - super.updateRotation(session, 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(session, yaw, pitch, isOnGround); - } - if (rightParrot != null) { - rightParrot.updateRotation(session, yaw, pitch, isOnGround); - } - } - @Override public void setPosition(Vector3f position) { - setPosition(position, true); - } - - /** - * Set the player position and specify if the entity type's offset should be added. Set to false when the player - * sends us a move packet where the offset is already added - * - * @param position the new position of the Bedrock player - * @param includeOffset whether to include the offset - */ - public void setPosition(Vector3f position, boolean includeOffset) { - this.position = includeOffset ? position.add(0, entityType.getOffset(), 0) : position; + this.position = position.add(0, entityType.getOffset(), 0); } @Override @@ -250,19 +198,20 @@ public class PlayerEntity extends LivingEntity { super.updateBedrockMetadata(entityMetadata, session); if (entityMetadata.getId() == 2) { - String username = this.username; - Component name = (Component) entityMetadata.getValue(); - if (name != null) { - username = MessageTranslator.convertMessage(name); + // System.out.println(session.getScoreboardCache().getScoreboard().getObjectives().keySet()); + for (Team team : session.getScoreboardCache().getScoreboard().getTeams().values()) { + // session.getConnector().getLogger().info("team name " + team.getName()); + // session.getConnector().getLogger().info("team entities " + team.getEntities()); } - Team team = session.getWorldCache().getScoreboard().getTeamFor(username); + String username = this.username; + TextMessage name = (TextMessage) entityMetadata.getValue(); + if (name != null) { + username = MessageUtils.getBedrockMessage(name); + } + Team team = session.getScoreboardCache().getScoreboard().getTeamFor(username); if (team != null) { - String displayName = ""; - if (team.isVisibleFor(session.getPlayerEntity().getUsername())) { - displayName = MessageTranslator.toChatColor(team.getColor()) + username; - displayName = team.getCurrentData().getDisplayName(displayName); - } - metadata.put(EntityData.NAMETAG, displayName); + // session.getConnector().getLogger().info("team name es " + team.getName() + " with prefix " + team.getPrefix() + " and suffix " + team.getSuffix()); + metadata.put(EntityData.NAMETAG, team.getPrefix() + MessageUtils.toChatColor(team.getColor()) + username + team.getSuffix()); } } @@ -270,9 +219,9 @@ public class PlayerEntity extends LivingEntity { if (entityMetadata.getId() == 14) { UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); attributesPacket.setRuntimeEntityId(geyserId); - List attributes = new ArrayList<>(); + List attributes = new ArrayList<>(); // Setting to a higher maximum since plugins/datapacks can probably extend the Bedrock soft limit - attributes.add(new AttributeData("minecraft:absorption", 0.0f, 1024f, (float) entityMetadata.getValue(), 0.0f)); + attributes.add(new Attribute("minecraft:absorption", 0.0f, 1024f, (float) entityMetadata.getValue(), 0.0f)); attributesPacket.setAttributes(attributes); session.sendUpstreamPacket(attributesPacket); } @@ -281,12 +230,8 @@ public class PlayerEntity extends LivingEntity { if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) { CompoundTag tag = (CompoundTag) entityMetadata.getValue(); if (tag != null && !tag.isEmpty()) { - if ((entityMetadata.getId() == 18 && leftParrot != null) || (entityMetadata.getId() == 19 && rightParrot != null)) { - // No need to update a parrot's data when it already exists - return; - } // The parrot is a separate entity in Bedrock, but part of the player entity in Java - ParrotEntity parrot = new ParrotEntity(0, session.getEntityCache().getNextEntityId().incrementAndGet(), + Entity parrot = new Entity(0, session.getEntityCache().getNextEntityId().incrementAndGet(), EntityType.PARROT, position, motion, rotation); parrot.spawnEntity(session); parrot.getMetadata().put(EntityData.VARIANT, tag.get("Variant").getValue()); @@ -296,8 +241,8 @@ public class PlayerEntity extends LivingEntity { parrot.getMetadata().put(EntityData.RIDER_ROTATION_LOCKED, 1); parrot.updateBedrockMetadata(session); SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); - EntityLinkData.Type type = (entityMetadata.getId() == 18) ? EntityLinkData.Type.RIDER : EntityLinkData.Type.PASSENGER; - linkPacket.setEntityLink(new EntityLinkData(geyserId, parrot.getGeyserId(), type, false)); + EntityLink.Type type = (entityMetadata.getId() == 18) ? EntityLink.Type.RIDER : EntityLink.Type.PASSENGER; + linkPacket.setEntityLink(new EntityLink(geyserId, parrot.getGeyserId(), type, false)); // Delay, or else spawned-in players won't get the link // TODO: Find a better solution. This problem also exists with item frames session.getConnector().getGeneralThreadPool().schedule(() -> session.sendUpstreamPacket(linkPacket), 500, TimeUnit.MILLISECONDS); @@ -319,22 +264,4 @@ public class PlayerEntity extends LivingEntity { } } } - - @Override - public void updateBedrockAttributes(GeyserSession session) { // TODO: Don't use duplicated code - if (!valid) return; - - List attributes = new ArrayList<>(); - for (Map.Entry entry : this.attributes.entrySet()) { - if (!entry.getValue().getType().isBedrockAttribute()) - continue; - - attributes.add(AttributeUtils.getBedrockAttribute(entry.getValue())); - } - - UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket(); - updateAttributesPacket.setRuntimeEntityId(geyserId); - updateAttributesPacket.setAttributes(attributes); - session.sendUpstreamPacket(updateAttributesPacket); - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java index 143e3637..6be138c0 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/SpawnerMinecartEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.translators.world.block.BlockTranslator; diff --git a/connector/src/main/java/org/geysermc/connector/entity/TNTEntity.java b/connector/src/main/java/org/geysermc/connector/entity/TNTEntity.java index ad73c1d9..629c9e51 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/TNTEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/TNTEntity.java @@ -1,34 +1,35 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/ThrowableEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ThrowableEntity.java index 4e0c25ab..d0632d97 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/ThrowableEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/ThrowableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,124 +26,11 @@ package org.geysermc.connector.entity; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -/** - * Used as a class for any object-like entity that moves as a projectile - */ -public class ThrowableEntity extends Entity implements Tickable { - - private Vector3f lastPosition; +public class ThrowableEntity extends Entity { public ThrowableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - this.lastPosition = position; - } - - /** - * Updates the position for the Bedrock client. - * - * Java clients assume the next positions of moving items. Bedrock needs to be explicitly told positions - */ - @Override - public void tick(GeyserSession session) { - super.moveRelative(session, motion.getX(), motion.getY(), motion.getZ(), rotation, onGround); - float drag = getDrag(session); - float gravity = getGravity(); - motion = motion.mul(drag).down(gravity); - } - - protected void moveAbsoluteImmediate(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { - super.moveAbsolute(session, position, rotation, isOnGround, teleported); - } - - /** - * Get the gravity of this entity type. Used for applying gravity while the entity is in motion. - * - * @return the amount of gravity to apply to this entity while in motion. - */ - protected float getGravity() { - if (metadata.getFlags().getFlag(EntityFlag.HAS_GRAVITY)) { - switch (entityType) { - case THROWN_POTION: - case LINGERING_POTION: - return 0.05f; - case THROWN_EXP_BOTTLE: - return 0.07f; - case FIREBALL: - return 0; - case SNOWBALL: - case THROWN_EGG: - case THROWN_ENDERPEARL: - return 0.03f; - } - } - return 0; - } - - /** - * @param session the session of the Bedrock client. - * @return the drag that should be multiplied to the entity's motion - */ - protected float getDrag(GeyserSession session) { - if (isInWater(session)) { - return 0.8f; - } else { - switch (entityType) { - case THROWN_POTION: - case LINGERING_POTION: - case THROWN_EXP_BOTTLE: - case SNOWBALL: - case THROWN_EGG: - case THROWN_ENDERPEARL: - return 0.99f; - case FIREBALL: - case SMALL_FIREBALL: - case DRAGON_FIREBALL: - return 0.95f; - } - } - return 1; - } - - /** - * @param session the session of the Bedrock client. - * @return true if this entity is currently in water. - */ - protected boolean isInWater(GeyserSession session) { - if (session.getConnector().getConfig().isCacheChunks()) { - int block = session.getConnector().getWorldManager().getBlockAt(session, position.toInt()); - return block == BlockTranslator.BEDROCK_WATER_ID; - } - return false; - } - - @Override - public boolean despawnEntity(GeyserSession session) { - if (entityType == EntityType.THROWN_ENDERPEARL) { - LevelEventPacket particlePacket = new LevelEventPacket(); - particlePacket.setType(LevelEventType.PARTICLE_TELEPORT); - particlePacket.setPosition(position); - session.sendUpstreamPacket(particlePacket); - } - return super.despawnEntity(session); - } - - @Override - public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { - position = lastPosition; - super.moveRelative(session, relX, relY, relZ, rotation, isOnGround); - lastPosition = position; - } - - @Override - public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { - super.moveAbsolute(session, position, rotation, isOnGround, teleported); - lastPosition = position; } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java b/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java deleted file mode 100644 index c1f82836..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/ThrownPotionEntity.java +++ /dev/null @@ -1,77 +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.connector.entity; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -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.connector.GeyserConnector; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.Potion; - -import java.util.EnumSet; - -public class ThrownPotionEntity extends ThrowableEntity { - private static final EnumSet NON_ENCHANTED_POTIONS = EnumSet.of(Potion.WATER, Potion.MUNDANE, Potion.THICK, Potion.AWKWARD); - - public ThrownPotionEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 7 && entityMetadata.getType() == MetadataType.ITEM) { - ItemStack itemStack = (ItemStack) entityMetadata.getValue(); - ItemEntry itemEntry = ItemRegistry.getItem(itemStack); - if (itemEntry.getJavaIdentifier().endsWith("potion") && itemStack.getNbt() != null) { - Tag potionTag = itemStack.getNbt().get("Potion"); - if (potionTag instanceof StringTag) { - Potion potion = Potion.getByJavaIdentifier(((StringTag) potionTag).getValue()); - if (potion != null) { - metadata.put(EntityData.POTION_AUX_VALUE, potion.getBedrockId()); - metadata.getFlags().setFlag(EntityFlag.ENCHANTED, !NON_ENCHANTED_POTIONS.contains(potion)); - } else { - metadata.put(EntityData.POTION_AUX_VALUE, 0); - GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue()); - } - } - - boolean isLingering = itemEntry.getJavaIdentifier().equals("minecraft:lingering_potion"); - metadata.getFlags().setFlag(EntityFlag.LINGERING, isLingering); - } - } - - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java b/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java index 714a70da..def5715c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/TippedArrowEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,39 +25,12 @@ package org.geysermc.connector.entity; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.TippedArrowPotion; -/** - * Internally this is known as TippedArrowEntity but is used with tipped arrows and normal arrows - */ public class TippedArrowEntity extends AbstractArrowEntity { public TippedArrowEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - // Arrow potion effect color - if (entityMetadata.getId() == 9) { - int potionColor = (int) entityMetadata.getValue(); - // -1 means no color - if (potionColor == -1) { - metadata.remove(EntityData.CUSTOM_DISPLAY); - } else { - TippedArrowPotion potion = TippedArrowPotion.getByJavaColor(potionColor); - if (potion != null && potion.getJavaColor() != -1) { - metadata.put(EntityData.CUSTOM_DISPLAY, (byte) potion.getBedrockId()); - } else { - metadata.remove(EntityData.CUSTOM_DISPLAY); - } - } - } - super.updateBedrockMetadata(entityMetadata, session); - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java b/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java index 014c0049..7c2442b0 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/TridentEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -39,7 +39,7 @@ public class TridentEntity extends AbstractArrowEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 10) { + if (entityMetadata.getId() == 11) { metadata.getFlags().setFlag(EntityFlag.ENCHANTED, (boolean) entityMetadata.getValue()); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/WitherSkullEntity.java b/connector/src/main/java/org/geysermc/connector/entity/WitherSkullEntity.java deleted file mode 100644 index ba5b9eb5..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/WitherSkullEntity.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.connector.entity; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class WitherSkullEntity extends ItemedFireballEntity { - private boolean isCharged; - - public WitherSkullEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - protected float getDrag(GeyserSession session) { - return isCharged ? 0.73f : super.getDrag(session); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 7) { - boolean newIsCharged = (boolean) entityMetadata.getValue(); - if (newIsCharged != isCharged) { - isCharged = newIsCharged; - entityType = isCharged ? EntityType.WITHER_SKULL_DANGEROUS : EntityType.WITHER_SKULL; - despawnEntity(session); - spawnEntity(session); - } - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/attribute/Attribute.java b/connector/src/main/java/org/geysermc/connector/entity/attribute/Attribute.java index 2a2d47ba..71d25a36 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/attribute/Attribute.java +++ b/connector/src/main/java/org/geysermc/connector/entity/attribute/Attribute.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java b/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java index ccd0bcb5..2061b895 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/attribute/AttributeType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,20 +33,20 @@ import lombok.Getter; public enum AttributeType { // Universal Attributes - FOLLOW_RANGE("minecraft:generic.follow_range", "minecraft:follow_range", 0f, 2048f, 32f), - KNOCKBACK_RESISTANCE("minecraft:generic.knockback_resistance", "minecraft:knockback_resistance", 0f, 1f, 0f), - MOVEMENT_SPEED("minecraft:generic.movement_speed", "minecraft:movement", 0f, 1024f, 0.1f), - FLYING_SPEED("minecraft:generic.flying_speed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f), - ATTACK_DAMAGE("minecraft:generic.attack_damage", "minecraft:attack_damage", 0f, 2048f, 1f), - HORSE_JUMP_STRENGTH("minecraft:horse.jump_strength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f), + FOLLOW_RANGE("generic.followRange", "minecraft:follow_range", 0f, 2048f, 32f), + KNOCKBACK_RESISTANCE("generic.knockbackResistance", "minecraft:knockback_resistance", 0f, 1f, 0f), + MOVEMENT_SPEED("generic.movementSpeed", "minecraft:movement", 0f, 1024f, 0.1f), + FLYING_SPEED("generic.flyingSpeed", "minecraft:movement", 0.0f, 1024.0f, 0.4000000059604645f), + ATTACK_DAMAGE("generic.attackDamage", "minecraft:attack_damage", 0f, 2048f, 1f), + HORSE_JUMP_STRENGTH("horse.jumpStrength", "minecraft:horse.jump_strength", 0.0f, 2.0f, 0.7f), // Java Attributes - ARMOR("minecraft:generic.armor", null, 0f, 30f, 0f), - ARMOR_TOUGHNESS("minecraft:generic.armor_toughness", null, 0F, 20f, 0f), - ATTACK_KNOCKBACK("minecraft:generic.attack_knockback", null, 1.5f, Float.MAX_VALUE, 0f), - ATTACK_SPEED("minecraft:generic.attack_speed", null, 0f, 1024f, 4f), - LUCK("minecraft:generic.luck", null, -1024f, 1024f, 0f), - MAX_HEALTH("minecraft:generic.max_health", null, 0f, 1024f, 20f), + ARMOR("generic.armor", null, 0f, 30f, 0f), + ARMOR_TOUGHNESS("generic.armorToughness", null, 0F, 20f, 0f), + ATTACK_KNOCKBACK("generic.attackKnockback", null, 1.5f, Float.MAX_VALUE, 0f), + ATTACK_SPEED("generic.attackSpeed", null, 0f, 1024f, 4f), + LUCK("generic.luck", null, -1024f, 1024f, 0f), + MAX_HEALTH("generic.maxHealth", null, 0f, 1024f, 20f), // Bedrock Attributes ABSORPTION(null, "minecraft:absorption", 0f, Float.MAX_VALUE, 0f), diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/AbstractFishEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/AbstractFishEntity.java index 3b80c05f..de5fa1b5 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/AbstractFishEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/AbstractFishEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; public class AbstractFishEntity extends WaterEntity { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/AgeableEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/AgeableEntity.java index 909cb736..b90983f7 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/AgeableEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/AgeableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,8 @@ package org.geysermc.connector.entity.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/AmbientEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/AmbientEntity.java index cc5fd211..bcaf81e6 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/AmbientEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/AmbientEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java index e0f4d9a1..47faad36 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/ArmorStandEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import lombok.Getter; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.LivingEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -37,7 +36,6 @@ import org.geysermc.connector.network.session.GeyserSession; public class ArmorStandEntity extends LivingEntity { // These are used to store the state of the armour stand for use when handling invisibility - @Getter private boolean isMarker = false; private boolean isInvisible = false; private boolean isSmall = false; @@ -49,11 +47,11 @@ public class ArmorStandEntity extends LivingEntity { @Override public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { // Fake the height to be above where it is so the nametag appears in the right location for invisible non-marker armour stands - if (!isMarker && isInvisible && passengers.isEmpty()) { + if (!isMarker && isInvisible) { position = position.add(0d, entityType.getHeight() * (isSmall ? 0.55d : 1d), 0d); } - super.moveAbsolute(session, position, Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()), isOnGround, teleported); + super.moveAbsolute(session, position, rotation, isOnGround, teleported); } @Override @@ -95,10 +93,4 @@ public class ArmorStandEntity extends LivingEntity { } super.updateBedrockMetadata(entityMetadata, session); } - - @Override - public void spawnEntity(GeyserSession session) { - this.rotation = Vector3f.from(rotation.getX(), rotation.getX(), rotation.getX()); - super.spawnEntity(session); - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/BatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/BatEntity.java deleted file mode 100644 index 80b426b4..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/BatEntity.java +++ /dev/null @@ -1,48 +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.connector.entity.living; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class BatEntity extends AmbientEntity { - - public BatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { - byte xd = (byte) entityMetadata.getValue(); - metadata.getFlags().setFlag(EntityFlag.RESTING, (xd & 0x01) == 0x01); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/CreatureEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/CreatureEntity.java index e2cc5a6f..f0062f89 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/CreatureEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/CreatureEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/FlyingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/FlyingEntity.java index 6bcfe79f..ac36bed2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/FlyingEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/FlyingEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/GolemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/GolemEntity.java index 2f202ee9..c1ab2f90 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/GolemEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/GolemEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/InsentientEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/InsentientEntity.java index 90bb373f..2467dfe0 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/InsentientEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/InsentientEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +28,7 @@ package org.geysermc.connector.entity.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.github.steveice10.mc.protocol.data.game.entity.metadata.MetadataType; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.LivingEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java deleted file mode 100644 index fb2726d1..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.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.connector.entity.living; - -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class MagmaCubeEntity extends SlimeEntity { - - public MagmaCubeEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { - updateJump(session, isOnGround); - super.moveRelative(session, relX, relY, relZ, rotation, isOnGround); - } - - @Override - public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { - updateJump(session, isOnGround); - super.moveAbsolute(session, position, rotation, isOnGround, teleported); - } - - public void updateJump(GeyserSession session, boolean newOnGround) { - if (newOnGround != onGround) { - // Add the jumping effect to the magma cube - metadata.put(EntityData.CLIENT_EVENT, (byte) (newOnGround ? 1 : 2)); - updateBedrockMetadata(session); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/SlimeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/SlimeEntity.java index da088410..26106f0a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/SlimeEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/SlimeEntity.java @@ -1,33 +1,34 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.entity.living; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/SnowGolemEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/SnowGolemEntity.java deleted file mode 100644 index 144b0ed2..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/SnowGolemEntity.java +++ /dev/null @@ -1,49 +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.connector.entity.living; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class SnowGolemEntity extends GolemEntity { - - public SnowGolemEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { - byte xd = (byte) entityMetadata.getValue(); - // Handle the visibility of the pumpkin - metadata.getFlags().setFlag(EntityFlag.SHEARED, (xd & 0x10) != 0x10); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java index d4a40924..81c0eeef 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/SquidEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java index 558b061b..69afd975 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/WaterEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; public class WaterEntity extends CreatureEntity { @@ -34,6 +34,6 @@ public class WaterEntity extends CreatureEntity { public WaterEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - metadata.put(EntityData.AIR_SUPPLY, (short) 400); + metadata.put(EntityData.AIR, (short) 400); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java index fc5bc722..3e363377 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/AnimalEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java index bdffbbcd..537a1251 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/BeeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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 com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -44,23 +41,10 @@ public class BeeEntity extends AnimalEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 16) { byte xd = (byte) entityMetadata.getValue(); - // Bee is performing sting attack; trigger animation - if ((xd & 0x02) == 0x02) { - EntityEventPacket packet = new EntityEventPacket(); - packet.setRuntimeEntityId(geyserId); - packet.setType(EntityEventType.ATTACK_START); - packet.setData(0); - session.sendUpstreamPacket(packet); - } - // If the bee has stung - metadata.put(EntityData.MARK_VARIANT, (xd & 0x04) == 0x04 ? 1 : 0); + metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02); // If the bee has nectar or not metadata.getFlags().setFlag(EntityFlag.POWERED, (xd & 0x08) == 0x08); } - if (entityMetadata.getId() == 17) { - // Converting "anger time" to a boolean - metadata.getFlags().setFlag(EntityFlag.ANGRY, (int) entityMetadata.getValue() > 0); - } super.updateBedrockMetadata(entityMetadata, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java index 90514cf1..a277f8ee 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/FoxEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,8 @@ package org.geysermc.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -41,13 +41,12 @@ public class FoxEntity extends AnimalEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 16) { - metadata.put(EntityData.VARIANT, entityMetadata.getValue()); + metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue()); } if (entityMetadata.getId() == 17) { byte xd = (byte) entityMetadata.getValue(); metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01); metadata.getFlags().setFlag(EntityFlag.SNEAKING, (xd & 0x04) == 0x04); - metadata.getFlags().setFlag(EntityFlag.INTERESTED, (xd & 0x08) == 0x08); metadata.getFlags().setFlag(EntityFlag.SLEEPING, (xd & 0x20) == 0x20); } super.updateBedrockMetadata(entityMetadata, session); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java deleted file mode 100644 index 1878648b..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/HoglinEntity.java +++ /dev/null @@ -1,50 +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.connector.entity.living.animal; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.DimensionUtils; - -public class HoglinEntity extends AnimalEntity { - - public HoglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { - // Immune to zombification? - // Apply shaking effect if not in the nether and zombification is possible - metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER)); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/MooshroomEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/MooshroomEntity.java deleted file mode 100644 index 9e12f3f1..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/MooshroomEntity.java +++ /dev/null @@ -1,47 +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.connector.entity.living.animal; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class MooshroomEntity extends AnimalEntity { - - public MooshroomEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { - metadata.put(EntityData.VARIANT, entityMetadata.getValue().equals("brown") ? 1 : 0); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java index 87320838..1c5dc975 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/OcelotEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java index eec07af5..f22815c6 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PandaEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,75 +27,23 @@ package org.geysermc.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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 com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; public class PandaEntity extends AnimalEntity { - private int mainGene; - private int hiddenGene; - public PandaEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 18) { - metadata.getFlags().setFlag(EntityFlag.EATING, (int) entityMetadata.getValue() > 0); - metadata.put(EntityData.EATING_COUNTER, entityMetadata.getValue()); - if ((int) entityMetadata.getValue() != 0) { - // Particles and sound - EntityEventPacket packet = new EntityEventPacket(); - packet.setRuntimeEntityId(geyserId); - packet.setType(EntityEventType.EATING_ITEM); - packet.setData(ItemRegistry.BAMBOO.getBedrockId() << 16); - session.sendUpstreamPacket(packet); - } - } - if (entityMetadata.getId() == 19) { - mainGene = (int) (byte) entityMetadata.getValue(); - updateAppearance(); - } - if (entityMetadata.getId() == 20) { - hiddenGene = (int) (byte) entityMetadata.getValue(); - updateAppearance(); - } if (entityMetadata.getId() == 21) { byte xd = (byte) entityMetadata.getValue(); metadata.getFlags().setFlag(EntityFlag.SNEEZING, (xd & 0x02) == 0x02); - metadata.getFlags().setFlag(EntityFlag.ROLLING, (xd & 0x04) == 0x04); - metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x08) == 0x08); - // Required to put these both for sitting to actually show - metadata.put(EntityData.SITTING_AMOUNT, (xd & 0x08) == 0x08 ? 1f : 0f); - metadata.put(EntityData.SITTING_AMOUNT_PREVIOUS, (xd & 0x08) == 0x08 ? 1f : 0f); - metadata.getFlags().setFlag(EntityFlag.LAYING_DOWN, (xd & 0x10) == 0x10); + metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x04) == 0x04); } super.updateBedrockMetadata(entityMetadata, session); } - - /** - * 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 == hiddenGene) { - // Main and hidden genes match; this is what the panda looks like. - metadata.put(EntityData.VARIANT, mainGene); - } else { - // Genes have no effect on appearance - metadata.put(EntityData.VARIANT, 0); - } - } else { - // No need to worry about hidden gene - metadata.put(EntityData.VARIANT, mainGene); - } - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java index e747405b..b28ad99f 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PigEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -39,15 +39,9 @@ public class PigEntity extends AnimalEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { metadata.getFlags().setFlag(EntityFlag.SADDLED, (boolean) entityMetadata.getValue()); } super.updateBedrockMetadata(entityMetadata, session); } - - @Override - protected float getDefaultMaxHealth() { - return 10f; - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java index db658dd8..6011d513 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PolarBearEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PufferFishEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PufferFishEntity.java index 9a6a712f..d5503dc0 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/PufferFishEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/PufferFishEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.living.AbstractFishEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java index 54401411..6bc64bfd 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/RabbitEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,8 @@ package org.geysermc.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -48,15 +48,6 @@ public class RabbitEntity extends AnimalEntity { metadata.put(EntityData.SCALE, .35f); metadata.getFlags().setFlag(EntityFlag.BABY, true); } - } else if (entityMetadata.getId() == 16) { - int variant = (int) entityMetadata.getValue(); - - // Change the killer bunny to display as white since it only exists on Java Edition - if (variant == 99) { - variant = 1; - } - - metadata.put(EntityData.VARIANT, variant); } } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/SheepEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/SheepEntity.java index 37bb2fde..e2b1b979 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/SheepEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/SheepEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,8 @@ package org.geysermc.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java deleted file mode 100644 index 9ea97eb1..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/StriderEntity.java +++ /dev/null @@ -1,88 +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.connector.entity.living.animal; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class StriderEntity extends AnimalEntity { - - private boolean shaking = false; - - public StriderEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - - metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); - metadata.getFlags().setFlag(EntityFlag.BREATHING, true); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 17) { - shaking = (boolean) entityMetadata.getValue(); - } - if (entityMetadata.getId() == 18) { - metadata.getFlags().setFlag(EntityFlag.SADDLED, (boolean) entityMetadata.getValue()); - } - - super.updateBedrockMetadata(entityMetadata, session); - } - - @Override - public void updateBedrockMetadata(GeyserSession session) { - // Make sure they are not shaking when riding another entity - // Needs to copy the parent state - if (metadata.getFlags().getFlag(EntityFlag.RIDING)) { - boolean parentShaking = false; - for (Entity ent : session.getEntityCache().getEntities().values()) { - if (ent.getPassengers().contains(entityId) && ent instanceof StriderEntity) { - parentShaking = ent.getMetadata().getFlags().getFlag(EntityFlag.SHAKING); - break; - } - } - - metadata.getFlags().setFlag(EntityFlag.BREATHING, !parentShaking); - metadata.getFlags().setFlag(EntityFlag.SHAKING, parentShaking); - } else { - metadata.getFlags().setFlag(EntityFlag.BREATHING, !shaking); - metadata.getFlags().setFlag(EntityFlag.SHAKING, shaking); - } - - // Update the passengers if we have any - for (long passenger : passengers) { - Entity passengerEntity = session.getEntityCache().getEntityByJavaId(passenger); - if (passengerEntity != null) { - passengerEntity.updateBedrockMetadata(session); - } - } - - super.updateBedrockMetadata(session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/TropicalFishEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/TropicalFishEntity.java index 8d5b476a..a8866d7e 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/TropicalFishEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/TropicalFishEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import lombok.AllArgsConstructor; import lombok.Getter; import org.geysermc.connector.entity.living.AbstractFishEntity; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java deleted file mode 100644 index 9456f4d2..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/TurtleEntity.java +++ /dev/null @@ -1,49 +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.connector.entity.living.animal; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class TurtleEntity extends AnimalEntity { - - public TurtleEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 17) { - metadata.getFlags().setFlag(EntityFlag.IS_PREGNANT, (boolean) entityMetadata.getValue()); - } else if (entityMetadata.getId() == 18) { - metadata.getFlags().setFlag(EntityFlag.LAYING_EGG, (boolean) entityMetadata.getValue()); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java index 628beff1..3773011a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/AbstractHorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,24 @@ package org.geysermc.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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 com.nukkitx.protocol.bedrock.data.Attribute; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import com.nukkitx.protocol.bedrock.packet.UpdateAttributesPacket; +import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.entity.living.animal.AnimalEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.utils.AttributeUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; public class AbstractHorseEntity extends AnimalEntity { + // For updating the horse visual easier + private float health = 20f; + public AbstractHorseEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } @@ -45,36 +52,17 @@ public class AbstractHorseEntity extends AnimalEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + if (entityMetadata.getId() == 8) { + health = (float) entityMetadata.getValue(); + updateBedrockAttributes(session); + } + if (entityMetadata.getId() == 16) { byte xd = (byte) entityMetadata.getValue(); metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x02) == 0x02); metadata.getFlags().setFlag(EntityFlag.SADDLED, (xd & 0x04) == 0x04); metadata.getFlags().setFlag(EntityFlag.EATING, (xd & 0x10) == 0x10); metadata.getFlags().setFlag(EntityFlag.STANDING, (xd & 0x20) == 0x20); - - // HorseFlags - // Bred 0x10 - // Eating 0x20 - // Open mouth 0x80 - int horseFlags = 0x0; - horseFlags = (xd & 0x40) == 0x40 ? horseFlags | 0x80 : horseFlags; - - // Only set eating when we don't have mouth open so a player interaction doesn't trigger the eating animation - horseFlags = (xd & 0x10) == 0x10 && (xd & 0x40) != 0x40 ? horseFlags | 0x20 : horseFlags; - - // Set the flags into the display item - metadata.put(EntityData.DISPLAY_ITEM, horseFlags); - - // Send the eating particles - // We use the wheat metadata as static particles since Java - // doesn't send over what item was used to feed the horse - if ((xd & 0x40) == 0x40) { - EntityEventPacket entityEventPacket = new EntityEventPacket(); - entityEventPacket.setRuntimeEntityId(geyserId); - entityEventPacket.setType(EntityEventType.EATING_ITEM); - entityEventPacket.setData(ItemRegistry.WHEAT.getBedrockId() << 16); - session.sendUpstreamPacket(entityEventPacket); - } } // Needed to control horses @@ -83,4 +71,25 @@ public class AbstractHorseEntity extends AnimalEntity { super.updateBedrockMetadata(entityMetadata, session); } + + @Override + public void updateBedrockAttributes(GeyserSession session) { + if (!valid) return; + + float maxHealth = attributes.containsKey(AttributeType.MAX_HEALTH) ? attributes.get(AttributeType.MAX_HEALTH).getValue() : 20f; + + List attributesLocal = new ArrayList<>(); + for (Map.Entry entry : this.attributes.entrySet()) { + if (!entry.getValue().getType().isBedrockAttribute()) + continue; + + attributesLocal.add(AttributeUtils.getBedrockAttribute(entry.getValue())); + } + attributesLocal.add(new Attribute("minecraft:health", 0.0f, maxHealth, health, maxHealth)); + + UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket(); + updateAttributesPacket.setRuntimeEntityId(geyserId); + updateAttributesPacket.setAttributes(attributesLocal); + session.sendUpstreamPacket(updateAttributesPacket); + } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java index f67567c9..df354357 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/ChestedHorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java index c687898d..27f4b83c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/HorseEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ package org.geysermc.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -40,7 +41,7 @@ public class HorseEntity extends AbstractHorseEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 18) { - metadata.put(EntityData.VARIANT, entityMetadata.getValue()); + metadata.put(EntityData.VARIANT, (int) entityMetadata.getValue()); metadata.put(EntityData.MARK_VARIANT, (((int) entityMetadata.getValue()) >> 8) % 5); } super.updateBedrockMetadata(entityMetadata, session); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java index a04539dc..d4d7b726 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/LlamaEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,8 @@ package org.geysermc.connector.entity.living.animal.horse; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/TraderLlamaEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/TraderLlamaEntity.java index 77059ae3..b9505509 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/TraderLlamaEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/horse/TraderLlamaEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal.horse; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java index 87d70025..63a67a0a 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/CatEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,33 +27,19 @@ package org.geysermc.connector.entity.living.animal.tameable; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; public class CatEntity extends TameableEntity { - private byte collarColor; - public CatEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } - @Override - public void updateRotation(GeyserSession session, float yaw, float pitch, boolean isOnGround) { - moveRelative(session, 0, 0, 0, Vector3f.from(this.rotation.getX(), pitch, yaw), isOnGround); - } - @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - super.updateBedrockMetadata(entityMetadata, session); - if (entityMetadata.getId() == 16) { - // Update collar color if tamed - if (metadata.getFlags().getFlag(EntityFlag.TAMED)) { - metadata.put(EntityData.COLOR, collarColor); - } - } if (entityMetadata.getId() == 18) { // Different colors in Java and Bedrock for some reason int variantColor; @@ -76,11 +62,11 @@ public class CatEntity extends TameableEntity { metadata.put(EntityData.VARIANT, variantColor); } if (entityMetadata.getId() == 21) { - collarColor = (byte) (int) entityMetadata.getValue(); // Needed or else wild cats are a red color if (metadata.getFlags().getFlag(EntityFlag.TAMED)) { - metadata.put(EntityData.COLOR, collarColor); + metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue()); } } + super.updateBedrockMetadata(entityMetadata, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java index f9df03d6..e02b3e7b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/ParrotEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.animal.tameable; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/TameableEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/TameableEntity.java index 21bf0a1b..2d3e0b1d 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/TameableEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/TameableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 @@ package org.geysermc.connector.entity.living.animal.tameable; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.connector.entity.Entity; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.living.animal.AnimalEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import java.util.UUID; - public class TameableEntity extends AnimalEntity { public TameableEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { @@ -49,22 +46,11 @@ public class TameableEntity extends AnimalEntity { metadata.getFlags().setFlag(EntityFlag.SITTING, (xd & 0x01) == 0x01); metadata.getFlags().setFlag(EntityFlag.ANGRY, (xd & 0x02) == 0x02); metadata.getFlags().setFlag(EntityFlag.TAMED, (xd & 0x04) == 0x04); - } - - // Note: Must be set for wolf collar color to work - if (entityMetadata.getId() == 17) { - if (entityMetadata.getValue() != null) { - // Owner UUID of entity - Entity entity = session.getEntityCache().getPlayerEntity((UUID) entityMetadata.getValue()); - // Used as both a check since the player isn't in the entity cache and a normal fallback - if (entity == null) { - entity = session.getPlayerEntity(); - } - // Translate to entity ID - metadata.put(EntityData.OWNER_EID, entity.getGeyserId()); - } else { - metadata.put(EntityData.OWNER_EID, 0L); // Reset - } + // Must be set for wolf collar color to work + // Extending it to all entities to prevent future bugs + if (metadata.getFlags().getFlag(EntityFlag.TAMED)) { + metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId()); + } // Can't de-tame an entity so no resetting the owner ID } super.updateBedrockMetadata(entityMetadata, session); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java index 144c0fe2..118262dc 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/animal/tameable/WolfEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,24 @@ package org.geysermc.connector.entity.living.animal.tameable; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; public class WolfEntity extends TameableEntity { - private byte collarColor; - public WolfEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { + // "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head + if (entityMetadata.getId() == 18) { + metadata.getFlags().setFlag(EntityFlag.INTERESTED, (boolean) entityMetadata.getValue()); + } + //Reset wolf color if (entityMetadata.getId() == 16) { byte xd = (byte) entityMetadata.getValue(); @@ -51,28 +54,11 @@ public class WolfEntity extends TameableEntity { } } - // "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head - if (entityMetadata.getId() == 18) { - metadata.getFlags().setFlag(EntityFlag.INTERESTED, (boolean) entityMetadata.getValue()); - } - // Wolf collar color // Relies on EntityData.OWNER_EID being set in TameableEntity.java if (entityMetadata.getId() == 19 && !metadata.getFlags().getFlag(EntityFlag.ANGRY)) { - metadata.put(EntityData.COLOR, collarColor = (byte) (int) entityMetadata.getValue()); - if (!metadata.containsKey(EntityData.OWNER_EID)) { - // If a color is set and there is no owner entity ID, set one. - // Otherwise, the entire wolf is set to that color: https://user-images.githubusercontent.com/9083212/99209989-92691200-2792-11eb-911d-9a315c955be9.png - metadata.put(EntityData.OWNER_EID, session.getPlayerEntity().getGeyserId()); - } + metadata.put(EntityData.COLOR, (byte) (int) entityMetadata.getValue()); } - - // Wolf anger (1.16+) - if (entityMetadata.getId() == 20) { - metadata.getFlags().setFlag(EntityFlag.ANGRY, (int) entityMetadata.getValue() != 0); - metadata.put(EntityData.COLOR, (int) entityMetadata.getValue() != 0 ? (byte) 0 : collarColor); - } - super.updateBedrockMetadata(entityMetadata, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java index 84b6772b..ddeb31bd 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/AbstractMerchantEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 @@ package org.geysermc.connector.entity.living.merchant; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.entity.living.AgeableEntity; import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; public class AbstractMerchantEntity extends AgeableEntity { public AbstractMerchantEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } - - @Override - public void teleport(GeyserSession session, Vector3f position, float yaw, float pitch, boolean isOnGround) { - super.teleport(session, position, yaw - 180, pitch, isOnGround); - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java index d481cd0c..895f8cc1 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/merchant/VillagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,32 +26,18 @@ package org.geysermc.connector.entity.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 com.nukkitx.protocol.bedrock.data.EntityData; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class VillagerEntity extends AbstractMerchantEntity { - /** - * A map of Java profession IDs to Bedrock IDs - */ private static final Int2IntMap VILLAGER_VARIANTS = new Int2IntOpenHashMap(); - /** - * A map of all Java region IDs (plains, savanna...) to Bedrock - */ - public static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap(); + private static final Int2IntMap VILLAGER_REGIONS = new Int2IntOpenHashMap(); static { // Java villager profession IDs -> Bedrock @@ -98,60 +84,4 @@ public class VillagerEntity extends AbstractMerchantEntity { } super.updateBedrockMetadata(entityMetadata, session); } - - @Override - public void moveRelative(GeyserSession session, double relX, double relY, double relZ, Vector3f rotation, boolean isOnGround) { - int z = 0; - int bedId = 0; - float bedPositionSubtractorW = 0; - float bedPositionSubtractorN = 0; - Vector3i bedPosition = metadata.getPos(EntityData.BED_POSITION); - if (session.getConnector().getConfig().isCacheChunks() && bedPosition != null) { - bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition); - } - String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId); - setRotation(rotation); - setOnGround(isOnGround); - this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); - - MoveEntityAbsolutePacket moveEntityPacket = new MoveEntityAbsolutePacket(); - moveEntityPacket.setRuntimeEntityId(geyserId); - //Sets Villager position and rotation when sleeping - if (!metadata.getFlags().getFlag(EntityFlag.SLEEPING)) { - moveEntityPacket.setPosition(position); - moveEntityPacket.setRotation(getBedrockRotation()); - } else { - //String Setup - Pattern r = Pattern.compile("facing=([a-z]+)"); - Matcher m = r.matcher(bedRotationZ); - if (m.find()) { - switch (m.group(0)){ - case "facing=south": - //bed is facing south - z = 180; - bedPositionSubtractorW = -.5f; - break; - case "facing=east": - //bed is facing east - z = 90; - bedPositionSubtractorW = -.5f; - break; - case "facing=west": - //bed is facing west - z = 270; - bedPositionSubtractorW = .5f; - break; - case "facing=north": - //rotation does not change because north is 0 - bedPositionSubtractorN = .5f; - break; - } - } - moveEntityPacket.setRotation(Vector3f.from(0, 0, z)); - moveEntityPacket.setPosition(Vector3f.from(position.getX() + bedPositionSubtractorW, position.getY(), position.getZ() + bedPositionSubtractorN)); - } - moveEntityPacket.setOnGround(isOnGround); - moveEntityPacket.setTeleported(false); - session.sendUpstreamPacket(moveEntityPacket); - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/AbstractSkeletonEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/AbstractSkeletonEntity.java index cd07faf3..ff98d313 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/AbstractSkeletonEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/AbstractSkeletonEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,25 +25,12 @@ package org.geysermc.connector.entity.living.monster; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; public class AbstractSkeletonEntity extends MonsterEntity { public AbstractSkeletonEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 14) { - byte xd = (byte) entityMetadata.getValue(); - // A bit of a loophole so the hands get raised - set the target ID to its own ID - metadata.put(EntityData.TARGET_EID, (xd == 4) ? geyserId : 0); - } - super.updateBedrockMetadata(entityMetadata, session); - } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java deleted file mode 100644 index 0dac9207..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BasePiglinEntity.java +++ /dev/null @@ -1,50 +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.connector.entity.living.monster; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.DimensionUtils; - -public class BasePiglinEntity extends MonsterEntity { - - public BasePiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { - // Immune to zombification? - // Apply shaking effect if not in the nether and zombification is possible - metadata.getFlags().setFlag(EntityFlag.SHAKING, !((boolean) entityMetadata.getValue()) && !session.getDimension().equals(DimensionUtils.NETHER)); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BlazeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BlazeEntity.java index dcbb3935..16836976 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/BlazeEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/BlazeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java index b62337ec..9b5c3822 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/CreeperEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 +27,12 @@ package org.geysermc.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; public class CreeperEntity extends MonsterEntity { - /** - * Whether the creeper has been ignited and is using ID 17. - * In this instance we ignore ID 15 since it's sending us -1 which confuses poor Bedrock. - */ - private boolean ignitedByFlintAndSteel = false; - public CreeperEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); } @@ -46,16 +40,13 @@ public class CreeperEntity extends MonsterEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { if (entityMetadata.getId() == 15) { - if (!ignitedByFlintAndSteel) { - metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1); - } + metadata.getFlags().setFlag(EntityFlag.IGNITED, (int) entityMetadata.getValue() == 1); } if (entityMetadata.getId() == 16) { metadata.getFlags().setFlag(EntityFlag.POWERED, (boolean) entityMetadata.getValue()); } if (entityMetadata.getId() == 17) { - ignitedByFlintAndSteel = (boolean) entityMetadata.getValue(); - metadata.getFlags().setFlag(EntityFlag.IGNITED, ignitedByFlintAndSteel); + metadata.getFlags().setFlag(EntityFlag.IGNITED, (boolean) entityMetadata.getValue()); } super.updateBedrockMetadata(entityMetadata, session); diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java index bfbb74af..fedd7980 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ElderGuardianEntity.java @@ -1,32 +1,33 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.entity.living.monster; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; public class ElderGuardianEntity extends GuardianEntity { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java index 62167979..394be544 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,335 +27,60 @@ package org.geysermc.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.AttributeData; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -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.*; -import lombok.Data; -import org.geysermc.connector.entity.Tickable; -import org.geysermc.connector.entity.attribute.AttributeType; +import com.nukkitx.protocol.bedrock.data.Attribute; +import com.nukkitx.protocol.bedrock.data.EntityEventType; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import com.nukkitx.protocol.bedrock.packet.AddEntityPacket; +import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.living.InsentientEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.AttributeUtils; -import org.geysermc.connector.utils.DimensionUtils; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; -import java.util.concurrent.atomic.AtomicLong; - -public class EnderDragonEntity extends InsentientEntity implements Tickable { - /** - * The Ender Dragon has multiple hit boxes, which - * are each its own invisible entity - */ - private EnderDragonPartEntity head; - private EnderDragonPartEntity neck; - private EnderDragonPartEntity body; - private EnderDragonPartEntity leftWing; - private EnderDragonPartEntity rightWing; - private EnderDragonPartEntity[] tail; - - private EnderDragonPartEntity[] allParts; - - /** - * A circular buffer that stores a history of - * y and yaw values. - */ - private final Segment[] segmentHistory = new Segment[19]; - private int latestSegment = -1; - - private int phase; - /** - * The number of ticks since the beginning of the phase - */ - private int phaseTicks; - - private int ticksTillNextGrowl = 100; - - /** - * Used to determine when the wing flap sound should be played - */ - private float wingPosition; - private float lastWingPosition; +public class EnderDragonEntity extends InsentientEntity { public EnderDragonEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - - metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); } @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { // Phase - phase = (int) entityMetadata.getValue(); - phaseTicks = 0; - metadata.getFlags().setFlag(EntityFlag.SITTING, isSitting()); - } - - super.updateBedrockMetadata(entityMetadata, session); - - if (entityMetadata.getId() == 8) { // Health - // Update the health attribute, so that the death animation gets played - // Round health up, so that Bedrock doesn't consider the dragon to be dead when health is between 0 and 1 - float health = (float) Math.ceil(metadata.getFloat(EntityData.HEALTH)); - if (phase == 9 && health <= 0) { // Dying phase - EntityEventPacket entityEventPacket = new EntityEventPacket(); - entityEventPacket.setType(EntityEventType.ENDER_DRAGON_DEATH); - entityEventPacket.setRuntimeEntityId(geyserId); - entityEventPacket.setData(0); - session.sendUpstreamPacket(entityEventPacket); + if (entityMetadata.getId() == 15) { + metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); + switch ((int) entityMetadata.getValue()) { + // Performing breath attack + case 5: + EntityEventPacket entityEventPacket = new EntityEventPacket(); + entityEventPacket.setType(EntityEventType.DRAGON_FLAMING); + entityEventPacket.setRuntimeEntityId(geyserId); + entityEventPacket.setData(0); + session.sendUpstreamPacket(entityEventPacket); + case 6: + case 7: + metadata.getFlags().setFlag(EntityFlag.SITTING, true); + break; } - attributes.put(AttributeType.HEALTH, AttributeType.HEALTH.getAttribute(health, 200)); - updateBedrockAttributes(session); } - } - - /** - * Send an updated list of attributes to the Bedrock client. - * This is overwritten to allow the health attribute to differ from - * the health specified in the metadata. - * - * @param session GeyserSession - */ - @Override - public void updateBedrockAttributes(GeyserSession session) { - if (!valid) return; - - List attributes = new ArrayList<>(); - for (Map.Entry entry : this.attributes.entrySet()) { - if (!entry.getValue().getType().isBedrockAttribute()) - continue; - attributes.add(AttributeUtils.getBedrockAttribute(entry.getValue())); - } - - UpdateAttributesPacket updateAttributesPacket = new UpdateAttributesPacket(); - updateAttributesPacket.setRuntimeEntityId(geyserId); - updateAttributesPacket.setAttributes(attributes); - session.sendUpstreamPacket(updateAttributesPacket); + super.updateBedrockMetadata(entityMetadata, session); } @Override public void spawnEntity(GeyserSession session) { - super.spawnEntity(session); + AddEntityPacket addEntityPacket = new AddEntityPacket(); + addEntityPacket.setIdentifier("minecraft:" + entityType.name().toLowerCase()); + addEntityPacket.setRuntimeEntityId(geyserId); + addEntityPacket.setUniqueEntityId(geyserId); + addEntityPacket.setPosition(position); + addEntityPacket.setMotion(motion); + addEntityPacket.setRotation(getBedrockRotation()); + addEntityPacket.setEntityType(entityType.getType()); + addEntityPacket.getMetadata().putAll(metadata); - AtomicLong nextEntityId = session.getEntityCache().getNextEntityId(); - head = new EnderDragonPartEntity(entityId + 1, nextEntityId.incrementAndGet(), EntityType.ENDER_DRAGON_PART, 1, 1); - neck = new EnderDragonPartEntity(entityId + 2, nextEntityId.incrementAndGet(), EntityType.ENDER_DRAGON_PART, 3, 3); - body = new EnderDragonPartEntity(entityId + 3, nextEntityId.incrementAndGet(), EntityType.ENDER_DRAGON_PART, 5, 3); - leftWing = new EnderDragonPartEntity(entityId + 4, nextEntityId.incrementAndGet(), EntityType.ENDER_DRAGON_PART, 4, 2); - rightWing = new EnderDragonPartEntity(entityId + 5, nextEntityId.incrementAndGet(), EntityType.ENDER_DRAGON_PART, 4, 2); - tail = new EnderDragonPartEntity[3]; - for (int i = 0; i < 3; i++) { - tail[i] = new EnderDragonPartEntity(entityId + 6 + i, nextEntityId.incrementAndGet(), EntityType.ENDER_DRAGON_PART, 2, 2); - } + // Otherwise dragon is always 'dying' + addEntityPacket.getAttributes().add(new Attribute("minecraft:health", 0.0f, 200f, 200f, 200f)); - allParts = new EnderDragonPartEntity[]{head, neck, body, leftWing, rightWing, tail[0], tail[1], tail[2]}; + valid = true; + session.sendUpstreamPacket(addEntityPacket); - for (EnderDragonPartEntity part : allParts) { - session.getEntityCache().spawnEntity(part); - } - - for (int i = 0; i < segmentHistory.length; i++) { - segmentHistory[i] = new Segment(); - segmentHistory[i].yaw = rotation.getZ(); - segmentHistory[i].y = position.getY(); - } - } - - @Override - public boolean despawnEntity(GeyserSession session) { - for (EnderDragonPartEntity part : allParts) { - part.despawnEntity(session); - } - return super.despawnEntity(session); - } - - @Override - public void tick(GeyserSession session) { - effectTick(session); - if (!metadata.getFlags().getFlag(EntityFlag.NO_AI) && isAlive()) { - pushSegment(); - updateBoundingBoxes(session); - } - } - - /** - * Updates the positions of the Ender Dragon's multiple bounding boxes - * - * @param session GeyserSession. - */ - private void updateBoundingBoxes(GeyserSession session) { - Vector3f facingDir = Vector3f.createDirectionDeg(0, rotation.getZ()); - 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())); - float pitchXZ = (float) Math.cos(pitch); - float pitchY = (float) Math.sin(pitch); - - // Lowers the head when the dragon sits/hovers - float headDuck; - if (isHovering() || isSitting()) { - headDuck = -1f; - } else { - headDuck = baseSegment.y - getSegment(0).y; - } - - head.setPosition(facingDir.up(pitchY).mul(pitchXZ, 1, -pitchXZ).mul(6.5f).up(headDuck)); - 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 - rotation.getZ()).mul(4.5f).up(2f); - rightWing.setPosition(wingPos); - leftWing.setPosition(wingPos.mul(-1, 1, -1)); // Mirror horizontally - - Vector3f tailBase = facingDir.mul(1.5f); - for (int i = 0; i < tail.length; i++) { - float distance = (i + 1) * 2f; - // Curls the tail when the dragon turns - Segment targetSegment = getSegment(12 + 2 * i); - float angle = rotation.getZ() + 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)); - } - // Send updated positions - for (EnderDragonPartEntity part : allParts) { - part.moveAbsolute(session, part.getPosition().add(position), Vector3f.ZERO, false, false); - } - } - - /** - * Handles the particles and sounds of the Ender Dragon - * @param session GeyserSession. - */ - private void effectTick(GeyserSession session) { - Random random = ThreadLocalRandom.current(); - if (!metadata.getFlags().getFlag(EntityFlag.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"); - playSoundPacket.setPosition(position); - playSoundPacket.setVolume(5f); - playSoundPacket.setPitch(0.8f + random.nextFloat() * 0.3f); - session.sendUpstreamPacket(playSoundPacket); - } - - if (!isSitting() && !isHovering() && ticksTillNextGrowl-- == 0) { - playGrowlSound(session); - ticksTillNextGrowl = 200 + random.nextInt(200); - } - - lastWingPosition = wingPosition; - } - if (isAlive()) { - if (metadata.getFlags().getFlag(EntityFlag.NO_AI)) { - wingPosition = 0.5f; - } else if (isHovering() || isSitting()) { - wingPosition += 0.1f; - } else { - double speed = motion.length(); - wingPosition += 0.2f / (speed * 10f + 1) * Math.pow(2, motion.getY()); - } - - phaseTicks++; - if (phase == 3) { // Landing Phase - float headHeight = head.getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT); - Vector3f headCenter = head.getPosition().up(headHeight * 0.5f); - - for (int i = 0; i < 8; i++) { - Vector3f particlePos = headCenter.add(random.nextGaussian() / 2f, random.nextGaussian() / 2f, random.nextGaussian() / 2f); - // This is missing velocity information - LevelEventPacket particlePacket = new LevelEventPacket(); - particlePacket.setType(LevelEventType.PARTICLE_DRAGONS_BREATH); - particlePacket.setPosition(particlePos); - session.sendUpstreamPacket(particlePacket); - } - } else if (phase == 5) { // Sitting Flaming Phase - if (phaseTicks % 2 == 0 && phaseTicks < 10) { - // Performing breath attack - // Entity event DRAGON_FLAMING seems to create particles from the origin of the dragon, - // so we need to manually spawn particles - for (int i = 0; i < 8; i++) { - SpawnParticleEffectPacket spawnParticleEffectPacket = new SpawnParticleEffectPacket(); - 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"); - session.sendUpstreamPacket(spawnParticleEffectPacket); - } - } - } else if (phase == 7) { // Sitting Attacking Phase - playGrowlSound(session); - } else if (phase == 9) { // Dying Phase - // Send explosion particles as the dragon move towards the end portal - if (phaseTicks % 10 == 0) { - float xOffset = 8f * (random.nextFloat() - 0.5f); - float yOffset = 4f * (random.nextFloat() - 0.5f) + 2f; - float zOffset = 8f * (random.nextFloat() - 0.5f); - Vector3f particlePos = position.add(xOffset, yOffset, zOffset); - LevelEventPacket particlePacket = new LevelEventPacket(); - particlePacket.setType(LevelEventType.PARTICLE_EXPLOSION); - particlePacket.setPosition(particlePos); - session.sendUpstreamPacket(particlePacket); - } - } - } - } - - private void playGrowlSound(GeyserSession session) { - Random random = ThreadLocalRandom.current(); - PlaySoundPacket playSoundPacket = new PlaySoundPacket(); - playSoundPacket.setSound("mob.enderdragon.growl"); - playSoundPacket.setPosition(position); - playSoundPacket.setVolume(2.5f); - playSoundPacket.setPitch(0.8f + random.nextFloat() * 0.3f); - session.sendUpstreamPacket(playSoundPacket); - } - - private boolean isAlive() { - return metadata.getFloat(EntityData.HEALTH) > 0; - } - - private boolean isHovering() { - return phase == 10; - } - - private boolean isSitting() { - return phase == 5 || phase == 6 || phase == 7; - } - - /** - * Store the current yaw and y into the circular buffer - */ - private void pushSegment() { - latestSegment = (latestSegment + 1) % segmentHistory.length; - segmentHistory[latestSegment].yaw = rotation.getZ(); - segmentHistory[latestSegment].y = position.getY(); - } - - /** - * Gets the previous yaw and y - * Used to curl the tail and pitch the head and tail up/down - * - * @param index Number of ticks in the past - * @return Segment with the yaw and y - */ - private Segment getSegment(int index) { - index = (latestSegment - index) % segmentHistory.length; - if (index < 0) { - index += segmentHistory.length; - } - return segmentHistory[index]; - } - - @Data - private static class Segment { - private float yaw; - private float y; + session.getConnector().getLogger().debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")"); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonPartEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonPartEntity.java deleted file mode 100644 index 288a3e42..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonPartEntity.java +++ /dev/null @@ -1,43 +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.connector.entity.living.monster; - -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.connector.entity.Entity; -import org.geysermc.connector.entity.type.EntityType; - -public class EnderDragonPartEntity extends Entity { - public EnderDragonPartEntity(long entityId, long geyserId, EntityType entityType, float width, float height) { - super(entityId, geyserId, entityType, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO); - - metadata.put(EntityData.BOUNDING_BOX_WIDTH, width); - metadata.put(EntityData.BOUNDING_BOX_HEIGHT, height); - metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true); - metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java index 3151ae47..644181ab 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EndermanEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,11 +26,10 @@ package org.geysermc.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet; +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -45,23 +44,13 @@ public class EndermanEntity extends MonsterEntity { public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { // Held block if (entityMetadata.getId() == 15) { - metadata.put(EntityData.CARRIED_BLOCK, BlockTranslator.getBedrockBlockId((int) entityMetadata.getValue())); + metadata.put(EntityData.ENDERMAN_HELD_ITEM_ID, BlockTranslator.getBedrockBlockId((BlockState) entityMetadata.getValue())); } - // "Is screaming" - controls sound + // 'Angry' - mouth open if (entityMetadata.getId() == 16) { - if ((boolean) entityMetadata.getValue()) { - LevelSoundEvent2Packet packet = new LevelSoundEvent2Packet(); - packet.setSound(SoundEvent.STARE); - packet.setPosition(this.position); - packet.setExtraData(-1); - packet.setIdentifier("minecraft:enderman"); - session.sendUpstreamPacket(packet); - } - } - // "Is staring/provoked" - controls visuals - if (entityMetadata.getId() == 17) { metadata.getFlags().setFlag(EntityFlag.ANGRY, (boolean) entityMetadata.getValue()); } + // TODO: ID 17 is stared at but I don't believe it's used - maybe only for the sound effect. Check after particle merge super.updateBedrockMetadata(entityMetadata, session); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GhastEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GhastEntity.java deleted file mode 100644 index 69bb384a..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GhastEntity.java +++ /dev/null @@ -1,49 +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.connector.entity.living.monster; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import org.geysermc.connector.entity.living.FlyingEntity; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class GhastEntity extends FlyingEntity { - - public GhastEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { - // If the ghast is attacking - metadata.put(EntityData.CHARGE_AMOUNT, (byte) ((boolean) entityMetadata.getValue() ? 1 : 0)); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java index 65b406d5..b9dc9e66 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GiantEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.monster; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.type.EntityType; public class GiantEntity extends MonsterEntity { diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GuardianEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GuardianEntity.java index d254a329..821faa85 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/GuardianEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/GuardianEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/MonsterEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/MonsterEntity.java index 06a04d4c..0edd1b98 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/MonsterEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/MonsterEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java deleted file mode 100644 index 79402391..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/PiglinEntity.java +++ /dev/null @@ -1,69 +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.connector.entity.living.monster; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -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.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; - -public class PiglinEntity extends BasePiglinEntity { - - public PiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { - boolean isBaby = (boolean) entityMetadata.getValue(); - if (isBaby) { - metadata.put(EntityData.SCALE, .55f); - metadata.getFlags().setFlag(EntityFlag.BABY, true); - } - } - if (entityMetadata.getId() == 17) { - metadata.getFlags().setFlag(EntityFlag.CHARGING, (boolean) entityMetadata.getValue()); - } - if (entityMetadata.getId() == 18) { - metadata.getFlags().setFlag(EntityFlag.DANCING, (boolean) entityMetadata.getValue()); - } - - super.updateBedrockMetadata(entityMetadata, session); - } - - @Override - public void updateEquipment(GeyserSession session) { - // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly - metadata.getFlags().setFlag(EntityFlag.ADMIRING, offHand.getId() == ItemRegistry.GOLD.getBedrockId()); - super.updateBedrockMetadata(session); - - super.updateEquipment(session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java index f31dde69..bca9e689 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ShulkerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; 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.EntityData; import org.geysermc.connector.entity.living.GolemEntity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -53,21 +53,14 @@ public class ShulkerEntity extends GolemEntity { metadata.put(EntityData.SHULKER_ATTACH_POS, Vector3i.from(position.getX(), position.getY(), position.getZ())); } } - - if (entityMetadata.getId() == 17) { - int height = (byte) entityMetadata.getValue(); - metadata.put(EntityData.SHULKER_PEEK_ID, height); - } - + //TODO Outdated metadata flag SHULKER_PEAK_HEIGHT +// if (entityMetadata.getId() == 17) { +// int height = (byte) entityMetadata.getValue(); +// metadata.put(EntityData.SHULKER_PEAK_HEIGHT, height); +// } if (entityMetadata.getId() == 18) { - byte color = (byte) entityMetadata.getValue(); - if (color == 16) { - // 16 is default on both editions - metadata.put(EntityData.VARIANT, 16); - } else { - // Every other shulker color is offset 15 in bedrock edition - metadata.put(EntityData.VARIANT, Math.abs(color - 15)); - } + int color = Math.abs((byte) entityMetadata.getValue() - 15); + metadata.put(EntityData.VARIANT, color); } super.updateBedrockMetadata(entityMetadata, session); } diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/SpiderEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/SpiderEntity.java index 5706c1d6..301145e6 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/SpiderEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/SpiderEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/VexEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/VexEntity.java deleted file mode 100644 index cbf0c149..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/VexEntity.java +++ /dev/null @@ -1,50 +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.connector.entity.living.monster; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class VexEntity extends MonsterEntity { - - public VexEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { - byte xd = (byte) entityMetadata.getValue(); - // Set the target to the player to force the attack animation - // even if the player isn't the target as we dont get the target on Java - metadata.put(EntityData.TARGET_EID, (xd & 0x01) == 0x01 ? session.getPlayerEntity().getGeyserId() : 0); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/WitherEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/WitherEntity.java index 8dcce6a7..005d0db3 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/WitherEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/WitherEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZoglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZoglinEntity.java deleted file mode 100644 index 585a1e2c..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZoglinEntity.java +++ /dev/null @@ -1,52 +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.connector.entity.living.monster; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -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.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class ZoglinEntity extends MonsterEntity { - - public ZoglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 15) { - boolean isBaby = (boolean) entityMetadata.getValue(); - if (isBaby) { - metadata.put(EntityData.SCALE, .55f); - metadata.getFlags().setFlag(EntityFlag.BABY, true); - } - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java index f3e0fdad..2ca212ff 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,8 @@ package org.geysermc.connector.entity.living.monster; import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; 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.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java deleted file mode 100644 index c098fb5f..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieVillagerEntity.java +++ /dev/null @@ -1,56 +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.connector.entity.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.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.living.merchant.VillagerEntity; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class ZombieVillagerEntity extends ZombieEntity { - - public ZombieVillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 18) { - metadata.getFlags().setFlag(EntityFlag.IS_TRANSFORMING, (boolean) entityMetadata.getValue()); - metadata.getFlags().setFlag(EntityFlag.SHAKING, (boolean) entityMetadata.getValue()); - } - if (entityMetadata.getId() == 19) { - VillagerData villagerData = (VillagerData) entityMetadata.getValue(); - // Region - only one used on Bedrock - metadata.put(EntityData.MARK_VARIANT, VillagerEntity.VILLAGER_REGIONS.get(villagerData.getType())); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombifiedPiglinEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombifiedPiglinEntity.java deleted file mode 100644 index ad00145b..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombifiedPiglinEntity.java +++ /dev/null @@ -1,39 +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.connector.entity.living.monster; - -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; - -public class ZombifiedPiglinEntity extends ZombieEntity { - - public ZombifiedPiglinEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - - metadata.getFlags().setFlag(EntityFlag.FIRE_IMMUNE, true); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/AbstractIllagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/AbstractIllagerEntity.java index e0fa1800..b91871f0 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/AbstractIllagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/AbstractIllagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java deleted file mode 100644 index 09d28fbf..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/PillagerEntity.java +++ /dev/null @@ -1,49 +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.connector.entity.living.monster.raid; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadata; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; - -public class PillagerEntity extends AbstractIllagerEntity { - - public PillagerEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { - super(entityId, geyserId, entityType, position, motion, rotation); - } - - @Override - public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { - // Java Edition always has the Pillager entity as positioning the crossbow - metadata.getFlags().setFlag(EntityFlag.USING_ITEM, true); - metadata.getFlags().setFlag(EntityFlag.CHARGED, true); - } - super.updateBedrockMetadata(entityMetadata, session); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/RaidParticipantEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/RaidParticipantEntity.java index 15248f45..de102a6c 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/RaidParticipantEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/RaidParticipantEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/SpellcasterIllagerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/SpellcasterIllagerEntity.java index ad9f059a..6a998ddf 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/SpellcasterIllagerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/monster/raid/SpellcasterIllagerEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java deleted file mode 100644 index 24cc8c0e..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/player/SessionPlayerEntity.java +++ /dev/null @@ -1,67 +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.connector.entity.player; - -import com.github.steveice10.mc.auth.data.GameProfile; -import com.nukkitx.math.vector.Vector3f; -import org.geysermc.connector.network.session.GeyserSession; - -import java.util.UUID; - -/** - * The entity class specifically for a {@link GeyserSession}'s player. - */ -public class SessionPlayerEntity extends PlayerEntity { - - private final GeyserSession session; - - public SessionPlayerEntity(GeyserSession session) { - super(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO); - - valid = true; - this.session = session; - this.session.getCollisionManager().updatePlayerBoundingBox(position); - } - - @Override - public void spawnEntity(GeyserSession session) { - // Already logged in - } - - @Override - public void moveAbsolute(GeyserSession session, Vector3f position, Vector3f rotation, boolean isOnGround, boolean teleported) { - session.getCollisionManager().updatePlayerBoundingBox(position); - super.moveAbsolute(session, position, rotation, isOnGround, teleported); - } - - @Override - public void setPosition(Vector3f position) { - if (session != null) { // null during entity initialization - session.getCollisionManager().updatePlayerBoundingBox(position); - } - super.setPosition(position); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java deleted file mode 100644 index 97f6f15c..00000000 --- a/connector/src/main/java/org/geysermc/connector/entity/player/SkullPlayerEntity.java +++ /dev/null @@ -1,68 +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.connector.entity.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.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import lombok.Getter; -import lombok.Setter; -import org.geysermc.connector.network.session.GeyserSession; - -/** - * 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 - @Setter - private int blockState; - - public SkullPlayerEntity(GameProfile gameProfile, long geyserId, Vector3f position, Vector3f rotation) { - super(gameProfile, 0, geyserId, position, Vector3f.ZERO, rotation); - setPlayerList(false); - - //Set bounding box to almost nothing so the skull is able to be broken and not cause entity to cast a shadow - metadata.clear(); - metadata.put(EntityData.SCALE, 1.08f); - metadata.put(EntityData.BOUNDING_BOX_HEIGHT, 0.001f); - metadata.put(EntityData.BOUNDING_BOX_WIDTH, 0.001f); - metadata.getOrCreateFlags().setFlag(EntityFlag.CAN_SHOW_NAME, false); - metadata.getFlags().setFlag(EntityFlag.INVISIBLE, true); // Until the skin is loaded - } - - public void despawnEntity(GeyserSession session, Vector3i position) { - this.despawnEntity(session); - session.getSkullCache().remove(position, this); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java index e1e531f4..3acc17c3 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java +++ b/connector/src/main/java/org/geysermc/connector/entity/type/EntityType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ import org.geysermc.connector.entity.living.animal.tameable.*; import org.geysermc.connector.entity.living.merchant.*; import org.geysermc.connector.entity.living.monster.*; import org.geysermc.connector.entity.living.monster.raid.AbstractIllagerEntity; -import org.geysermc.connector.entity.living.monster.raid.PillagerEntity; import org.geysermc.connector.entity.living.monster.raid.RaidParticipantEntity; import org.geysermc.connector.entity.living.monster.raid.SpellcasterIllagerEntity; -import org.geysermc.connector.entity.player.PlayerEntity; @Getter public enum EntityType { @@ -48,12 +46,12 @@ public enum EntityType { SHEEP(SheepEntity.class, 13, 1.3f, 0.9f), WOLF(WolfEntity.class, 14, 0.85f, 0.6f), VILLAGER(VillagerEntity.class, 15, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:villager_v2"), - MOOSHROOM(MooshroomEntity.class, 16, 1.4f, 0.9f), + MOOSHROOM(AnimalEntity.class, 16, 1.4f, 0.9f), SQUID(SquidEntity.class, 17, 0.8f), RABBIT(RabbitEntity.class, 18, 0.5f, 0.4f), - BAT(BatEntity.class, 19, 0.9f, 0.5f), + BAT(AmbientEntity.class, 19, 0.9f, 0.5f), IRON_GOLEM(GolemEntity.class, 20, 2.7f, 1.4f), - SNOW_GOLEM(SnowGolemEntity.class, 21, 1.9f, 0.7f), + SNOW_GOLEM(GolemEntity.class, 21, 1.9f, 0.7f), OCELOT(OcelotEntity.class, 22, 0.35f, 0.3f), HORSE(HorseEntity.class, 23, 1.6f, 1.3965f), DONKEY(ChestedHorseEntity.class, 24, 1.6f, 1.3965f), @@ -70,15 +68,15 @@ public enum EntityType { CREEPER(CreeperEntity.class, 33, 1.7f, 0.6f, 0.6f, 1.62f), SKELETON(AbstractSkeletonEntity.class, 34, 1.8f, 0.6f, 0.6f, 1.62f), SPIDER(SpiderEntity.class, 35, 0.9f, 1.4f, 1.4f, 1f), - ZOMBIFIED_PIGLIN(ZombifiedPiglinEntity.class, 36, 1.95f, 0.6f, 0.6f, 1.62f, "minecraft:zombie_pigman"), + ZOMBIE_PIGMAN(MonsterEntity.class, 36, 1.8f, 0.6f, 0.6f, 1.62f), SLIME(SlimeEntity.class, 37, 0.51f), ENDERMAN(EndermanEntity.class, 38, 2.9f, 0.6f), SILVERFISH(MonsterEntity.class, 39, 0.3f, 0.4f), CAVE_SPIDER(MonsterEntity.class, 40, 0.5f, 0.7f), - GHAST(GhastEntity.class, 41, 4.0f), - MAGMA_CUBE(MagmaCubeEntity.class, 42, 0.51f), + GHAST(FlyingEntity.class, 41, 4.0f), + MAGMA_CUBE(SlimeEntity.class, 42, 0.51f), BLAZE(BlazeEntity.class, 43, 1.8f, 0.6f), - ZOMBIE_VILLAGER(ZombieVillagerEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:zombie_villager_v2"), + ZOMBIE_VILLAGER(ZombieEntity.class, 44, 1.8f, 0.6f, 0.6f, 1.62f), WITCH(RaidParticipantEntity.class, 45, 1.8f, 0.6f, 0.6f, 1.62f), STRAY(AbstractSkeletonEntity.class, 46, 1.8f, 0.6f, 0.6f, 1.62f), HUSK(ZombieEntity.class, 47, 1.8f, 0.6f, 0.6f, 1.62f), @@ -87,12 +85,12 @@ public enum EntityType { ELDER_GUARDIAN(ElderGuardianEntity.class, 50, 1.9975f), NPC(PlayerEntity.class, 51, 1.8f, 0.6f, 0.6f, 1.62f), WITHER(WitherEntity.class, 52, 3.5f, 0.9f), - ENDER_DRAGON(EnderDragonEntity.class, 53, 0f, 0f), + ENDER_DRAGON(EnderDragonEntity.class, 53, 4f, 13f), SHULKER(ShulkerEntity.class, 54, 1f, 1f), ENDERMITE(MonsterEntity.class, 55, 0.3f, 0.4f), AGENT(Entity.class, 56, 0f), VINDICATOR(AbstractIllagerEntity.class, 57, 1.8f, 0.6f, 0.6f, 1.62f), - PILLAGER(PillagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f), + PILLAGER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f), WANDERING_TRADER(AbstractMerchantEntity.class, 118, 1.8f, 0.6f, 0.6f, 1.62f), PHANTOM(FlyingEntity.class, 58, 0.5f, 0.9f, 0.9f, 0.6f), RAVAGER(RaidParticipantEntity.class, 59, 1.9f, 1.2f), @@ -100,7 +98,7 @@ public enum EntityType { ARMOR_STAND(ArmorStandEntity.class, 61, 1.975f, 0.5f), TRIPOD_CAMERA(Entity.class, 62, 0f), PLAYER(PlayerEntity.class, 63, 1.8f, 0.6f, 0.6f, 1.62f), - ITEM(ItemEntity.class, 64, 0.25f, 0.25f, 0.25f, 0.125f), + ITEM(ItemEntity.class, 64, 0.25f, 0.25f), PRIMED_TNT(TNTEntity.class, 65, 0.98f, 0.98f, 0.98f, 0f, "minecraft:tnt"), FALLING_BLOCK(FallingBlockEntity.class, 66, 0.98f, 0.98f), MOVING_BLOCK(Entity.class, 67, 0f), @@ -110,7 +108,7 @@ public enum EntityType { END_CRYSTAL(EnderCrystalEntity.class, 71, 2.0f, 2.0f, 2.0f, 0f, "minecraft:ender_crystal"), FIREWORK_ROCKET(FireworkEntity.class, 72, 0.25f, 0.25f, 0.25f, 0f, "minecraft:fireworks_rocket"), TRIDENT(TridentEntity.class, 73, 0f, 0f, 0f, 0f, "minecraft:thrown_trident"), - TURTLE(TurtleEntity.class, 74, 0.4f, 1.2f), + TURTLE(AnimalEntity.class, 74, 0.4f, 1.2f), CAT(CatEntity.class, 75, 0.35f, 0.3f), SHULKER_BULLET(Entity.class, 76, 0.3125f), FISHING_BOBBER(FishingHookEntity.class, 77, 0f, 0f, 0f, 0f, "minecraft:fishing_hook"), @@ -123,12 +121,12 @@ public enum EntityType { PAINTING(PaintingEntity.class, 83, 0f), MINECART(MinecartEntity.class, 84, 0.7f, 0.98f, 0.98f, 0.35f), FIREBALL(ItemedFireballEntity.class, 85, 1.0f), - THROWN_POTION(ThrownPotionEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"), + THROWN_POTION(ThrowableEntity.class, 86, 0.25f, 0.25f, 0.25f, 0f, "minecraft:splash_potion"), THROWN_ENDERPEARL(ThrowableEntity.class, 87, 0.25f, 0.25f, 0.25f, 0f, "minecraft:ender_pearl"), LEASH_KNOT(LeashKnotEntity.class, 88, 0.5f, 0.375f), - WITHER_SKULL(WitherSkullEntity.class, 89, 0.3125f), + WITHER_SKULL(Entity.class, 89, 0.3125f), BOAT(BoatEntity.class, 90, 0.7f, 1.6f, 1.6f, 0.35f), - WITHER_SKULL_DANGEROUS(WitherSkullEntity.class, 91, 0f), + WITHER_SKULL_DANGEROUS(Entity.class, 91, 0f), LIGHTNING_BOLT(Entity.class, 93, 0f), SMALL_FIREBALL(ItemedFireballEntity.class, 94, 0.3125f), AREA_EFFECT_CLOUD(AreaEffectCloudEntity.class, 95, 0.5f, 1.0f), @@ -137,12 +135,12 @@ public enum EntityType { MINECART_CHEST(MinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:chest_minecart"), MINECART_FURNACE(FurnaceMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), MINECART_SPAWNER(SpawnerMinecartEntity.class, 98, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:minecart"), - MINECART_COMMAND_BLOCK(CommandBlockMinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), + MINECART_COMMAND_BLOCK(MinecartEntity.class, 100, 0.7f, 0.98f, 0.98f, 0.35f, "minecraft:command_block_minecart"), LINGERING_POTION(ThrowableEntity.class, 101, 0f), LLAMA_SPIT(Entity.class, 102, 0.25f), EVOKER_FANGS(Entity.class, 103, 0.8f, 0.5f, 0.5f, 0f, "minecraft:evocation_fang"), EVOKER(SpellcasterIllagerEntity.class, 104, 1.95f, 0.6f, 0.6f, 0f, "minecraft:evocation_illager"), - VEX(VexEntity.class, 105, 0.8f, 0.4f), + VEX(MonsterEntity.class, 105, 0.8f, 0.4f), ICE_BOMB(Entity.class, 106, 0f), BALLOON(Entity.class, 107, 0f), //TODO PUFFERFISH(PufferFishEntity.class, 108, 0.7f, 0.7f), @@ -153,11 +151,6 @@ public enum EntityType { PANDA(PandaEntity.class, 113, 1.25f, 1.125f, 1.825f), FOX(FoxEntity.class, 121, 0.5f, 1.25f), BEE(BeeEntity.class, 122, 0.6f, 0.6f), - STRIDER(StriderEntity.class, 125, 1.7f, 0.9f, 0f, 0f, "minecraft:strider"), - HOGLIN(HoglinEntity.class, 124, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:hoglin"), - ZOGLIN(ZoglinEntity.class, 126, 1.4f, 1.3965f, 1.3965f, 0f, "minecraft:zoglin"), - PIGLIN(PiglinEntity.class, 123, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin"), - PIGLIN_BRUTE(BasePiglinEntity.class, 127, 1.95f, 0.6f, 0.6f, 0f, "minecraft:piglin_brute"), /** * Item frames are handled differently since they are a block in Bedrock. @@ -167,12 +160,7 @@ public enum EntityType { /** * Not an entity in Bedrock, so we replace it with a Pillager */ - ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager"), - - /** - * Not an entity in Bedrock, but used for the Ender Dragon's multiple hitboxes - */ - ENDER_DRAGON_PART(EnderDragonPartEntity.class, 32, 0, 0, 0, 0, "minecraft:armor_stand"); + ILLUSIONER(AbstractIllagerEntity.class, 114, 1.8f, 0.6f, 0.6f, 1.62f, "minecraft:pillager"); private static final EntityType[] VALUES = values(); diff --git a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java index 41ae994f..539fe1e2 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/Inventory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java index 4816e3c3..432ca827 100644 --- a/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java +++ b/connector/src/main/java/org/geysermc/connector/inventory/PlayerInventory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 +31,6 @@ import lombok.Setter; public class PlayerInventory extends Inventory { - /** - * Stores the held item slot, starting at index 0. - * Add 36 in order to get the network item slot. - */ @Getter @Setter private int heldItemSlot; diff --git a/connector/src/main/java/org/geysermc/connector/metrics/Metrics.java b/connector/src/main/java/org/geysermc/connector/metrics/Metrics.java index 25ae5a36..36aa32c3 100644 --- a/connector/src/main/java/org/geysermc/connector/metrics/Metrics.java +++ b/connector/src/main/java/org/geysermc/connector/metrics/Metrics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java deleted file mode 100644 index fbc7849f..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java +++ /dev/null @@ -1,69 +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.connector.network; - -import com.nukkitx.protocol.bedrock.BedrockPacketCodec; -import com.nukkitx.protocol.bedrock.v419.Bedrock_v419; -import com.nukkitx.protocol.bedrock.v422.Bedrock_v422; - -import java.util.ArrayList; -import java.util.List; - -/** - * Contains information about the supported Bedrock protocols in Geyser. - */ -public class BedrockProtocol { - /** - * 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_v422.V422_CODEC; - /** - * A list of all supported Bedrock versions that can join Geyser - */ - public static final List SUPPORTED_BEDROCK_CODECS = new ArrayList<>(); - - static { - SUPPORTED_BEDROCK_CODECS.add(Bedrock_v419.V419_CODEC.toBuilder() - .minecraftVersion("1.16.100/1.16.101") // We change this as 1.16.100.60 is a beta - .build()); - SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); - } - - /** - * Gets the {@link BedrockPacketCodec} of the given protocol version. - * @param protocolVersion The protocol version to attempt to find - * @return The packet codec, or null if the client's protocol is unsupported - */ - public static BedrockPacketCodec getBedrockCodec(int protocolVersion) { - for (BedrockPacketCodec packetCodec : SUPPORTED_BEDROCK_CODECS) { - if (packetCodec.getProtocolVersion() == protocolVersion) { - return packetCodec; - } - } - return null; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java index 87883087..29ba1567 100644 --- a/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/ConnectorServerEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 @@ package org.geysermc.connector.network; -import com.nukkitx.protocol.bedrock.BedrockPong; -import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; -import com.nukkitx.protocol.bedrock.BedrockServerSession; +import com.github.steveice10.mc.protocol.data.message.Message; +import com.nukkitx.protocol.bedrock.*; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.socket.DatagramPacket; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.ping.GeyserPingInfo; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.common.ping.GeyserPingInfo; import org.geysermc.connector.ping.IGeyserPingPassthrough; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.GeyserConfiguration; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.utils.MessageUtils; import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; public class ConnectorServerEventHandler implements BedrockServerEventHandler { @@ -51,32 +48,32 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { @Override public boolean onConnectionRequest(InetSocketAddress inetSocketAddress) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.attempt_connect", inetSocketAddress)); + connector.getLogger().info(inetSocketAddress + " tried to connect!"); return true; } @Override public BedrockPong onQuery(InetSocketAddress inetSocketAddress) { - connector.getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.pinged", inetSocketAddress)); + connector.getLogger().debug(inetSocketAddress + " has pinged you!"); GeyserConfiguration config = connector.getConfig(); GeyserPingInfo pingInfo = null; if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) { IGeyserPingPassthrough pingPassthrough = connector.getBootstrap().getGeyserPingPassthrough(); - pingInfo = pingPassthrough.getPingInformation(inetSocketAddress); + pingInfo = pingPassthrough.getPingInformation(); } BedrockPong pong = new BedrockPong(); pong.setEdition("MCPE"); pong.setGameType("Default"); pong.setNintendoLimited(false); - pong.setProtocolVersion(BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()); + pong.setProtocolVersion(GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()); pong.setVersion(null); // Server tries to connect either way and it looks better pong.setIpv4Port(config.getBedrock().getPort()); - if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) { - String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n"); + if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) { + String[] motd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n"); String mainMotd = motd[0]; // First line of the motd. String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank. @@ -88,27 +85,13 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { } if (config.isPassthroughPlayerCounts() && pingInfo != null) { - pong.setPlayerCount(pingInfo.getPlayers().getOnline()); - pong.setMaximumPlayerCount(pingInfo.getPlayers().getMax()); + pong.setPlayerCount(pingInfo.currentPlayerCount); + pong.setMaximumPlayerCount(pingInfo.maxPlayerCount); } else { pong.setPlayerCount(connector.getPlayers().size()); pong.setMaximumPlayerCount(config.getMaxPlayers()); } - // The ping will not appear if the MOTD + sub-MOTD is of a certain length. - // We don't know why, though - byte[] motdArray = pong.getMotd().getBytes(StandardCharsets.UTF_8); - if (motdArray.length + pong.getSubMotd().getBytes(StandardCharsets.UTF_8).length > 338) { - // Remove the sub-MOTD first since that only appears locally - pong.setSubMotd(""); - if (motdArray.length > 338) { - // If the top MOTD is still too long, we chop it down - byte[] newMotdArray = new byte[339]; - System.arraycopy(motdArray, 0, newMotdArray, 0, newMotdArray.length); - pong.setMotd(new String(newMotdArray, StandardCharsets.UTF_8)); - } - } - //Bedrock will not even attempt a connection if the client thinks the server is full //so we have to fake it not being full if (pong.getPlayerCount() >= pong.getMaximumPlayerCount()) { @@ -122,8 +105,16 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { public void onSessionCreation(BedrockServerSession bedrockServerSession) { bedrockServerSession.setLogging(true); bedrockServerSession.setPacketHandler(new UpstreamPacketHandler(connector, new GeyserSession(connector, bedrockServerSession))); - // Set the packet codec to default just in case we need to send disconnect packets. - bedrockServerSession.setPacketCodec(BedrockProtocol.DEFAULT_BEDROCK_CODEC); + bedrockServerSession.addDisconnectHandler(disconnectReason -> { + connector.getLogger().info("Bedrock user with ip: " + bedrockServerSession.getAddress().getAddress() + " has disconnected for reason " + disconnectReason); + + GeyserSession player = connector.getPlayers().get(bedrockServerSession.getAddress()); + if (player != null) { + player.disconnect(disconnectReason.name()); + connector.removePlayer(player); + } + }); + bedrockServerSession.setPacketCodec(GeyserConnector.BEDROCK_PACKET_CODEC); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java index eef890ed..91b3ebd4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/LoggingPacketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -132,6 +132,11 @@ public class LoggingPacketHandler implements BedrockPacketHandler { return defaultHandler(packet); } + @Override + public boolean handle(EntityFallPacket packet) { + return defaultHandler(packet); + } + @Override public boolean handle(EntityPickRequestPacket packet) { return defaultHandler(packet); @@ -623,12 +628,12 @@ public class LoggingPacketHandler implements BedrockPacketHandler { } @Override - public boolean handle(StructureTemplateDataRequestPacket packet) { + public boolean handle(StructureTemplateDataExportRequestPacket packet) { return defaultHandler(packet); } @Override - public boolean handle(StructureTemplateDataResponsePacket packet) { + public boolean handle(StructureTemplateDataExportResponsePacket packet) { return defaultHandler(packet); } @@ -751,113 +756,4 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public boolean handle(MultiplayerSettingsPacket packet) { return defaultHandler(packet); } - - // 1.16 new packets - - @Override - public boolean handle(DebugInfoPacket packet) { - return defaultHandler(packet); - } - - // I question if God exists because of this packet - God does not exist if I find out there's a built-in dab - // TODO for the future: redirect this as a /me command - // TODO for the far future: should we have a client mod that handles skins, handle these too - @Override - public boolean handle(EmoteListPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(CodeBuilderPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(CreativeContentPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(ItemStackRequestPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(LevelSoundEvent1Packet packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(ItemStackResponsePacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(PlayerArmorDamagePacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(PlayerEnchantOptionsPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(UpdatePlayerGameTypePacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(PacketViolationWarningPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(PositionTrackingDBClientRequestPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(PositionTrackingDBServerBroadcastPacket packet) { - return defaultHandler(packet); - } - - // 1.16.100 new packets - - @Override - public boolean handle(MotionPredictionHintsPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(AnimateEntityPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(CameraShakePacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(PlayerFogPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(CorrectPlayerMovePredictionPacket packet) { - return defaultHandler(packet); - } - - @Override - public boolean handle(ItemComponentPacket packet) { - return defaultHandler(packet); - } - - // 1.16.200 new packet - - @Override - public boolean handle(FilterTextPacket packet) { - return defaultHandler(packet); - } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java index 637f6d99..061e0f86 100644 --- a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java @@ -1,35 +1,37 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network; +import com.github.steveice10.mc.protocol.data.message.Message; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; -import org.geysermc.connector.common.ping.GeyserPingInfo; +import org.geysermc.common.ping.GeyserPingInfo; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -58,7 +60,6 @@ public class QueryPacketHandler { /** * The Query packet handler instance - * * @param connector Geyser Connector * @param sender The Sender IP/Port for the Query * @param buffer The Query data @@ -78,12 +79,11 @@ public class QueryPacketHandler { /** * Checks the packet is in fact a query packet - * * @param buffer Query data * @return if the packet is a query packet */ private boolean isQueryPacket(ByteBuf buffer) { - return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 0xFEFD : false; + return (buffer.readableBytes() >= 2) ? buffer.readUnsignedShort() == 65277 : false; } /** @@ -130,7 +130,6 @@ public class QueryPacketHandler { /** * Gets the game data for the query - * * @return the game data for the query */ private byte[] getGameData() { @@ -140,14 +139,13 @@ public class QueryPacketHandler { String motd; String currentPlayerCount; String maxPlayerCount; - String map; if (connector.getConfig().isPassthroughMotd() || connector.getConfig().isPassthroughPlayerCounts()) { pingInfo = connector.getBootstrap().getGeyserPingPassthrough().getPingInformation(); } if (connector.getConfig().isPassthroughMotd() && pingInfo != null) { - String[] javaMotd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n"); + String[] javaMotd = MessageUtils.getBedrockMessage(Message.fromString(pingInfo.motd)).split("\n"); motd = javaMotd[0].trim(); // First line of the motd. } else { motd = connector.getConfig().getBedrock().getMotd1(); @@ -155,28 +153,21 @@ public class QueryPacketHandler { // If passthrough player counts is enabled lets get players from the server if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) { - currentPlayerCount = String.valueOf(pingInfo.getPlayers().getOnline()); - maxPlayerCount = String.valueOf(pingInfo.getPlayers().getMax()); + currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount); + maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount); } else { currentPlayerCount = String.valueOf(connector.getPlayers().size()); maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers()); } - // If passthrough protocol name is enabled let's get the protocol name from the ping response. - if (connector.getConfig().isPassthroughProtocolName() && pingInfo != null) { - map = String.valueOf((pingInfo.getVersion().getName())); - } else { - map = GeyserConnector.NAME; - } - // Create a hashmap of all game data needed in the query Map gameData = new HashMap(); gameData.put("hostname", motd); gameData.put("gametype", "SMP"); gameData.put("game_id", "MINECRAFT"); - gameData.put("version", GeyserConnector.NAME + " (" + GeyserConnector.GIT_VERSION + ") " + BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); + gameData.put("version", GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()); gameData.put("plugins", ""); - gameData.put("map", map); + gameData.put("map", GeyserConnector.NAME); gameData.put("numplayers", currentPlayerCount); gameData.put("maxplayers", maxPlayerCount); gameData.put("hostport", String.valueOf(connector.getConfig().getBedrock().getPort())); @@ -186,7 +177,7 @@ public class QueryPacketHandler { // Blank Buffer Bytes query.write("GeyserMC".getBytes()); query.write((byte) 0x00); - query.write((byte) 0x80); + query.write((byte) 128); query.write((byte) 0x00); // Fills the game data @@ -198,7 +189,7 @@ public class QueryPacketHandler { } // Final byte to show the end of the game data - query.write(new byte[] { 0x00, 0x01 }); + query.write(new byte[]{0x00, 0x01}); return query.toByteArray(); } catch (IOException e) { e.printStackTrace(); @@ -206,11 +197,6 @@ public class QueryPacketHandler { } } - /** - * Generate a byte[] storing the player names - * - * @return The byte[] representation of players - */ private byte[] getPlayers() { ByteArrayOutputStream query = new ByteArrayOutputStream(); @@ -222,11 +208,11 @@ public class QueryPacketHandler { try { // Start the player section query.write("player_".getBytes()); - query.write(new byte[] { 0x00, 0x00 }); + query.write(new byte[]{0x00, 0x00}); // Fill player names if(pingInfo != null) { - for (String username : pingInfo.getPlayerList()) { + for (String username : pingInfo.getPlayers()) { query.write(username.getBytes()); query.write((byte) 0x00); } @@ -243,7 +229,6 @@ public class QueryPacketHandler { /** * Sends a packet to the sender - * * @param data packet data */ private void sendPacket(ByteBuf data) { @@ -266,28 +251,18 @@ public class QueryPacketHandler { * Gets an MD5 token for the current IP/Port. * This should reset every 30 seconds but a new one is generated per instance * Seems wasteful to code something in to clear it when it has no use. - * * @param token the token * @param address the address * @return an MD5 token for the current IP/Port */ public static byte[] getTokenString(byte[] token, InetAddress address) { try { - // Generate an MD5 hash from the address MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(address.toString().getBytes(StandardCharsets.UTF_8)); digest.update(token); - - // Get the first 4 bytes of the digest - byte[] digestBytes = Arrays.copyOf(digest.digest(), 4); - - // Convert the bytes to a buffer - ByteBuffer byteBuffer = ByteBuffer.wrap(digestBytes); - - // Turn the number into a null terminated string - return (byteBuffer.getInt() + "\0").getBytes(); + return Arrays.copyOf(digest.digest(), 4); } catch (NoSuchAlgorithmException e) { - return (ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).getInt() + "\0").getBytes(); + return ByteBuffer.allocate(4).putInt(ThreadLocalRandom.current().nextInt()).array(); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java index 7ebfaeda..67862d0e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/UpstreamPacketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 +26,13 @@ package org.geysermc.connector.network; import com.nukkitx.protocol.bedrock.BedrockPacket; -import com.nukkitx.protocol.bedrock.data.ResourcePackType; -import com.nukkitx.protocol.bedrock.BedrockPacketCodec; import com.nukkitx.protocol.bedrock.packet.*; +import org.geysermc.common.AuthType; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.cache.AdvancementsCache; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; -import org.geysermc.connector.utils.*; - -import java.io.FileInputStream; -import java.io.InputStream; +import org.geysermc.connector.utils.LoginEncryptionUtils; public class UpstreamPacketHandler extends LoggingPacketHandler { @@ -52,22 +46,14 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public boolean handle(LoginPacket loginPacket) { - BedrockPacketCodec packetCodec = BedrockProtocol.getBedrockCodec(loginPacket.getProtocolVersion()); - if (packetCodec == null) { - if (loginPacket.getProtocolVersion() > BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { - // Too early to determine session locale - session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.outdated.server", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); - session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.server", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); - return true; - } else if (loginPacket.getProtocolVersion() < BedrockProtocol.DEFAULT_BEDROCK_CODEC.getProtocolVersion()) { - session.getConnector().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.outdated.client", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); - session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.outdated.client", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); - return true; - } + if (loginPacket.getProtocolVersion() > GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) { + session.disconnect("Outdated Geyser proxy! I'm still on " + GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()); + return true; + } else if (loginPacket.getProtocolVersion() < GeyserConnector.BEDROCK_PACKET_CODEC.getProtocolVersion()) { + session.disconnect("Outdated Bedrock client! Please use " + GeyserConnector.BEDROCK_PACKET_CODEC.getMinecraftVersion()); + return true; } - session.getUpstream().getSession().setPacketCodec(packetCodec); - LoginEncryptionUtils.encryptPlayerConnection(connector, session, loginPacket); PlayStatusPacket playStatus = new PlayStatusPacket(); @@ -75,13 +61,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.sendUpstreamPacket(playStatus); ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket(); - for(ResourcePack resourcePack : ResourcePack.PACKS.values()) { - ResourcePackManifest.Header header = resourcePack.getManifest().getHeader(); - resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry( - header.getUuid().toString(), header.getVersionString(), resourcePack.getFile().length(), - "", "", "", false, false)); - } - resourcePacksInfo.setForcedToAccept(GeyserConnector.getInstance().getConfig().isForceResourcePacks()); session.sendUpstreamPacket(resourcePacksInfo); return true; } @@ -91,44 +70,15 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { switch (packet.getStatus()) { case COMPLETED: session.connect(connector.getRemoteServer()); - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.connect", session.getAuthData().getName())); + connector.getLogger().info("Player connected with username " + session.getAuthData().getName()); break; - - case SEND_PACKS: - for(String id : packet.getPackIds()) { - ResourcePackDataInfoPacket data = new ResourcePackDataInfoPacket(); - String[] packID = id.split("_"); - ResourcePack pack = ResourcePack.PACKS.get(packID[0]); - ResourcePackManifest.Header header = pack.getManifest().getHeader(); - - data.setPackId(header.getUuid()); - int chunkCount = (int) Math.ceil((int) pack.getFile().length() / (double) ResourcePack.CHUNK_SIZE); - data.setChunkCount(chunkCount); - data.setCompressedPackSize(pack.getFile().length()); - data.setMaxChunkSize(ResourcePack.CHUNK_SIZE); - data.setHash(pack.getSha256()); - data.setPackVersion(packID[1]); - data.setPremium(false); - data.setType(ResourcePackType.RESOURCE); - - session.sendUpstreamPacket(data); - } - break; - case HAVE_ALL_PACKS: - ResourcePackStackPacket stackPacket = new ResourcePackStackPacket(); - stackPacket.setExperimentsPreviouslyToggled(false); - stackPacket.setForcedToAccept(false); // Leaving this as false allows the player to choose to download or not - stackPacket.setGameVersion(session.getClientData().getGameVersion()); - - for (ResourcePack pack : ResourcePack.PACKS.values()) { - ResourcePackManifest.Header header = pack.getManifest().getHeader(); - stackPacket.getResourcePacks().add(new ResourcePackStackPacket.Entry(header.getUuid().toString(), header.getVersionString(), "")); - } - - session.sendUpstreamPacket(stackPacket); + ResourcePackStackPacket stack = new ResourcePackStackPacket(); + stack.setExperimental(false); + stack.setForcedToAccept(false); + stack.setGameVersion("*"); + session.sendUpstreamPacket(stack); break; - default: session.disconnect("disconnectionScreen.resourcePack"); break; @@ -139,21 +89,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public boolean handle(ModalFormResponsePacket packet) { - switch (packet.getFormId()) { - case AdvancementsCache.ADVANCEMENT_INFO_FORM_ID: - return session.getAdvancementsCache().handleInfoForm(packet.getFormData()); - case AdvancementsCache.ADVANCEMENTS_LIST_FORM_ID: - return session.getAdvancementsCache().handleListForm(packet.getFormData()); - case AdvancementsCache.ADVANCEMENTS_MENU_FORM_ID: - return session.getAdvancementsCache().handleMenuForm(packet.getFormData()); - case SettingsUtils.SETTINGS_FORM_ID: - return SettingsUtils.handleSettingsForm(session, packet.getFormData()); - case StatisticsUtils.STATISTICS_LIST_FORM_ID: - return StatisticsUtils.handleListForm(session, packet.getFormData()); - case StatisticsUtils.STATISTICS_MENU_FORM_ID: - return StatisticsUtils.handleMenuForm(session, packet.getFormData()); - } - return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData()); } @@ -162,8 +97,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { GeyserConfiguration.IUserAuthenticationInfo info = connector.getConfig().getUserAuths().get(bedrockUsername); if (info != null) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().getName())); - session.setMicrosoftAccount(info.isMicrosoftAccount()); + connector.getLogger().info("using stored credentials for bedrock user " + session.getAuthData().getName()); session.authenticate(info.getEmail(), info.getPassword()); // TODO send a message to bedrock user telling them they are connected (if nothing like a motd @@ -177,8 +111,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public boolean handle(SetLocalPlayerAsInitializedPacket packet) { - LanguageUtils.loadGeyserLocale(session.getLocale()); - if (!session.isLoggedIn() && !session.isLoggingIn() && session.getConnector().getAuthType() == AuthType.ONLINE) { // TODO it is safer to key authentication on something that won't change (UUID, not username) if (!couldLoginUserByName(session.getAuthData().getName())) { @@ -192,13 +124,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public boolean handle(MovePlayerPacket packet) { if (session.isLoggingIn()) { - SetTitlePacket titlePacket = new SetTitlePacket(); - titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - titlePacket.setText(LanguageUtils.getPlayerLocaleString("geyser.auth.login.wait", session.getLocale())); - titlePacket.setFadeInTime(0); - titlePacket.setFadeOutTime(1); - titlePacket.setStayTime(2); - session.sendUpstreamPacket(titlePacket); + session.sendMessage("Please wait until you are logged in..."); } return translateAndDefault(packet); @@ -208,30 +134,4 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { boolean defaultHandler(BedrockPacket packet) { return translateAndDefault(packet); } - - @Override - public boolean handle(ResourcePackChunkRequestPacket packet) { - ResourcePackChunkDataPacket data = new ResourcePackChunkDataPacket(); - ResourcePack pack = ResourcePack.PACKS.get(packet.getPackId().toString()); - - data.setChunkIndex(packet.getChunkIndex()); - data.setProgress(packet.getChunkIndex() * ResourcePack.CHUNK_SIZE); - data.setPackVersion(packet.getPackVersion()); - data.setPackId(packet.getPackId()); - - int offset = packet.getChunkIndex() * ResourcePack.CHUNK_SIZE; - byte[] packData = new byte[(int) MathUtils.constrain(pack.getFile().length() - offset, 0, ResourcePack.CHUNK_SIZE)]; - - try (InputStream inputStream = new FileInputStream(pack.getFile())) { - inputStream.skip(offset); - inputStream.read(packData, 0, packData.length); - } catch (Exception e) { - e.printStackTrace(); - } - - data.setData(packData); - - session.sendUpstreamPacket(data); - return true; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/remote/RemoteServer.java b/connector/src/main/java/org/geysermc/connector/network/remote/RemoteServer.java index b957b90d..c65301d0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/remote/RemoteServer.java +++ b/connector/src/main/java/org/geysermc/connector/network/remote/RemoteServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 5b43fec0..0607bb3a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/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-2020 GeyserMC. http://geysermc.org * * 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,69 +26,54 @@ package org.geysermc.connector.network.session; 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; -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.data.SubProtocol; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.statistic.Statistic; -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.mc.protocol.packet.handshake.client.HandshakePacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientTeleportConfirmPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket; import com.github.steveice10.mc.protocol.packet.login.server.LoginSuccessPacket; -import com.github.steveice10.packetlib.BuiltinFlags; import com.github.steveice10.packetlib.Client; import com.github.steveice10.packetlib.event.session.*; import com.github.steveice10.packetlib.packet.Packet; import com.github.steveice10.packetlib.tcp.TcpSessionFactory; import com.nukkitx.math.GenericMath; +import com.nukkitx.math.TrigMath; import com.nukkitx.math.vector.*; 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.ContainerId; +import com.nukkitx.protocol.bedrock.data.GamePublishSetting; +import com.nukkitx.protocol.bedrock.data.GameRuleData; +import com.nukkitx.protocol.bedrock.data.PlayerPermission; import com.nukkitx.protocol.bedrock.packet.*; -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.Long2ObjectMaps; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2LongMap; import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; -import it.unimi.dsi.fastutil.objects.ObjectIterator; import lombok.Getter; -import lombok.NonNull; import lombok.Setter; -import org.geysermc.common.window.CustomFormWindow; +import org.geysermc.common.AuthType; import org.geysermc.common.window.FormWindow; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.command.CommandSender; -import org.geysermc.connector.common.AuthType; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.player.SessionPlayerEntity; -import org.geysermc.connector.entity.player.SkullPlayerEntity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.remote.RemoteServer; import org.geysermc.connector.network.session.auth.AuthData; import org.geysermc.connector.network.session.auth.BedrockClientData; import org.geysermc.connector.network.session.cache.*; +import org.geysermc.connector.network.translators.world.WorldBorder; import org.geysermc.connector.network.translators.BiomeTranslator; import org.geysermc.connector.network.translators.EntityIdentifierRegistry; import org.geysermc.connector.network.translators.PacketTranslatorRegistry; -import org.geysermc.connector.network.translators.chat.MessageTranslator; -import org.geysermc.connector.network.translators.collision.CollisionManager; -import org.geysermc.connector.network.translators.inventory.EnchantmentInventoryTranslator; import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.skin.SkinManager; -import org.geysermc.connector.utils.*; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.utils.ChunkUtils; +import org.geysermc.connector.utils.LocaleUtils; +import org.geysermc.connector.utils.SkinUtils; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.EncryptionUtil; @@ -97,10 +82,8 @@ import java.net.InetSocketAddress; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; @Getter public class GeyserSession implements CommandSender { @@ -114,30 +97,16 @@ public class GeyserSession implements CommandSender { @Setter private BedrockClientData clientData; - @Deprecated - @Setter - private boolean microsoftAccount; - - private final SessionPlayerEntity playerEntity; + private PlayerEntity playerEntity; private PlayerInventory inventory; - private AdvancementsCache advancementsCache; - private BookEditCache bookEditCache; private ChunkCache chunkCache; private EntityCache entityCache; - private EntityEffectCache effectCache; private InventoryCache inventoryCache; - private WorldCache worldCache; + private ScoreboardCache scoreboardCache; private WindowCache windowCache; - private final Int2ObjectMap teleportMap = new Int2ObjectOpenHashMap<>(); - - /** - * Stores session collision - */ - private final CollisionManager collisionManager; - - private final Map skullCache = new ConcurrentHashMap<>(); - private final Long2ObjectMap storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); + @Setter + private TeleportCache teleportCache; /** * A map of Vector3i positions to Java entity IDs. @@ -145,6 +114,8 @@ public class GeyserSession implements CommandSender { */ private final Object2LongMap itemFrameCache = new Object2LongOpenHashMap<>(); + private DataCache javaPacketCache; + @Setter private Vector2i lastChunkPosition = null; private int renderDistance; @@ -159,12 +130,9 @@ public class GeyserSession implements CommandSender { @Setter private GameMode gameMode = GameMode.SURVIVAL; - /** - * Keeps track of the world name for respawning. - */ - @Setter - private String worldName = null; + private final AtomicInteger pendingDimSwitches = new AtomicInteger(0); + @Setter private boolean sneaking; @Setter @@ -173,15 +141,8 @@ public class GeyserSession implements CommandSender { @Setter private boolean jumping; - /** - * The dimension of the player. - * As all entities are in the same world, this can be safely applied to all other entities. - */ @Setter - private String dimension = DimensionUtils.OVERWORLD; - - @Setter - private int breakingBlock; + private BlockState breakingBlock; @Setter private Vector3i lastBlockPlacePosition; @@ -192,13 +153,13 @@ public class GeyserSession implements CommandSender { @Setter private boolean interacting; - /** - * Stores the last position of the block the player interacted with. This can either be a block that the client - * placed or an existing block the player interacted with (for example, a chest).
- * Initialized as (0, 0, 0) so it is always not-null. - */ @Setter - private Vector3i lastInteractionPosition = Vector3i.ZERO; + private Vector3i lastInteractionPosition; + + @Setter + private boolean switchingDimension = false; + private boolean manyDimPackets = false; + private ServerRespawnPacket lastDimPacket = null; @Setter private Entity ridingVehicleEntity; @@ -206,233 +167,77 @@ public class GeyserSession implements CommandSender { @Setter private int craftSlot = 0; + @Setter + private WorldBorder worldBorder; @Setter private long lastWindowCloseTime = 0; - @Setter - private VillagerTrade[] villagerTrades; - @Setter - private long lastInteractedVillagerEid; - - /** - * Stores the enchantment information the client has received if they are in an enchantment table GUI - */ - private final EnchantmentInventoryTranslator.EnchantmentSlotData[] enchantmentSlotData = new EnchantmentInventoryTranslator.EnchantmentSlotData[3]; - - /** - * The current attack speed of the player. Used for sending proper cooldown timings. - * Setting a default fixes cooldowns not showing up on a fresh world. - */ - @Setter - private double attackSpeed = 4.0d; - /** - * The time of the last hit. Used to gauge how long the cooldown is taking. - * This is a session variable in order to prevent more scheduled threads than necessary. - */ - @Setter - private long lastHitTime; - - /** - * Saves if the client is steering left on a boat. - */ - @Setter - private boolean steeringLeft; - /** - * Saves if the client is steering right on a boat. - */ - @Setter - private boolean steeringRight; - - /** - * Store the last time the player interacted. Used to fix a right-click spam bug. - * See https://github.com/GeyserMC/Geyser/issues/503 for context. - */ - @Setter - private long lastInteractionTime; - - /** - * Stores a future interaction to place a bucket. Will be cancelled if the client instead intended to - * interact with a block. - */ - @Setter - private ScheduledFuture bucketScheduledFuture; - - /** - * Used to send a movement packet every three seconds if the player hasn't moved. Prevents timeouts when AFK in certain instances. - */ - @Setter - private long lastMovementTimestamp = System.currentTimeMillis(); - - /** - * Controls whether the daylight cycle gamerule has been sent to the client, so the sun/moon remain motionless. - */ - private boolean daylightCycle = true; - - private boolean reducedDebugInfo = false; - - @Setter - private CustomFormWindow settingsForm; - - /** - * The op permission level set by the server - */ - @Setter - private int opPermissionLevel = 0; - - /** - * If the current player can fly - */ - @Setter - private boolean canFly = false; - - /** - * If the current player is flying - */ - @Setter - private boolean flying = false; - - /** - * If the current player is in noclip - */ - @Setter - private boolean noClip = false; - - /** - * If the current player can not interact with the world - */ - @Setter - private boolean worldImmutable = false; - - /** - * Caches current rain status. - */ - @Setter - private boolean raining = false; - - /** - * Caches current thunder status. - */ - @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. - */ - private final Map statistics = new HashMap<>(); - - /** - * Whether we're expecting statistics to be sent back to us. - */ - @Setter - private boolean waitingForStatistics = false; - - @Setter - private List selectedEmotes = new ArrayList<>(); - private final Set emotes = new HashSet<>(); - - /** - * The thread that will run every 50 milliseconds - one Minecraft tick. - */ - private ScheduledFuture tickThread = null; - private MinecraftProtocol protocol; public GeyserSession(GeyserConnector connector, BedrockServerSession bedrockServerSession) { this.connector = connector; this.upstream = new UpstreamSession(bedrockServerSession); - this.advancementsCache = new AdvancementsCache(this); - this.bookEditCache = new BookEditCache(this); this.chunkCache = new ChunkCache(this); this.entityCache = new EntityCache(this); - this.effectCache = new EntityEffectCache(); this.inventoryCache = new InventoryCache(this); - this.worldCache = new WorldCache(this); + this.scoreboardCache = new ScoreboardCache(this); this.windowCache = new WindowCache(this); - this.collisionManager = new CollisionManager(this); - - this.playerEntity = new SessionPlayerEntity(this); + this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "unknown"), 1, 1, Vector3f.ZERO, Vector3f.ZERO, Vector3f.ZERO); this.inventory = new PlayerInventory(); + this.javaPacketCache = new DataCache<>(); + this.spawned = false; this.loggedIn = false; this.inventoryCache.getInventories().put(0, inventory); - - connector.getPlayers().forEach(player -> this.emotes.addAll(player.getEmotes())); - - bedrockServerSession.addDisconnectHandler(disconnectReason -> { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.disconnect", bedrockServerSession.getAddress().getAddress(), disconnectReason)); - - disconnect(disconnectReason.name()); - connector.removePlayer(this); - }); } public void connect(RemoteServer remoteServer) { startGame(); this.remoteServer = remoteServer; - // Set the hardcoded shield ID to the ID we just defined in StartGamePacket - upstream.getSession().getHardcodedBlockingId().set(ItemRegistry.SHIELD.getBedrockId()); - ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket(); - biomeDefinitionListPacket.setDefinitions(BiomeTranslator.BIOMES); + biomeDefinitionListPacket.setTag(BiomeTranslator.BIOMES); upstream.sendPacket(biomeDefinitionListPacket); AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); - entityPacket.setIdentifiers(EntityIdentifierRegistry.ENTITY_IDENTIFIERS); + entityPacket.setTag(EntityIdentifierRegistry.ENTITY_IDENTIFIERS); upstream.sendPacket(entityPacket); - CreativeContentPacket creativePacket = new CreativeContentPacket(); + InventoryContentPacket creativePacket = new InventoryContentPacket(); + creativePacket.setContainerId(ContainerId.CREATIVE); creativePacket.setContents(ItemRegistry.CREATIVE_ITEMS); upstream.sendPacket(creativePacket); PlayStatusPacket playStatusPacket = new PlayStatusPacket(); playStatusPacket.setStatus(PlayStatusPacket.Status.PLAYER_SPAWN); upstream.sendPacket(playStatusPacket); + } - UpdateAttributesPacket attributesPacket = new UpdateAttributesPacket(); - attributesPacket.setRuntimeEntityId(getPlayerEntity().getGeyserId()); - List attributes = new ArrayList<>(); - // Default move speed - // Bedrock clients move very fast by default until they get an attribute packet correcting the speed - attributes.add(new AttributeData("minecraft:movement", 0.0f, 1024f, 0.1f, 0.1f)); - attributesPacket.setAttributes(attributes); - upstream.sendPacket(attributesPacket); - - GameRulesChangedPacket gamerulePacket = new GameRulesChangedPacket(); - // Only allow the server to send health information - // Setting this to false allows natural regeneration to work false but doesn't break it being true - gamerulePacket.getGameRules().add(new GameRuleData<>("naturalregeneration", false)); - // Don't let the client modify the inventory on death - // Setting this to true allows keep inventory to work if enabled but doesn't break functionality being false - gamerulePacket.getGameRules().add(new GameRuleData<>("keepinventory", true)); - // Ensure client doesn't try and do anything funky; the server handles this for us - gamerulePacket.getGameRules().add(new GameRuleData<>("spawnradius", 0)); - upstream.sendPacket(gamerulePacket); + public void fetchOurSkin(PlayerListPacket.Entry entry) { + PlayerSkinPacket playerSkinPacket = new PlayerSkinPacket(); + playerSkinPacket.setUuid(authData.getUUID()); + playerSkinPacket.setSkin(entry.getSkin()); + playerSkinPacket.setOldSkinName("OldName"); + playerSkinPacket.setNewSkinName("NewName"); + playerSkinPacket.setTrustedSkin(true); + upstream.sendPacket(playerSkinPacket); + getConnector().getLogger().debug("Sending skin for " + playerEntity.getUsername() + " " + authData.getUUID()); } public void login() { if (connector.getAuthType() != AuthType.ONLINE) { - if (connector.getAuthType() == AuthType.OFFLINE) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.offline")); - } else { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.floodgate")); - } + connector.getLogger().info( + "Attempting to login using " + connector.getAuthType().name().toLowerCase() + " mode... " + + (connector.getAuthType() == AuthType.OFFLINE ? + "authentication is disabled." : "authentication will be encrypted" + ) + ); authenticate(authData.getName()); } } @@ -443,7 +248,7 @@ public class GeyserSession implements CommandSender { public void authenticate(String username, String password) { if (loggedIn) { - connector.getLogger().severe(LanguageUtils.getLocaleStringLog("geyser.auth.already_loggedin", username)); + connector.getLogger().severe(username + " is already logged in!"); return; } @@ -452,222 +257,140 @@ public class GeyserSession implements CommandSender { new Thread(() -> { try { if (password != null && !password.isEmpty()) { - AuthenticationService authenticationService; - if (microsoftAccount) { - authenticationService = new MsaAuthenticationService(GeyserConnector.OAUTH_CLIENT_ID); - } else { - authenticationService = new MojangAuthenticationService(); - } - authenticationService.setUsername(username); - authenticationService.setPassword(password); - authenticationService.login(); - - protocol = new MinecraftProtocol(authenticationService); + protocol = new MinecraftProtocol(username, password); } else { protocol = new MinecraftProtocol(username); } - connectDownstream(); - } catch (InvalidCredentialsException | IllegalArgumentException e) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.invalid", username)); - disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode())); - } catch (RequestException ex) { - ex.printStackTrace(); - } - }).start(); - } + boolean floodgate = connector.getAuthType() == AuthType.FLOODGATE; + final PublicKey publicKey; - /** - * Present a form window to the user asking to log in with another web browser - */ - public void authenticateWithMicrosoftCode() { - if (loggedIn) { - connector.getLogger().severe(LanguageUtils.getLocaleStringLog("geyser.auth.already_loggedin", getAuthData().getName())); - return; - } - - loggingIn = true; - // new thread so clients don't timeout - new Thread(() -> { - try { - MsaAuthenticationService msaAuthenticationService = new MsaAuthenticationService(GeyserConnector.OAUTH_CLIENT_ID); - - MsaAuthenticationService.MsCodeResponse response = msaAuthenticationService.getAuthCode(); - LoginEncryptionUtils.showMicrosoftCodeWindow(this, response); - - // This just looks cool - SetTimePacket packet = new SetTimePacket(); - packet.setTime(16000); - sendUpstreamPacket(packet); - - // Wait for the code to validate - attemptCodeAuthentication(msaAuthenticationService); - } catch (InvalidCredentialsException | IllegalArgumentException e) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.invalid", getAuthData().getName())); - disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode())); - } catch (RequestException ex) { - ex.printStackTrace(); - } - }).start(); - } - - /** - * Poll every second to see if the user has successfully signed in - */ - private void attemptCodeAuthentication(MsaAuthenticationService msaAuthenticationService) { - if (loggedIn || closed) { - return; - } - try { - msaAuthenticationService.login(); - protocol = new MinecraftProtocol(msaAuthenticationService); - - connectDownstream(); - } catch (RequestException e) { - if (!(e instanceof AuthPendingException)) { - e.printStackTrace(); - } else { - // Wait one second before trying again - connector.getGeneralThreadPool().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS); - } - } - } - - /** - * After getting whatever credentials needed, we attempt to join the Java server. - */ - private void connectDownstream() { - boolean floodgate = connector.getAuthType() == AuthType.FLOODGATE; - final PublicKey publicKey; - - if (floodgate) { - PublicKey key = null; - try { - key = EncryptionUtil.getKeyFromFile( - connector.getConfig().getFloodgateKeyPath(), - PublicKey.class - ); - } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) { - connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.bad_key"), e); - } - publicKey = key; - } else publicKey = null; - - if (publicKey != null) { - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.loaded_key")); - } - - // Start ticking - tickThread = connector.getGeneralThreadPool().scheduleAtFixedRate(this::tick, 50, 50, TimeUnit.MILLISECONDS); - - downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); - if (connector.getConfig().getRemote().isUseProxyProtocol()) { - downstream.getSession().setFlag(BuiltinFlags.ENABLE_CLIENT_PROXY_PROTOCOL, true); - downstream.getSession().setFlag(BuiltinFlags.CLIENT_PROXIED_ADDRESS, upstream.getAddress()); - } - // Let Geyser handle sending the keep alive - downstream.getSession().setFlag(MinecraftConstants.AUTOMATIC_KEEP_ALIVE_MANAGEMENT, false); - downstream.getSession().addListener(new SessionAdapter() { - @Override - public void packetSending(PacketSendingEvent event) { - //todo move this somewhere else - if (event.getPacket() instanceof HandshakePacket && floodgate) { - String encrypted = ""; + if (floodgate) { + PublicKey key = null; try { - encrypted = EncryptionUtil.encryptBedrockData(publicKey, new BedrockData( - clientData.getGameVersion(), - authData.getName(), - authData.getXboxUUID(), - clientData.getDeviceOS().ordinal(), - clientData.getLanguageCode(), - clientData.getCurrentInputMode().ordinal(), - upstream.getSession().getAddress().getAddress().getHostAddress() - )); - } catch (Exception e) { - connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e); + key = EncryptionUtil.getKeyFromFile( + connector.getConfig().getFloodgateKeyFile(), + PublicKey.class + ); + } catch (IOException | InvalidKeySpecException | NoSuchAlgorithmException e) { + connector.getLogger().error("Error while reading Floodgate key file", e); } + publicKey = key; + } else publicKey = null; - HandshakePacket handshakePacket = event.getPacket(); - event.setPacket(new HandshakePacket( - handshakePacket.getProtocolVersion(), - handshakePacket.getHostname() + '\0' + BedrockData.FLOODGATE_IDENTIFIER + '\0' + encrypted, - handshakePacket.getPort(), - handshakePacket.getIntent() - )); - } - } - - @Override - public void connected(ConnectedEvent event) { - loggingIn = false; - loggedIn = true; - if (protocol.getProfile() == null) { - // Java account is offline - disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode())); - return; - } - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.remote.connect", authData.getName(), protocol.getProfile().getName(), remoteServer.getAddress())); - playerEntity.setUuid(protocol.getProfile().getId()); - playerEntity.setUsername(protocol.getProfile().getName()); - - String locale = clientData.getLanguageCode(); - - // Let the user know there locale may take some time to download - // as it has to be extracted from a JAR - if (locale.toLowerCase().equals("en_us") && !LocaleUtils.LOCALE_MAPPINGS.containsKey("en_us")) { - // This should probably be left hardcoded as it will only show for en_us clients - sendMessage("Loading your locale (en_us); if this isn't already downloaded, this may take some time"); + if (publicKey != null) { + connector.getLogger().info("Loaded Floodgate key!"); } - // Download and load the language for the player - LocaleUtils.downloadAndLoadLocale(locale); - } + downstream = new Client(remoteServer.getAddress(), remoteServer.getPort(), protocol, new TcpSessionFactory()); + downstream.getSession().addListener(new SessionAdapter() { + @Override + public void packetSending(PacketSendingEvent event) { + //todo move this somewhere else + if (event.getPacket() instanceof HandshakePacket && floodgate) { + String encrypted = ""; + try { + encrypted = EncryptionUtil.encryptBedrockData(publicKey, new BedrockData( + clientData.getGameVersion(), + authData.getName(), + authData.getXboxUUID(), + clientData.getDeviceOS().ordinal(), + clientData.getLanguageCode(), + clientData.getCurrentInputMode().ordinal(), + upstream.getSession().getAddress().getAddress().getHostAddress() + )); + } catch (Exception e) { + connector.getLogger().error("Failed to encrypt message", e); + } - @Override - public void disconnected(DisconnectedEvent event) { - loggingIn = false; - loggedIn = false; - connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.remote.disconnect", authData.getName(), remoteServer.getAddress(), event.getReason())); - if (event.getCause() != null) { - event.getCause().printStackTrace(); - } - - upstream.disconnect(MessageTranslator.convertMessageLenient(event.getReason())); - } - - @Override - public void packetReceived(PacketReceivedEvent event) { - if (!closed) { - // Required, or else Floodgate players break with Bukkit chunk caching - if (event.getPacket() instanceof LoginSuccessPacket) { - GameProfile profile = ((LoginSuccessPacket) event.getPacket()).getProfile(); - playerEntity.setUsername(profile.getName()); - playerEntity.setUuid(profile.getId()); - - // Check if they are not using a linked account - if (connector.getAuthType() == AuthType.OFFLINE || playerEntity.getUuid().getMostSignificantBits() == 0) { - SkinManager.handleBedrockSkin(playerEntity, clientData); + HandshakePacket handshakePacket = event.getPacket(); + event.setPacket(new HandshakePacket( + handshakePacket.getProtocolVersion(), + handshakePacket.getHostname() + '\0' + BedrockData.FLOODGATE_IDENTIFIER + '\0' + encrypted, + handshakePacket.getPort(), + handshakePacket.getIntent() + )); } } - PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); - } - } + @Override + public void connected(ConnectedEvent event) { + loggingIn = false; + loggedIn = true; + connector.getLogger().info(authData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress()); + playerEntity.setUuid(protocol.getProfile().getId()); + playerEntity.setUsername(protocol.getProfile().getName()); - @Override - public void packetError(PacketErrorEvent event) { - connector.getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.network.downstream_error", event.getCause().getMessage())); - if (connector.getConfig().isDebugMode()) - event.getCause().printStackTrace(); - event.setSuppress(true); - } - }); + String locale = clientData.getLanguageCode(); - if (!daylightCycle) { - setDaylightCycle(true); - } - downstream.getSession().connect(); - connector.addPlayer(this); + // Let the user know there locale may take some time to download + // as it has to be extracted from a JAR + if (locale.toLowerCase().equals("en_us") && !LocaleUtils.LOCALE_MAPPINGS.containsKey("en_us")) { + sendMessage("Downloading your locale (en_us) this may take some time"); + } + + // Download and load the language for the player + LocaleUtils.downloadAndLoadLocale(locale); + } + + @Override + public void disconnected(DisconnectedEvent event) { + loggingIn = false; + loggedIn = false; + connector.getLogger().info(authData.getName() + " has disconnected from remote java server on address " + remoteServer.getAddress() + " because of " + event.getReason()); + if (event.getCause() != null) { + event.getCause().printStackTrace(); + } + upstream.disconnect(event.getReason()); + } + + @Override + public void packetReceived(PacketReceivedEvent event) { + if (!closed) { + //handle consecutive respawn packets + if (event.getPacket().getClass().equals(ServerRespawnPacket.class)) { + manyDimPackets = lastDimPacket != null; + lastDimPacket = event.getPacket(); + return; + } else if (lastDimPacket != null) { + PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(lastDimPacket.getClass(), lastDimPacket, GeyserSession.this); + lastDimPacket = null; + } + + // Required, or else Floodgate players break with Bukkit chunk caching + if (event.getPacket() instanceof LoginSuccessPacket) { + GameProfile profile = ((LoginSuccessPacket) event.getPacket()).getProfile(); + playerEntity.setUsername(profile.getName()); + playerEntity.setUuid(profile.getId()); + + // Check if they are not using a linked account + if (connector.getAuthType() == AuthType.OFFLINE || playerEntity.getUuid().getMostSignificantBits() == 0) { + SkinUtils.handleBedrockSkin(playerEntity, clientData); + } + } + + PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); + } + } + + @Override + public void packetError(PacketErrorEvent event) { + connector.getLogger().warning("Downstream packet error! " + event.getCause().getMessage()); + if (connector.getConfig().isDebugMode()) + event.getCause().printStackTrace(); + event.setSuppress(true); + } + }); + + downstream.getSession().connect(); + connector.addPlayer(this); + } catch (InvalidCredentialsException | IllegalArgumentException e) { + connector.getLogger().info("User '" + username + "' entered invalid login info, kicking."); + disconnect("Invalid/incorrect login info"); + } catch (RequestException ex) { + ex.printStackTrace(); + } + }).start(); } public void disconnect(String reason) { @@ -677,21 +400,14 @@ public class GeyserSession implements CommandSender { downstream.getSession().disconnect(reason); } if (upstream != null && !upstream.isClosed()) { - connector.getPlayers().remove(this); + connector.getPlayers().remove(this.upstream.getAddress()); upstream.disconnect(reason); } } - if (tickThread != null) { - tickThread.cancel(true); - } - - this.advancementsCache = null; - this.bookEditCache = null; this.chunkCache = null; this.entityCache = null; - this.effectCache = null; - this.worldCache = null; + this.scoreboardCache = null; this.inventoryCache = null; this.windowCache = null; @@ -699,41 +415,13 @@ public class GeyserSession implements CommandSender { } public void close() { - disconnect(LanguageUtils.getPlayerLocaleString("geyser.network.close", getClientData().getLanguageCode())); - } - - /** - * Called every 50 milliseconds - one Minecraft tick. - */ - public void tick() { - // Check to see if the player's position needs updating - a position update should be sent once every 3 seconds - if (spawned && (System.currentTimeMillis() - lastMovementTimestamp) > 3000) { - // Recalculate in case something else changed position - Vector3d position = collisionManager.adjustBedrockPosition(playerEntity.getPosition(), playerEntity.isOnGround()); - // A null return value cancels the packet - if (position != null) { - ClientPlayerPositionPacket packet = new ClientPlayerPositionPacket(playerEntity.isOnGround(), - position.getX(), position.getY(), position.getZ()); - sendDownstreamPacket(packet); - } - lastMovementTimestamp = System.currentTimeMillis(); - } - - for (Tickable entity : entityCache.getTickableEntities()) { - entity.tick(this); - } + disconnect("Server closed."); } public void setAuthenticationData(AuthData authData) { this.authData = authData; } - public void setSneaking(boolean sneaking) { - this.sneaking = sneaking; - collisionManager.updatePlayerBoundingBox(); - collisionManager.updateScaffoldingFlags(); - } - @Override public String getName() { return authData.getName(); @@ -752,22 +440,29 @@ public class GeyserSession implements CommandSender { upstream.sendPacket(textPacket); } + public void sendActionBar(String text) { + SetTitlePacket setTitlePacket = new SetTitlePacket(); + setTitlePacket.setType(SetTitlePacket.Type.SET_ACTIONBAR_MESSAGE); + setTitlePacket.setText(text); + setTitlePacket.setFadeInTime(0); + setTitlePacket.setStayTime(0); + setTitlePacket.setFadeOutTime(0); + + upstream.sendPacket(setTitlePacket); + } + @Override public boolean isConsole() { return false; } - @Override - public String getLocale() { - return clientData.getLanguageCode(); - } - public void sendForm(FormWindow window, int id) { windowCache.showWindow(window, id); } public void setRenderDistance(int renderDistance) { - renderDistance = GenericMath.ceil(++renderDistance * MathUtils.SQRT_OF_TWO); //square to circle + renderDistance = GenericMath.ceil(++renderDistance * TrigMath.SQRT_OF_TWO); //square to circle + if (renderDistance > 32) renderDistance = 32; // <3 u ViaVersion but I don't like crashing clients x) this.renderDistance = renderDistance; ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); @@ -787,28 +482,28 @@ public class GeyserSession implements CommandSender { StartGamePacket startGamePacket = new StartGamePacket(); startGamePacket.setUniqueEntityId(playerEntity.getGeyserId()); startGamePacket.setRuntimeEntityId(playerEntity.getGeyserId()); - startGamePacket.setPlayerGameType(GameType.SURVIVAL); + startGamePacket.setPlayerGamemode(0); startGamePacket.setPlayerPosition(Vector3f.from(0, 69, 0)); startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(-1); - startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension)); + startGamePacket.setDimensionId(playerEntity.getDimension()); startGamePacket.setGeneratorId(1); - startGamePacket.setLevelGameType(GameType.SURVIVAL); + startGamePacket.setLevelGamemode(0); startGamePacket.setDifficulty(1); startGamePacket.setDefaultSpawn(Vector3i.ZERO); - startGamePacket.setAchievementsDisabled(!connector.getConfig().isXboxAchievementsEnabled()); - startGamePacket.setCurrentTick(-1); + startGamePacket.setAchievementsDisabled(true); + startGamePacket.setTime(-1); startGamePacket.setEduEditionOffers(0); startGamePacket.setEduFeaturesEnabled(false); startGamePacket.setRainLevel(0); startGamePacket.setLightningLevel(0); startGamePacket.setMultiplayerGame(true); startGamePacket.setBroadcastingToLan(true); - startGamePacket.getGamerules().add(new GameRuleData<>("showcoordinates", connector.getConfig().isShowCoordinates())); + startGamePacket.getGamerules().add(new GameRuleData<>("showcoordinates", true)); startGamePacket.setPlatformBroadcastMode(GamePublishSetting.PUBLIC); startGamePacket.setXblBroadcastMode(GamePublishSetting.PUBLIC); - startGamePacket.setCommandsEnabled(!connector.getConfig().isXboxAchievementsEnabled()); + startGamePacket.setCommandsEnabled(true); startGamePacket.setTexturePacksRequired(false); startGamePacket.setBonusChestEnabled(false); startGamePacket.setStartingWithMap(false); @@ -822,99 +517,41 @@ public class GeyserSession implements CommandSender { startGamePacket.setFromWorldTemplate(false); startGamePacket.setWorldTemplateOptionLocked(false); - String serverName = connector.getConfig().getBedrock().getServerName(); - startGamePacket.setLevelId(serverName); - startGamePacket.setLevelName(serverName); - + startGamePacket.setLevelId("world"); + startGamePacket.setWorldName("world"); startGamePacket.setPremiumWorldTemplateId("00000000-0000-0000-0000-000000000000"); // startGamePacket.setCurrentTick(0); startGamePacket.setEnchantmentSeed(0); startGamePacket.setMultiplayerCorrelationId(""); + startGamePacket.setBlockPalette(BlockTranslator.BLOCKS); startGamePacket.setItemEntries(ItemRegistry.ITEMS); startGamePacket.setVanillaVersion("*"); - startGamePacket.setAuthoritativeMovementMode(AuthoritativeMovementMode.CLIENT); + // startGamePacket.setMovementServerAuthoritative(true); upstream.sendPacket(startGamePacket); } - 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 boolean confirmTeleport(Vector3d position) { - if (teleportMap.size() == 0) { - return true; - } - int teleportID = -1; - - for (Int2ObjectMap.Entry entry : teleportMap.int2ObjectEntrySet()) { - if (entry.getValue().canConfirm(position)) { - if (entry.getValue().getTeleportConfirmId() > teleportID) { - teleportID = entry.getValue().getTeleportConfirmId(); - } + if (teleportCache != null) { + if (!teleportCache.canConfirm(position)) { + GeyserConnector.getInstance().getLogger().debug("Unconfirmed Teleport " + teleportCache.getTeleportConfirmId() + + " Ignore movement " + position + " expected " + teleportCache); + return false; } + int teleportId = teleportCache.getTeleportConfirmId(); + teleportCache = null; + ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(teleportId); + sendDownstreamPacket(teleportConfirmPacket); } - - ObjectIterator> it = teleportMap.int2ObjectEntrySet().iterator(); - - if (teleportID != -1) { - // Confirm the current teleport and any earlier ones - while (it.hasNext()) { - TeleportCache entry = it.next().getValue(); - int nextID = entry.getTeleportConfirmId(); - if (nextID <= teleportID) { - ClientTeleportConfirmPacket teleportConfirmPacket = new ClientTeleportConfirmPacket(nextID); - sendDownstreamPacket(teleportConfirmPacket); - // Servers (especially ones like Hypixel) expect exact coordinates given back to them. - ClientPlayerPositionRotationPacket positionPacket = new ClientPlayerPositionRotationPacket(playerEntity.isOnGround(), - entry.getX(), entry.getY(), entry.getZ(), entry.getYaw(), entry.getPitch()); - sendDownstreamPacket(positionPacket); - it.remove(); - connector.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) { - connector.getLogger().debug("Resending teleport " + resendID); - TeleportCache teleport = teleportMap.get(resendID); - getPlayerEntity().moveAbsolute(this, Vector3f.from(teleport.getX(), teleport.getY(), teleport.getZ()), - teleport.getYaw(), teleport.getPitch(), playerEntity.isOnGround(), true); - } - } - return true; } /** * Queue a packet to be sent to player. - * + * * @param packet the bedrock packet from the NukkitX protocol lib */ public void sendUpstreamPacket(BedrockPacket packet) { - if (upstream != null) { + if (upstream != null && !upstream.isClosed()) { upstream.sendPacket(packet); } else { connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " but the session was null"); @@ -923,11 +560,11 @@ public class GeyserSession implements CommandSender { /** * Send a packet immediately to the player. - * + * * @param packet the bedrock packet from the NukkitX protocol lib */ public void sendUpstreamPacketImmediately(BedrockPacket packet) { - if (upstream != null) { + if (upstream != null && !upstream.isClosed()) { upstream.sendPacketImmediately(packet); } else { connector.getLogger().debug("Tried to send upstream packet " + packet.getClass().getSimpleName() + " immediately but the session was null"); @@ -946,116 +583,4 @@ public class GeyserSession implements CommandSender { connector.getLogger().debug("Tried to send downstream packet " + packet.getClass().getSimpleName() + " before connected to the server"); } } - - /** - * Update the cached value for the reduced debug info gamerule. - * This also toggles the coordinates display - * - * @param value The new value for reducedDebugInfo - */ - public void setReducedDebugInfo(boolean value) { - worldCache.setShowCoordinates(!value); - reducedDebugInfo = value; - } - - /** - * Changes the daylight cycle gamerule on the client - * This is used in the login screen along-side normal usage - * - * @param doCycle If the cycle should continue - */ - public void setDaylightCycle(boolean doCycle) { - sendGameRule("dodaylightcycle", doCycle); - // Save the value so we don't have to constantly send a daylight cycle gamerule update - this.daylightCycle = doCycle; - } - - /** - * Send a gamerule value to the client - * - * @param gameRule The gamerule to send - * @param value The value of the gamerule - */ - public void sendGameRule(String gameRule, Object value) { - GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket(); - gameRulesChangedPacket.getGameRules().add(new GameRuleData<>(gameRule, value)); - upstream.sendPacket(gameRulesChangedPacket); - } - - /** - * Checks if the given session's player has a permission - * - * @param permission The permission node to check - * @return true if the player has the requested permission, false if not - */ - public Boolean hasPermission(String permission) { - return connector.getWorldManager().hasPermission(this, permission); - } - - /** - * Send an AdventureSettingsPacket to the client with the latest flags - */ - public void sendAdventureSettings() { - AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); - adventureSettingsPacket.setUniqueEntityId(playerEntity.getGeyserId()); - // Set command permission if OP permission level is high enough - // This allows mobile players access to a GUI for doing commands. The commands there do not change above OPERATOR - // and all commands there are accessible with OP permission level 2 - adventureSettingsPacket.setCommandPermission(opPermissionLevel >= 2 ? CommandPermission.OPERATOR : CommandPermission.NORMAL); - // Required to make command blocks destroyable - adventureSettingsPacket.setPlayerPermission(opPermissionLevel >= 2 ? PlayerPermission.OPERATOR : PlayerPermission.MEMBER); - - // Update the noClip and worldImmutable values based on the current gamemode - noClip = gameMode == GameMode.SPECTATOR; - worldImmutable = gameMode == GameMode.ADVENTURE || gameMode == GameMode.SPECTATOR; - - Set flags = new HashSet<>(); - if (canFly) { - flags.add(AdventureSetting.MAY_FLY); - } - - if (flying) { - flags.add(AdventureSetting.FLYING); - } - - if (worldImmutable) { - flags.add(AdventureSetting.WORLD_IMMUTABLE); - } - - if (noClip) { - flags.add(AdventureSetting.NO_CLIP); - } - - flags.add(AdventureSetting.AUTO_JUMP); - - adventureSettingsPacket.getSettings().addAll(flags); - sendUpstreamPacket(adventureSettingsPacket); - } - - /** - * Used for updating statistic values since we only get changes from the server - * - * @param statistics Updated statistics values - */ - public void updateStatistics(@NonNull Map statistics) { - this.statistics.putAll(statistics); - } - - public void refreshEmotes(List emotes) { - this.selectedEmotes = emotes; - this.emotes.addAll(emotes); - for (GeyserSession player : connector.getPlayers()) { - List pieces = new ArrayList<>(); - for (UUID piece : emotes) { - if (!player.getEmotes().contains(piece)) { - pieces.add(piece); - } - player.getEmotes().add(piece); - } - EmoteListPacket emoteList = new EmoteListPacket(); - emoteList.setRuntimeEntityId(player.getPlayerEntity().getGeyserId()); - emoteList.getPieceIds().addAll(pieces); - player.sendUpstreamPacket(emoteList); - } - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java index 04e208af..09870eef 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/UpstreamSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,15 +41,17 @@ public class UpstreamSession { private boolean initialized = false; public void sendPacket(@NonNull BedrockPacket packet) { - if (!isClosed()) { - session.sendPacket(packet); - } + if (isClosed()) + return; + + session.sendPacket(packet); } public void sendPacketImmediately(@NonNull BedrockPacket packet) { - if (!isClosed()) { - session.sendPacketImmediately(packet); - } + if (isClosed()) + return; + + session.sendPacketImmediately(packet); } public void disconnect(String reason) { diff --git a/connector/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java b/connector/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java index ba9e1354..9674f8db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/auth/AuthData.java @@ -1,28 +1,3 @@ -/* - * 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.connector.network.session.auth; import lombok.AllArgsConstructor; diff --git a/connector/src/main/java/org/geysermc/connector/network/session/auth/BedrockClientData.java b/connector/src/main/java/org/geysermc/connector/network/session/auth/BedrockClientData.java index 10075a9a..6aeebbaa 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/auth/BedrockClientData.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/auth/BedrockClientData.java @@ -1,28 +1,3 @@ -/* - * 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.connector.network.session.auth; import com.fasterxml.jackson.annotation.JsonEnumDefaultValue; diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/AdvancementsCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/AdvancementsCache.java deleted file mode 100644 index 369967ac..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/AdvancementsCache.java +++ /dev/null @@ -1,321 +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.connector.network.session.cache; - -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientAdvancementTabPacket; -import lombok.Getter; -import lombok.Setter; -import org.geysermc.common.window.SimpleFormWindow; -import org.geysermc.common.window.button.FormButton; -import org.geysermc.common.window.response.SimpleFormResponse; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.chat.MessageTranslator; -import org.geysermc.connector.utils.GeyserAdvancement; -import org.geysermc.connector.utils.LanguageUtils; -import org.geysermc.connector.utils.LocaleUtils; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class AdvancementsCache { - - // Different form IDs - public static final int ADVANCEMENTS_MENU_FORM_ID = 1341; - public static final int ADVANCEMENTS_LIST_FORM_ID = 1342; - public static final int ADVANCEMENT_INFO_FORM_ID = 1343; - - /** - * Stores the player's advancement progress - */ - @Getter - private final Map> storedAdvancementProgress = new HashMap<>(); - - /** - * Stores advancements for the player. - */ - @Getter - private final Map storedAdvancements = new HashMap<>(); - - /** - * Stores player's chosen advancement's ID and title for use in form creators. - */ - @Setter - private String currentAdvancementCategoryId = null; - - private final GeyserSession session; - - public AdvancementsCache(GeyserSession session) { - this.session = session; - } - - /** - * Build a form with all advancement categories - * - * @return The built advancement category menu - */ - public SimpleFormWindow buildMenuForm() { - // Cache the language for cleaner access - String language = session.getClientData().getLanguageCode(); - - // Created menu window for advancement categories - SimpleFormWindow window = new SimpleFormWindow(LocaleUtils.getLocaleString("gui.advancements", language), ""); - for (Map.Entry advancement : storedAdvancements.entrySet()) { - if (advancement.getValue().getParentId() == null) { // No parent means this is a root advancement - window.getButtons().add(new FormButton(MessageTranslator.convertMessage(advancement.getValue().getDisplayData().getTitle(), language))); - } - } - - if (window.getButtons().isEmpty()) { - window.setContent(LocaleUtils.getLocaleString("advancements.empty", language)); - } - - return window; - } - - /** - * Builds the list of advancements - * - * @return The built list form - */ - public SimpleFormWindow buildListForm() { - // Cache the language for easier access - String language = session.getLocale(); - String id = currentAdvancementCategoryId; - GeyserAdvancement categoryAdvancement = storedAdvancements.get(currentAdvancementCategoryId); - - // Create the window - SimpleFormWindow window = new SimpleFormWindow(MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getTitle(), language), - MessageTranslator.convertMessage(categoryAdvancement.getDisplayData().getDescription(), language)); - - if (id != null) { - for (Map.Entry advancementEntry : storedAdvancements.entrySet()) { - GeyserAdvancement advancement = advancementEntry.getValue(); - if (advancement != null) { - if (advancement.getParentId() != null && currentAdvancementCategoryId.equals(advancement.getRootId(this))) { - boolean earned = isEarned(advancement); - - if (earned || !advancement.getDisplayData().isShowToast()) { - window.getButtons().add(new FormButton("§6" + MessageTranslator.convertMessage(advancementEntry.getValue().getDisplayData().getTitle()) + "\n")); - } else { - window.getButtons().add(new FormButton(MessageTranslator.convertMessage(advancementEntry.getValue().getDisplayData().getTitle()) + "\n")); - } - } - } - } - } - - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("gui.back", language))); - - return window; - } - - /** - * Builds the advancement display info based on the chosen category - * - * @param advancement The advancement used to create the info display - * @return The information for the chosen advancement - */ - public SimpleFormWindow buildInfoForm(GeyserAdvancement advancement) { - // Cache language for easier access - String language = session.getLocale(); - - String earned = isEarned(advancement) ? "yes" : "no"; - - String description = getColorFromAdvancementFrameType(advancement) + MessageTranslator.convertMessage(advancement.getDisplayData().getDescription(), language); - String earnedString = LanguageUtils.getPlayerLocaleString("geyser.advancements.earned", language, LocaleUtils.getLocaleString("gui." + earned, language)); - - /* - Layout will look like: - - (Form title) Stone Age - - (Description) Mine stone with your new pickaxe - - Earned: Yes - Parent Advancement: Minecraft // If relevant - */ - - String content = description + "\n\n§f" + - earnedString + "\n"; - if (!currentAdvancementCategoryId.equals(advancement.getParentId())) { - // Only display the parent if it is not the category - content += LanguageUtils.getPlayerLocaleString("geyser.advancements.parentid", language, MessageTranslator.convertMessage(storedAdvancements.get(advancement.getParentId()).getDisplayData().getTitle(), language)); - } - SimpleFormWindow window = new SimpleFormWindow(MessageTranslator.convertMessage(advancement.getDisplayData().getTitle()), content); - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("gui.back", language))); - - return window; - } - - /** - * Determine if this advancement has been earned. - * - * @param advancement the advancement to determine - * @return true if the advancement has been earned. - */ - public boolean isEarned(GeyserAdvancement advancement) { - boolean earned = false; - if (advancement.getRequirements().size() == 0) { - // Minecraft handles this case, so we better as well - return false; - } - Map progress = storedAdvancementProgress.get(advancement.getId()); - if (progress != null) { - // Each advancement's requirement must be fulfilled - // For example, [[zombie, blaze, skeleton]] means that one of those three categories must be achieved - // But [[zombie], [blaze], [skeleton]] means that all three requirements must be completed - for (List requirements : advancement.getRequirements()) { - boolean requirementsDone = false; - for (String requirement : requirements) { - Long obtained = progress.get(requirement); - // -1 means that this particular component required for completing the advancement - // has yet to be fulfilled - if (obtained != null && !obtained.equals(-1L)) { - requirementsDone = true; - break; - } - } - if (!requirementsDone) { - return false; - } - } - earned = true; - } - return earned; - } - - /** - * Handle the menu form response - * - * @param response The response string to parse - * @return True if the form was parsed correctly, false if not - */ - public boolean handleMenuForm(String response) { - SimpleFormWindow menuForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(ADVANCEMENTS_MENU_FORM_ID); - menuForm.setResponse(response); - - SimpleFormResponse formResponse = (SimpleFormResponse) menuForm.getResponse(); - - String id = ""; - if (formResponse != null && formResponse.getClickedButton() != null) { - int advancementIndex = 0; - for (Map.Entry advancement : storedAdvancements.entrySet()) { - if (advancement.getValue().getParentId() == null) { // Root advancement - if (advancementIndex == formResponse.getClickedButtonId()) { - id = advancement.getKey(); - break; - } else { - advancementIndex++; - } - } - } - } - if (!id.equals("")) { - if (id.equals(currentAdvancementCategoryId)) { - // The server thinks we are already on this tab - session.sendForm(buildListForm(), ADVANCEMENTS_LIST_FORM_ID); - } else { - // Send a packet indicating that we intend to open this particular advancement window - ClientAdvancementTabPacket packet = new ClientAdvancementTabPacket(id); - session.sendDownstreamPacket(packet); - // Wait for a response there - } - } - - return true; - } - - /** - * Handle the list form response (Advancement category choice) - * - * @param response The response string to parse - * @return True if the form was parsed correctly, false if not - */ - public boolean handleListForm(String response) { - SimpleFormWindow listForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(ADVANCEMENTS_LIST_FORM_ID); - listForm.setResponse(response); - - SimpleFormResponse formResponse = (SimpleFormResponse) listForm.getResponse(); - - if (!listForm.isClosed() && formResponse != null && formResponse.getClickedButton() != null) { - 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 == formResponse.getClickedButtonId()) { - advancement = advancementEntry; - break; - } else { - advancementIndex++; - } - } - } - if (advancement != null) { - session.sendForm(buildInfoForm(advancement), ADVANCEMENT_INFO_FORM_ID); - } else { - session.sendForm(buildMenuForm(), ADVANCEMENTS_MENU_FORM_ID); - // Indicate that we have closed the current advancement tab - session.sendDownstreamPacket(new ClientAdvancementTabPacket()); - } - } else { - // Indicate that we have closed the current advancement tab - session.sendDownstreamPacket(new ClientAdvancementTabPacket()); - } - - return true; - } - - /** - * Handle the info form response - * - * @param response The response string to parse - * @return True if the form was parsed correctly, false if not - */ - public boolean handleInfoForm(String response) { - SimpleFormWindow listForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(ADVANCEMENT_INFO_FORM_ID); - listForm.setResponse(response); - - SimpleFormResponse formResponse = (SimpleFormResponse) listForm.getResponse(); - - if (!listForm.isClosed() && formResponse != null && formResponse.getClickedButton() != null) { - session.sendForm(buildListForm(), ADVANCEMENTS_LIST_FORM_ID); - } - - return true; - } - - public String getColorFromAdvancementFrameType(GeyserAdvancement advancement) { - String base = "\u00a7"; - if (advancement.getDisplayData().getFrameType() == Advancement.DisplayData.FrameType.CHALLENGE) { - return base + "5"; - } - return base + "a"; // Used for types TASK and GOAL - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java deleted file mode 100644 index f81a9fdf..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/BookEditCache.java +++ /dev/null @@ -1,75 +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.connector.network.session.cache; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientEditBookPacket; -import lombok.Setter; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; - -/** - * Manages updating the current writable book. - * - * Java sends book updates less frequently than Bedrock, and this can cause issues with servers that rate limit - * book packets. Because of this, we need to ensure packets are only send every second or so at maximum. - */ -public class BookEditCache { - private final GeyserSession session; - @Setter - private ClientEditBookPacket packet; - /** - * Stores the last time a book update packet was sent to the server. - */ - private long lastBookUpdate; - - public BookEditCache(GeyserSession session) { - this.session = session; - } - - /** - * Check to see if there is a book edit update to send, and if so, send it. - */ - public void checkForSend() { - if (packet == null) { - // No new packet has to be sent - return; - } - // Prevent kicks due to rate limiting - specifically on Spigot servers - if ((System.currentTimeMillis() - lastBookUpdate) < 1000) { - return; - } - // Don't send the update if the player isn't not holding a book, shouldn't happen if we catch all interactions - ItemStack itemStack = session.getInventory().getItemInHand(); - if (itemStack == null || itemStack.getId() != ItemRegistry.WRITABLE_BOOK.getJavaId()) { - packet = null; - return; - } - session.getDownstream().getSession().send(packet); - packet = null; - lastBookUpdate = System.currentTimeMillis(); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java index c1ba6fff..267f3cb1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/BossBar.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,15 @@ package org.geysermc.connector.network.session.cache; +import com.github.steveice10.mc.protocol.data.message.Message; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityData; import com.nukkitx.protocol.bedrock.packet.AddEntityPacket; import com.nukkitx.protocol.bedrock.packet.BossEventPacket; import com.nukkitx.protocol.bedrock.packet.RemoveEntityPacket; import lombok.AllArgsConstructor; -import net.kyori.adventure.text.Component; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; @AllArgsConstructor public class BossBar { @@ -41,7 +41,7 @@ public class BossBar { private GeyserSession session; private long entityId; - private Component title; + private Message title; private float health; private int color; private int overlay; @@ -52,13 +52,11 @@ public class BossBar { updateBossBar(); } - //TODO: There is a player unique entity ID - if this didn't exist before, we may be able to get rid of our hack - public void updateBossBar() { BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); - bossEventPacket.setAction(BossEventPacket.Action.CREATE); - bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.getLocale())); + bossEventPacket.setAction(BossEventPacket.Action.SHOW); + bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode())); bossEventPacket.setHealthPercentage(health); bossEventPacket.setColor(color); //ignored by client bossEventPacket.setOverlay(overlay); @@ -67,12 +65,12 @@ public class BossBar { session.sendUpstreamPacket(bossEventPacket); } - public void updateTitle(Component title) { + public void updateTitle(Message title) { this.title = title; BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); - bossEventPacket.setAction(BossEventPacket.Action.UPDATE_NAME); - bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.getLocale())); + bossEventPacket.setAction(BossEventPacket.Action.TITLE); + bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode())); session.sendUpstreamPacket(bossEventPacket); } @@ -81,7 +79,7 @@ public class BossBar { this.health = health; BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); - bossEventPacket.setAction(BossEventPacket.Action.UPDATE_PERCENTAGE); + bossEventPacket.setAction(BossEventPacket.Action.HEALTH_PERCENTAGE); bossEventPacket.setHealthPercentage(health); session.sendUpstreamPacket(bossEventPacket); @@ -90,7 +88,7 @@ public class BossBar { public void removeBossBar() { BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); - bossEventPacket.setAction(BossEventPacket.Action.REMOVE); + bossEventPacket.setAction(BossEventPacket.Action.HIDE); session.sendUpstreamPacket(bossEventPacket); removeBossEntity(); diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java index a48b20ce..ac7ab06c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ChunkCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,95 +27,75 @@ package org.geysermc.connector.network.session.cache; import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; import com.github.steveice10.mc.protocol.data.game.chunk.Column; -import it.unimi.dsi.fastutil.longs.Long2ObjectMap; -import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import org.geysermc.connector.bootstrap.GeyserBootstrap; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import lombok.Getter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.MathUtils; +import org.geysermc.connector.network.translators.world.chunk.ChunkPosition; + +import java.util.HashMap; +import java.util.Map; public class ChunkCache { - private final boolean cache; + private boolean cache; + private final GeyserSession session; - private final Long2ObjectMap chunks = new Long2ObjectOpenHashMap<>(); + @Getter + private Map chunks = new HashMap<>(); public ChunkCache(GeyserSession session) { - if (session.getConnector().getWorldManager().getClass() == GeyserBootstrap.DEFAULT_CHUNK_MANAGER.getClass()) { - this.cache = session.getConnector().getConfig().isCacheChunks(); - } else { - this.cache = false; // To prevent Spigot from initializing - } + this.session = session; + this.cache = session.getConnector().getConfig().isCacheChunks(); } - public Column addToCache(Column chunk) { - if (!cache) { - return chunk; - } - - long chunkPosition = MathUtils.chunkPositionToLong(chunk.getX(), chunk.getZ()); - Column existingChunk; - if (chunk.getBiomeData() == null // Only consider merging columns if the new chunk isn't a full chunk - && (existingChunk = chunks.getOrDefault(chunkPosition, null)) != null) { // Column is already present in cache, we can merge with existing - boolean changed = false; - for (int i = 0; i < chunk.getChunks().length; i++) { // The chunks member is final, so chunk.getChunks() will probably be inlined and then completely optimized away - if (chunk.getChunks()[i] != null) { - existingChunk.getChunks()[i] = chunk.getChunks()[i]; - changed = true; - } - } - return changed ? existingChunk : null; - } else { - chunks.put(chunkPosition, chunk); - return chunk; - } - } - - public Column getChunk(int chunkX, int chunkZ) { - long chunkPosition = MathUtils.chunkPositionToLong(chunkX, chunkZ); - return chunks.getOrDefault(chunkPosition, null); - } - - public void updateBlock(int x, int y, int z, int block) { + public void addToCache(Column chunk) { if (!cache) { return; } + ChunkPosition position = new ChunkPosition(chunk.getX(), chunk.getZ()); + chunks.put(position, chunk); + } - Column column = this.getChunk(x >> 4, z >> 4); - if (column == null) { + public void updateBlock(Position position, BlockState block) { + if (!cache) { return; } + ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4); + if (!chunks.containsKey(chunkPosition)) + return; - Chunk chunk = column.getChunks()[y >> 4]; + Column column = chunks.get(chunkPosition); + Chunk chunk = column.getChunks()[position.getY() >> 4]; + Position blockPosition = chunkPosition.getChunkBlock(position.getX(), position.getY(), position.getZ()); if (chunk != null) { - chunk.set(x & 0xF, y & 0xF, z & 0xF, block); + chunk.set(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ(), block); } } - public int getBlockAt(int x, int y, int z) { + public BlockState getBlockAt(Position position) { if (!cache) { - return BlockTranslator.JAVA_AIR_ID; + return BlockTranslator.AIR; } + ChunkPosition chunkPosition = new ChunkPosition(position.getX() >> 4, position.getZ() >> 4); + if (!chunks.containsKey(chunkPosition)) + return BlockTranslator.AIR; - Column column = this.getChunk(x >> 4, z >> 4); - if (column == null) { - return BlockTranslator.JAVA_AIR_ID; - } - - Chunk chunk = column.getChunks()[y >> 4]; + Column column = chunks.get(chunkPosition); + Chunk chunk = column.getChunks()[position.getY() >> 4]; + Position blockPosition = chunkPosition.getChunkBlock(position.getX(), position.getY(), position.getZ()); if (chunk != null) { - return chunk.get(x & 0xF, y & 0xF, z & 0xF); + return chunk.get(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); } - return BlockTranslator.JAVA_AIR_ID; + return BlockTranslator.AIR; } - public void removeChunk(int chunkX, int chunkZ) { + public void removeChunk(ChunkPosition position) { if (!cache) { return; } - - long chunkPosition = MathUtils.chunkPositionToLong(chunkX, chunkZ); - chunks.remove(chunkPosition); + chunks.remove(position); } } diff --git a/connector/src/main/java/org/geysermc/connector/entity/Tickable.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java similarity index 77% rename from connector/src/main/java/org/geysermc/connector/entity/Tickable.java rename to connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java index a7d571cc..4b2af963 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Tickable.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/DataCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 +23,15 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.entity; +package org.geysermc.connector.network.session.cache; -import org.geysermc.connector.network.session.GeyserSession; +import lombok.Getter; -/** - * Implemented onto anything that should have code ran every Minecraft tick - 50 milliseconds. - */ -public interface Tickable { - void tick(GeyserSession session); +import java.util.HashMap; +import java.util.Map; + +public class DataCache { + + @Getter + private Map cachedValues = new HashMap(); } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java index 40000551..0bc51ac7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ package org.geysermc.connector.network.session.cache; import it.unimi.dsi.fastutil.longs.*; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; -import org.geysermc.connector.entity.Tickable; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.player.PlayerEntity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import java.util.*; @@ -41,21 +40,17 @@ import java.util.concurrent.atomic.AtomicLong; * for that player (e.g. seeing vanished players from /vanish) */ public class EntityCache { - private final GeyserSession session; + private GeyserSession session; @Getter private Long2ObjectMap entities = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); - /** - * A list of all entities that must be ticked. - */ - private final List tickableEntities = Collections.synchronizedList(new ArrayList<>()); private Long2LongMap entityIdTranslations = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); private Map playerEntities = Collections.synchronizedMap(new HashMap<>()); private Map bossBars = Collections.synchronizedMap(new HashMap<>()); - private final Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); + private Long2LongMap cachedPlayerEntityLinks = Long2LongMaps.synchronize(new Long2LongOpenHashMap()); @Getter - private final AtomicLong nextEntityId = new AtomicLong(2L); + private AtomicLong nextEntityId = new AtomicLong(2L); public EntityCache(GeyserSession session) { this.session = session; @@ -64,11 +59,6 @@ public class EntityCache { public void spawnEntity(Entity entity) { if (cacheEntity(entity)) { entity.spawnEntity(session); - - if (entity instanceof Tickable) { - // Start ticking it - tickableEntities.add((Tickable) entity); - } } } @@ -86,9 +76,8 @@ public class EntityCache { if (entity != null && entity.isValid() && (force || entity.despawnEntity(session))) { long geyserId = entityIdTranslations.remove(entity.getEntityId()); entities.remove(geyserId); - - if (entity instanceof Tickable) { - tickableEntities.remove(entity); + if (entity.is(PlayerEntity.class)) { + playerEntities.remove(entity.as(PlayerEntity.class).getUuid()); } return true; } @@ -166,8 +155,4 @@ public class EntityCache { public void addCachedPlayerEntityLink(long playerId, long linkedEntityId) { cachedPlayerEntityLinks.put(playerId, linkedEntityId); } - - public List getTickableEntities() { - return tickableEntities; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java index 1edcc4db..a16ef690 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityEffectCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java index 3ead687f..032f6402 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/InventoryCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java similarity index 59% rename from connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java rename to connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java index 0cbfffba..9a692407 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/ScoreboardCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,31 @@ package org.geysermc.connector.network.session.cache; -import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; import lombok.Getter; -import lombok.Setter; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.scoreboard.Objective; import org.geysermc.connector.scoreboard.Scoreboard; -import org.geysermc.connector.scoreboard.ScoreboardUpdater; + +import java.util.Collection; @Getter -public class WorldCache { - private final GeyserSession session; - @Setter - private Difficulty difficulty = Difficulty.EASY; - private boolean showCoordinates = true; - +public class ScoreboardCache { + private GeyserSession session; private Scoreboard scoreboard; - private final ScoreboardUpdater scoreboardUpdater; - public WorldCache(GeyserSession session) { + public ScoreboardCache(GeyserSession session) { this.session = session; this.scoreboard = new Scoreboard(session); - scoreboardUpdater = new ScoreboardUpdater(this); - scoreboardUpdater.start(); } public void removeScoreboard() { if (scoreboard != null) { - for (Objective objective : scoreboard.getObjectives().values()) { + Collection objectives = scoreboard.getObjectives().values(); + scoreboard = new Scoreboard(session); + + for (Objective objective : objectives) { scoreboard.despawnObjective(objective); } - scoreboard = new Scoreboard(session); } } - - public int increaseAndGetScoreboardPacketsPerSecond() { - int pendingPps = scoreboardUpdater.incrementAndGetPacketsPerSecond(); - int pps = scoreboardUpdater.getPacketsPerSecond(); - return Math.max(pps, pendingPps); - } - - /** - * Tell the client to hide or show the coordinates - * - * @param value True to show, false to hide - */ - public void setShowCoordinates(boolean value) { - showCoordinates = value; - session.sendGameRule("showcoordinates", value); - } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/TeleportCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/TeleportCache.java index 17b96aeb..475630db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/TeleportCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/TeleportCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,47 +26,23 @@ package org.geysermc.connector.network.session.cache; import com.nukkitx.math.vector.Vector3d; +import com.nukkitx.math.vector.Vector3f; +import lombok.AllArgsConstructor; import lombok.Data; -import lombok.RequiredArgsConstructor; -/** - * Represents a teleport ID and corresponding coordinates that need to be confirmed.
- * - * The vanilla Java client, after getting a - * {@link com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket}, - * adjusts the player's positions and immediately sends a teleport back. However, we want to acknowledge that the - * Bedrock player actually moves close to that point, so we store the teleport until we get a movement packet from - * Bedrock that the teleport was successful. - */ -@RequiredArgsConstructor +@AllArgsConstructor @Data public class TeleportCache { - private static final double ERROR_X_AND_Z = 0.1; - private static final double ERROR_Y = 0.1; + private static final double ERROR = 0.2; + private static final double ERROR_Y = 0.5; - /** - * How many move packets the teleport can be unconfirmed for before it gets resent to the client - */ - private static final int RESEND_THRESHOLD = 5; - - private final double x, y, z; - private final float pitch, yaw; - private final int teleportConfirmId; - - private int unconfirmedFor = 0; + private double x, y, z; + private int teleportConfirmId; public boolean canConfirm(Vector3d position) { - return (Math.abs(this.x - position.getX()) < ERROR_X_AND_Z && + return (Math.abs(this.x - position.getX()) < ERROR && Math.abs(this.y - position.getY()) < ERROR_Y && - Math.abs(this.z - position.getZ()) < ERROR_X_AND_Z); - } - - public void incrementUnconfirmedFor() { - unconfirmedFor++; - } - - public boolean shouldResend() { - return unconfirmedFor >= RESEND_THRESHOLD; + Math.abs(this.z - position.getZ()) < ERROR); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java index a114b8bb..15b9a770 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/WindowCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 +37,10 @@ import org.geysermc.connector.network.session.GeyserSession; public class WindowCache { - private final GeyserSession session; + private GeyserSession session; @Getter - private final Int2ObjectMap windows = new Int2ObjectOpenHashMap<>(); + private Int2ObjectMap windows = new Int2ObjectOpenHashMap<>(); public WindowCache(GeyserSession session) { this.session = session; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java index eed901cd..c12cc513 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/BiomeTranslator.java @@ -1,36 +1,36 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators; -import com.nukkitx.nbt.NBTInputStream; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.nbt.stream.NBTInputStream; +import com.nukkitx.nbt.tag.CompoundTag; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import java.io.InputStream; import java.util.Arrays; @@ -40,7 +40,7 @@ import java.util.Arrays; // Array index formula by https://wiki.vg/Chunk_Format public class BiomeTranslator { - public static final NbtMap BIOMES; + public static final CompoundTag BIOMES; private BiomeTranslator() { } @@ -53,13 +53,13 @@ public class BiomeTranslator { /* Load biomes */ InputStream stream = FileUtils.getResource("bedrock/biome_definitions.dat"); - NbtMap biomesTag; + CompoundTag biomesTag; - try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(stream)) { - biomesTag = (NbtMap) biomenbtInputStream.readTag(); + try (NBTInputStream biomenbtInputStream = NbtUtils.createNetworkReader(stream)){ + biomesTag = (CompoundTag) biomenbtInputStream.readTag(); BIOMES = biomesTag; } catch (Exception ex) { - GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.biome_read")); + GeyserConnector.getInstance().getLogger().warning("Failed to get biomes from biome definitions, is there something wrong with the file?"); throw new AssertionError(ex); } } @@ -70,27 +70,24 @@ public class BiomeTranslator { return bedrockData; } - for (int y = 0; y < 16; y += 4) { - for (int z = 0; z < 16; z += 4) { - for (int x = 0; x < 16; x += 4) { - byte biomeId = biomeID(biomeData, x, y, z); - int offset = ((z + (y / 4)) << 4) | x; - Arrays.fill(bedrockData, offset, offset + 4, biomeId); - } + for (int z = 0; z < 16; z += 4) { + for (int x = 0; x < 16; x += 4) { + byte biomeId = biomeID(biomeData, x, z); + fillArray(z, x, bedrockData, biomeId); + fillArray(z + 1, x, bedrockData, biomeId); + fillArray(z + 2, x, bedrockData, biomeId); + fillArray(z + 3, x, bedrockData, biomeId); } } return bedrockData; } - private static byte biomeID(int[] biomeData, int x, int y, int z) { - int biomeId = biomeData[((y >> 2) & 63) << 4 | ((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; - if (biomeId == 0) { - biomeId = 42; // Ocean - } else if (biomeId >= 40 && biomeId <= 43) { // Java has multiple End dimensions that Bedrock doesn't recognize - biomeId = 9; - } else if (biomeId >= 170) { // Nether biomes. Dunno why it's like this :microjang: - biomeId += 8; - } - return (byte) biomeId; + private static void fillArray(int z, int x, byte[] legacyBiomeData, int biomeId) { + int offset = (z << 4) | x; + Arrays.fill(legacyBiomeData, offset, offset + 4, (byte) biomeId); + } + + private static byte biomeID(int[] biomeData, int x, int z) { + return (byte) biomeData[((z >> 2) & 3) << 2 | ((x >> 2) & 3)]; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java index f4c0f9ab..cc9b2cd8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java @@ -1,35 +1,35 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators; -import com.nukkitx.nbt.NBTInputStream; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.nbt.stream.NBTInputStream; +import com.nukkitx.nbt.tag.CompoundTag; import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import java.io.InputStream; @@ -38,7 +38,7 @@ import java.io.InputStream; */ public class EntityIdentifierRegistry { - public static NbtMap ENTITY_IDENTIFIERS; + public static CompoundTag ENTITY_IDENTIFIERS; private EntityIdentifierRegistry() { } @@ -52,9 +52,9 @@ public class EntityIdentifierRegistry { InputStream stream = FileUtils.getResource("bedrock/entity_identifiers.dat"); try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { - ENTITY_IDENTIFIERS = (NbtMap) nbtInputStream.readTag(); + ENTITY_IDENTIFIERS = (CompoundTag) nbtInputStream.readTag(); } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.entity"), e); + throw new AssertionError("Unable to get entities from entity identifiers", e); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java b/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java index ca053087..6c286da2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/ItemRemapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslator.java index 8bb3eb33..066aa1c5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java index b841a79b..c3ec8ff2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/PacketTranslatorRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 @@ package org.geysermc.connector.network.translators; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListDataPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket; import com.github.steveice10.packetlib.packet.Packet; import com.nukkitx.protocol.bedrock.BedrockPacket; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import org.reflections.Reflections; import java.util.HashMap; @@ -48,7 +46,7 @@ public class PacketTranslatorRegistry { private static final ObjectArrayList> IGNORED_PACKETS = new ObjectArrayList<>(); static { - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators") : new Reflections("org.geysermc.connector.network.translators"); + Reflections ref = new Reflections("org.geysermc.connector.network.translators"); for (Class clazz : ref.getTypesAnnotatedWith(Translator.class)) { Class packet = clazz.getAnnotation(Translator.class).packet(); @@ -67,15 +65,15 @@ public class PacketTranslatorRegistry { BEDROCK_TRANSLATOR.translators.put(targetPacket, translator); } else { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.invalid_target", clazz.getCanonicalName())); + GeyserConnector.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet."); } } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.failed", clazz.getCanonicalName())); + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated translator " + clazz.getCanonicalName() + "."); } } + IGNORED_PACKETS.add(ServerKeepAlivePacket.class); // Handled by MCProtocolLib IGNORED_PACKETS.add(ServerUpdateLightPacket.class); // Light is handled on Bedrock for us - IGNORED_PACKETS.add(ServerPlayerListDataPacket.class); // Cant be implemented in bedrock } private PacketTranslatorRegistry() { @@ -97,7 +95,7 @@ public class PacketTranslatorRegistry { GeyserConnector.getInstance().getLogger().debug("Could not find packet for " + (packet.toString().length() > 25 ? packet.getClass().getSimpleName() : packet)); } } catch (Throwable ex) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.packet.failed", packet.getClass().getSimpleName()), ex); + GeyserConnector.getInstance().getLogger().error("Could not translate packet " + packet.getClass().getSimpleName(), ex); ex.printStackTrace(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/Translator.java b/connector/src/main/java/org/geysermc/connector/network/translators/Translator.java index a7954301..8e097ba4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/Translator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/Translator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java similarity index 51% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java index c4dbbec4..2c44e4fd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockActionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,36 +23,27 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock.entity.player; +package org.geysermc.connector.network.translators.bedrock; + +import java.util.concurrent.TimeUnit; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -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.entity.player.PlayerAction; -import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; -import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerAbilitiesPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; -import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.BlockUtils; -import java.util.concurrent.TimeUnit; +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerAction; +import com.github.steveice10.mc.protocol.data.game.entity.player.PlayerState; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; +import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; @Translator(packet = PlayerActionPacket.class) public class BedrockActionTranslator extends PacketTranslator { @@ -63,24 +54,13 @@ public class BedrockActionTranslator extends PacketTranslator { + private boolean isSteeringLeft; + private boolean isSteeringRight; + @Override public void translate(AnimatePacket packet, GeyserSession session) { // Stop the player sending animations before they have fully spawned into the server @@ -57,13 +61,13 @@ public class BedrockAnimateTranslator extends PacketTranslator { // These two might need to be flipped, but my recommendation is getting moving working first case ROW_LEFT: // Packet value is a float of how long one has been rowing, so we convert that into a boolean - session.setSteeringLeft(packet.getRowingTime() > 0.0); - ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); + isSteeringLeft = packet.getRowingTime() > 0.0; + ClientSteerBoatPacket steerLeftPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft); session.sendDownstreamPacket(steerLeftPacket); break; case ROW_RIGHT: - session.setSteeringRight(packet.getRowingTime() > 0.0); - ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(session.isSteeringLeft(), session.isSteeringRight()); + isSteeringRight = packet.getRowingTime() > 0.0; + ClientSteerBoatPacket steerRightPacket = new ClientSteerBoatPacket(isSteeringRight, isSteeringLeft); session.sendDownstreamPacket(steerRightPacket); break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java index f9db86d8..9fe62bb4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockEntityDataTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,102 +26,66 @@ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientUpdateJigsawBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientUpdateSignPacket; -import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.utils.SignUtils; + +import java.util.HashMap; +import java.util.Map; @Translator(packet = BlockEntityDataPacket.class) public class BedrockBlockEntityDataTranslator extends PacketTranslator { + // In case two people are editing signs at the same time this array holds the temporary messages to be sent + // Position -> Message being held + protected static Map lastMessages = new HashMap<>(); + @Override public void translate(BlockEntityDataPacket packet, GeyserSession session) { - NbtMap tag = packet.getData(); - if (tag.getString("id").equals("Sign")) { - // This is the reason why this all works - Bedrock sends packets every time you update the sign, Java only wants the final packet - // But Bedrock sends one final packet when you're done editing the sign, which should be equal to the last message since there's no edits - // So if the latest update does not match the last cached update then it's still being edited - if (!tag.getString("Text").equals(session.getLastSignMessage())) { - session.setLastSignMessage(tag.getString("Text")); - return; - } - // Otherwise the two messages are identical and we can get to work deconstructing - StringBuilder newMessage = new StringBuilder(); - // While Bedrock's sign lines are one string, Java's is an array of each line - // (Initialized all with empty strings because it complains about null) - String[] lines = new String[] {"", "", "", ""}; - int iterator = 0; - // Keep track of the width of each character - // If it goes over the maximum, we need to start a new line to match Java - int widthCount = 0; - // This converts the message into the array'd message Java wants - for (char character : tag.getString("Text").toCharArray()) { - widthCount += SignUtils.getCharacterWidth(character); - // If we get a return in Bedrock, or go over the character width max, that signals to use the next line. - if (character == '\n' || widthCount > SignUtils.JAVA_CHARACTER_WIDTH_MAX) { - // We need to apply some more logic if we went over the character width max - boolean wentOverMax = widthCount > SignUtils.JAVA_CHARACTER_WIDTH_MAX && character != '\n'; - widthCount = 0; - // Saves if we're moving a word to the next line - String word = null; - if (wentOverMax && iterator < lines.length - 1) { - // If we went over the max, we want to try to wrap properly like Bedrock does. - // So we look for a space in the Bedrock user's text to imply a word. - int index = newMessage.lastIndexOf(" "); - if (index != -1) { - // There is indeed a space in this line; let's get it - word = newMessage.substring(index + 1); - // 'Delete' that word from the string builder - newMessage.delete(index, newMessage.length()); + if (packet.getData() instanceof CompoundTag) { + CompoundTag tag = (CompoundTag) packet.getData(); + if (tag.getString("id").equals("Sign")) { + // This is the reason why this all works - Bedrock sends packets every time you update the sign, Java only wants the final packet + // But Bedrock sends one final packet when you're done editing the sign, which should be equal to the last message since there's no edits + // So if the latest update does not match the last cached update then it's still being edited + Position pos = new Position(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); + if (!tag.getString("Text").equals(lastMessages.get(pos))) { + lastMessages.put(pos, tag.getString("Text")); + return; + } + // Otherwise the two messages are identical and we can get to work deconstructing + StringBuilder newMessage = new StringBuilder(); + // While Bedrock's sign lines are one string, Java's is an array of each line + // (Initialized all with empty strings because it complains about null) + String[] lines = new String[] {"", "", "", ""}; + int iterator = 0; + // This converts the message into the array'd message Java wants + for (char character : tag.getString("Text").toCharArray()) { + // If we get a return in Bedrock, that signals to use the next line. + if (character == '\n') { + lines[iterator] = newMessage.toString(); + iterator++; + // Bedrock, for whatever reason, can hold a message out of bounds + // We don't care about that so we discard that + if (iterator > lines.length - 1) { + break; } - } - lines[iterator] = newMessage.toString(); - iterator++; - // Bedrock, for whatever reason, can hold a message out of the bounds of the four lines - // We don't care about that so we discard that - if (iterator > lines.length - 1) { - break; - } - newMessage = new StringBuilder(); - if (wentOverMax) { - // Apply the wrapped word to the new line - if (word != null) { - newMessage.append(word); - // And apply the width count - for (char wordCharacter : word.toCharArray()) { - widthCount += SignUtils.getCharacterWidth(wordCharacter); - } - } - // If we went over the max, we want to append the character to the new line. - newMessage.append(character); - widthCount += SignUtils.getCharacterWidth(character); - } - } else newMessage.append(character); + newMessage = new StringBuilder(); + } else newMessage.append(character); + } + // Put the final line on since it isn't done in the for loop + if (iterator < lines.length) lines[iterator] = newMessage.toString(); + ClientUpdateSignPacket clientUpdateSignPacket = new ClientUpdateSignPacket(pos, lines); + session.sendDownstreamPacket(clientUpdateSignPacket); + //TODO (potentially): originally I was going to update the sign blocks so Bedrock and Java users would match visually + // However Java can still store a lot per-line and visuals are still messed up so that doesn't work + + // We remove the sign position from map to indicate there is no work-in-progress sign + lastMessages.remove(pos); } - // Put the final line on since it isn't done in the for loop - if (iterator < lines.length) lines[iterator] = newMessage.toString(); - Position pos = new Position(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); - ClientUpdateSignPacket clientUpdateSignPacket = new ClientUpdateSignPacket(pos, lines); - session.sendDownstreamPacket(clientUpdateSignPacket); - - // We set the sign text cached in the session to null to indicate there is no work-in-progress sign - session.setLastSignMessage(null); - - } else if (tag.getString("id").equals("JigsawBlock")) { - // Client has just sent a jigsaw block update - Position pos = new Position(tag.getInt("x"), tag.getInt("y"), tag.getInt("z")); - String name = tag.getString("name"); - String target = tag.getString("target"); - String pool = tag.getString("target_pool"); - String finalState = tag.getString("final_state"); - String joint = tag.getString("joint"); - ClientUpdateJigsawBlockPacket jigsawPacket = new ClientUpdateJigsawBlockPacket(pos, name, target, pool, - finalState, joint); - session.sendDownstreamPacket(jigsawPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java new file mode 100644 index 00000000..04fe8dbf --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.bedrock; + +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientMoveItemToHotbarPacket; +import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.protocol.bedrock.packet.BlockPickRequestPacket; +import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; +import org.geysermc.connector.inventory.Inventory; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.network.translators.item.ItemRegistry; +import org.geysermc.connector.network.translators.world.block.BlockTranslator; + +@Translator(packet = BlockPickRequestPacket.class) +public class BedrockBlockPickRequestPacketTranslator extends PacketTranslator { + + @Override + public void translate(BlockPickRequestPacket packet, GeyserSession session) { + Vector3i vector = packet.getBlockPosition(); + BlockState blockToPick = session.getConnector().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); + + // Block is air - chunk caching is probably off + if (blockToPick.getId() == 0) { + return; + } + + // Get the inventory to choose a slot to pick + Inventory inventory = session.getInventoryCache().getOpenInventory(); + if (inventory == null) { + inventory = session.getInventory(); + } + + String targetIdentifier = BlockTranslator.getJavaIdBlockMap().inverse().get(blockToPick).split("\\[")[0]; + + // Check hotbar for item + for (int i = 36; i < 45; i++) { + if (inventory.getItem(i) == null) { + continue; + } + ItemEntry item = ItemRegistry.getItem(inventory.getItem(i)); + // If this isn't the item we're looking for + if (!item.getJavaIdentifier().equals(targetIdentifier)) { + continue; + } + + PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket(); + hotbarPacket.setContainerId(0); + // Java inventory slot to hotbar slot ID + hotbarPacket.setSelectedHotbarSlot(i - 36); + hotbarPacket.setSelectHotbarSlot(true); + session.sendUpstreamPacket(hotbarPacket); + session.getInventory().setHeldItemSlot(i - 36); + // Don't check inventory if item was in hotbar + return; + } + + // Check inventory for item + for (int i = 9; i < 36; i++) { + if (inventory.getItem(i) == null) { + continue; + } + ItemEntry item = ItemRegistry.getItem(inventory.getItem(i)); + // If this isn't the item we're looking for + if (!item.getJavaIdentifier().equals(targetIdentifier)) { + continue; + } + + ClientMoveItemToHotbarPacket packetToSend = new ClientMoveItemToHotbarPacket(i); // https://wiki.vg/Protocol#Pick_Item + session.sendDownstreamPacket(packetToSend); + return; + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java deleted file mode 100644 index 9becfb36..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestTranslator.java +++ /dev/null @@ -1,51 +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.connector.network.translators.bedrock; - -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.protocol.bedrock.packet.BlockPickRequestPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.InventoryUtils; - -@Translator(packet = BlockPickRequestPacket.class) -public class BedrockBlockPickRequestTranslator extends PacketTranslator { - - @Override - public void translate(BlockPickRequestPacket packet, GeyserSession session) { - Vector3i vector = packet.getBlockPosition(); - int blockToPick = session.getConnector().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); - - // Block is air - chunk caching is probably off - if (blockToPick == BlockTranslator.JAVA_AIR_ID) { - return; - } - - InventoryUtils.findOrCreateItem(session, BlockTranslator.getPickItem(blockToPick)); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java deleted file mode 100644 index dd5d08a2..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBookEditTranslator.java +++ /dev/null @@ -1,123 +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.connector.network.translators.bedrock; - -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.packet.ingame.client.window.ClientEditBookPacket; -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 com.nukkitx.protocol.bedrock.packet.BookEditPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; - -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -@Translator(packet = BookEditPacket.class) -public class BedrockBookEditTranslator extends PacketTranslator { - - @Override - public void translate(BookEditPacket packet, GeyserSession session) { - ItemStack itemStack = session.getInventory().getItemInHand(); - if (itemStack != null) { - CompoundTag tag = itemStack.getNbt() != null ? itemStack.getNbt() : new CompoundTag(""); - ItemStack bookItem = new ItemStack(itemStack.getId(), itemStack.getAmount(), tag); - List pages = tag.contains("pages") ? new LinkedList<>(((ListTag) tag.get("pages")).getValue()) : new LinkedList<>(); - - int page = packet.getPageNumber(); - // Creative edits the NBT for us - if (session.getGameMode() != GameMode.CREATIVE) { - switch (packet.getAction()) { - case ADD_PAGE: { - // Add empty pages in between - for (int i = pages.size(); i < page; i++) { - pages.add(i, new StringTag("", "")); - } - pages.add(page, new StringTag("", packet.getText())); - break; - } - // Called whenever a page is modified - case REPLACE_PAGE: { - if (page < pages.size()) { - pages.set(page, new StringTag("", packet.getText())); - } else { - // Add empty pages in between - for (int i = pages.size(); i < page; i++) { - pages.add(i, new StringTag("", "")); - } - pages.add(page, new StringTag("", packet.getText())); - } - break; - } - case DELETE_PAGE: { - if (page < pages.size()) { - pages.remove(page); - } - break; - } - case SWAP_PAGES: { - int page2 = packet.getSecondaryPageNumber(); - if (page < pages.size() && page2 < pages.size()) { - Collections.swap(pages, page, page2); - } - break; - } - case SIGN_BOOK: { - tag.put(new StringTag("author", packet.getAuthor())); - tag.put(new StringTag("title", packet.getTitle())); - break; - } - default: - return; - } - } - // Remove empty pages at the end - while (pages.size() > 0) { - StringTag currentPage = (StringTag) pages.get(pages.size() - 1); - if (currentPage.getValue() == null || currentPage.getValue().isEmpty()) { - pages.remove(pages.size() - 1); - } else { - break; - } - } - tag.put(new ListTag("pages", pages)); - session.getInventory().setItem(36 + session.getInventory().getHeldItemSlot(), bookItem); - InventoryTranslator.INVENTORY_TRANSLATORS.get(null).updateInventory(session, session.getInventory()); - - session.getBookEditCache().setPacket(new ClientEditBookPacket(bookItem, packet.getAction() == BookEditPacket.Action.SIGN_BOOK, session.getInventory().getHeldItemSlot())); - // There won't be any more book updates after this, so we can try sending the edit packet immediately - if (packet.getAction() == BookEditPacket.Action.SIGN_BOOK) { - session.getBookEditCache().checkForSend(); - } - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandBlockUpdateTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandBlockUpdateTranslator.java deleted file mode 100644 index 634ba0c5..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandBlockUpdateTranslator.java +++ /dev/null @@ -1,71 +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.connector.network.translators.bedrock; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.github.steveice10.mc.protocol.data.game.world.block.CommandBlockMode; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientUpdateCommandBlockMinecartPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientUpdateCommandBlockPacket; -import com.nukkitx.protocol.bedrock.packet.CommandBlockUpdatePacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -@Translator(packet = CommandBlockUpdatePacket.class) -public class BedrockCommandBlockUpdateTranslator extends PacketTranslator { - - @Override - public void translate(CommandBlockUpdatePacket packet, GeyserSession session) { - String command = packet.getCommand(); - boolean outputTracked = packet.isOutputTracked(); - if (packet.isBlock()) { - CommandBlockMode mode; - switch (packet.getMode()) { - case CHAIN: // The green one - mode = CommandBlockMode.SEQUENCE; - break; - case REPEATING: // The purple one - mode = CommandBlockMode.AUTO; - break; - default: // NORMAL, the orange one - mode = CommandBlockMode.REDSTONE; - break; - } - boolean isConditional = packet.isConditional(); - boolean automatic = !packet.isRedstoneMode(); // Automatic = Always Active option in Java - ClientUpdateCommandBlockPacket commandBlockPacket = new ClientUpdateCommandBlockPacket( - new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), - command, mode, outputTracked, isConditional, automatic); - session.sendDownstreamPacket(commandBlockPacket); - } else { - ClientUpdateCommandBlockMinecartPacket commandMinecartPacket = new ClientUpdateCommandBlockMinecartPacket( - (int) session.getEntityCache().getEntityByGeyserId(packet.getMinecartRuntimeEntityId()).getEntityId(), - command, outputTracked - ); - session.sendDownstreamPacket(commandMinecartPacket); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java index 6ff29f5c..1f31367c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockCommandRequestTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.Translator; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket; import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; @Translator(packet = CommandRequestPacket.class) public class BedrockCommandRequestTranslator extends PacketTranslator { @@ -48,7 +48,7 @@ public class BedrockCommandRequestTranslator extends PacketTranslator { + + @Override + public void translate(EntityEventPacket packet, GeyserSession session) { + switch (packet.getType()) { + // Resend the packet so we get the eating sounds + case EATING_ITEM: + session.sendUpstreamPacket(packet); + return; + } + session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString()); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java deleted file mode 100644 index fcb62d44..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEntityPickRequestTranslator.java +++ /dev/null @@ -1,115 +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.connector.network.translators.bedrock; - -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.packet.EntityPickRequestPacket; -import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.utils.InventoryUtils; - -/** - * Called when the Bedrock user uses the pick block button on an entity - */ -@Translator(packet = EntityPickRequestPacket.class) -public class BedrockEntityPickRequestTranslator extends PacketTranslator { - - @Override - public void translate(EntityPickRequestPacket packet, GeyserSession session) { - if (session.getGameMode() != GameMode.CREATIVE) return; // Apparently Java behavior - Entity entity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); - if (entity == null) return; - - // Get the corresponding item - String itemName; - switch (entity.getEntityType()) { - case BOAT: - // Include type of boat in the name - int variant = entity.getMetadata().getInt(EntityData.VARIANT); - String typeOfBoat; - switch (variant) { - case 1: - typeOfBoat = "spruce"; - break; - case 2: - typeOfBoat = "birch"; - break; - case 3: - typeOfBoat = "jungle"; - break; - case 4: - typeOfBoat = "acacia"; - break; - case 5: - typeOfBoat = "dark_oak"; - break; - default: - typeOfBoat = "oak"; - break; - } - itemName = typeOfBoat + "_boat"; - break; - case LEASH_KNOT: - itemName = "lead"; - break; - case MINECART_CHEST: - case MINECART_COMMAND_BLOCK: - case MINECART_FURNACE: - case MINECART_HOPPER: - case MINECART_TNT: - // Move MINECART to the end of the name - itemName = entity.getEntityType().toString().toLowerCase().replace("minecart_", "") + "_minecart"; - break; - case MINECART_SPAWNER: - // Turns into a normal minecart - itemName = "minecart"; - break; - case ARMOR_STAND: - case END_CRYSTAL: - case ITEM_FRAME: - case MINECART: - case PAINTING: - // No spawn egg, just an item - itemName = entity.getEntityType().toString().toLowerCase(); - break; - default: - itemName = entity.getEntityType().toString().toLowerCase() + "_spawn_egg"; - break; - } - - String fullItemName = "minecraft:" + itemName; - ItemEntry entry = ItemRegistry.getItemEntry(fullItemName); - // Verify it is, indeed, an item - if (entry == null) return; - - InventoryUtils.findOrCreateItem(session, fullItemName); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java deleted file mode 100644 index db01df15..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockFilterTextTranslator.java +++ /dev/null @@ -1,45 +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.connector.network.translators.bedrock; - -import com.nukkitx.protocol.bedrock.packet.FilterTextPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -/** - * Used to send strings to the server and filter out unwanted words. - * Java doesn't care, so we don't care, and we approve all strings. - */ -@Translator(packet = FilterTextPacket.class) -public class BedrockFilterTextTranslator extends PacketTranslator { - - @Override - public void translate(FilterTextPacket packet, GeyserSession session) { - packet.setFromServer(true); - session.sendUpstreamPacket(packet); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java new file mode 100644 index 00000000..bfd4a90a --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInteractTranslator.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.bedrock; + +import com.nukkitx.protocol.bedrock.data.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityFlag; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +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.packet.ingame.client.player.ClientPlayerInteractEntityPacket; +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; +import com.nukkitx.protocol.bedrock.packet.InteractPacket; +import org.geysermc.connector.network.translators.item.ItemRegistry; + +@Translator(packet = InteractPacket.class) +public class BedrockInteractTranslator extends PacketTranslator { + + @Override + public void translate(InteractPacket packet, GeyserSession session) { + Entity entity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); + if (entity == null) + return; + + switch (packet.getAction()) { + case INTERACT: + if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD) { + break; + } + ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), + InteractAction.INTERACT, Hand.MAIN_HAND); + session.sendDownstreamPacket(interactPacket); + break; + case DAMAGE: + ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), + InteractAction.ATTACK, Hand.MAIN_HAND); + session.sendDownstreamPacket(attackPacket); + break; + case LEAVE_VEHICLE: + ClientPlayerStatePacket sneakPacket = new ClientPlayerStatePacket((int) 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 + if (packet.getRuntimeEntityId() != 0) { + Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); + if (interactEntity == null) + return; + + String interactiveTag; + switch (interactEntity.getEntityType()) { + case PIG: + if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.SADDLED)) { + interactiveTag = "action.interact.mount"; + } else interactiveTag = ""; + break; + case HORSE: + case SKELETON_HORSE: + case ZOMBIE_HORSE: + case DONKEY: + case MULE: + case LLAMA: + case TRADER_LLAMA: + if (interactEntity.getMetadata().getFlags().getFlag(EntityFlag.TAMED)) { + interactiveTag = "action.interact.ride.horse"; + } else { + interactiveTag = "action.interact.mount"; + } + break; + case BOAT: + interactiveTag = "action.interact.ride.boat"; + break; + case MINECART: + interactiveTag = "action.interact.ride.minecart"; + break; + default: + return; // No need to process any further since there is no interactive tag + } + session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag); + session.getPlayerEntity().updateBedrockMetadata(session); + } else { + if (!(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == null) || + !(session.getPlayerEntity().getMetadata().get(EntityData.INTERACTIVE_TAG) == "")) { + // No interactive tag should be sent + session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG); + session.getPlayerEntity().updateBedrockMetadata(session); + } + } + break; + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 8263507b..8f96b800 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,15 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerInteractEntityPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPlaceBlockPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerUseItemPacket; -import com.nukkitx.math.vector.Vector3f; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.packet.*; -import org.geysermc.connector.entity.CommandBlockMinecartEntity; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; +import com.nukkitx.protocol.bedrock.packet.InventoryTransactionPacket; + import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; -import org.geysermc.connector.entity.living.merchant.AbstractMerchantEntity; -import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -58,28 +54,13 @@ import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.sound.EntitySoundInteractionHandler; import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.BlockUtils; import org.geysermc.connector.utils.InventoryUtils; -import java.util.concurrent.TimeUnit; - -/** - * BedrockInventoryTransactionTranslator handles most interactions between the client and the world, - * or the client and their inventory. - */ @Translator(packet = InventoryTransactionPacket.class) public class BedrockInventoryTransactionTranslator extends PacketTranslator { - private static final float MAXIMUM_BLOCK_PLACING_DISTANCE = 64f; - private static final int CREATIVE_EYE_HEIGHT_PLACE_DISTANCE = 49; - private static final int SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE = 36; - private static final float MAXIMUM_BLOCK_DESTROYING_DISTANCE = 36f; - @Override public void translate(InventoryTransactionPacket packet, GeyserSession session) { - // Send book updates before opening inventories - session.getBookEditCache().checkForSend(); - switch (packet.getTransactionType()) { case NORMAL: Inventory inventory = session.getInventoryCache().getOpenInventory(); @@ -95,178 +76,99 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator - (session.getGameMode().equals(GameMode.CREATIVE) ? CREATIVE_EYE_HEIGHT_PLACE_DISTANCE : SURVIVAL_EYE_HEIGHT_PLACE_DISTANCE)) { - restoreCorrectBlock(session, blockPos, packet); - return; - } - - // Vanilla check - if (!(session.getPlayerEntity().getPosition().sub(0, EntityType.PLAYER.getOffset(), 0) - .distanceSquared(packet.getBlockPosition().toFloat().add(0.5f, 0.5f, 0.5f)) < 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; - } - /* - Block place checks end - client is good to go - */ - ClientPlayerPlaceBlockPacket blockPacket = new ClientPlayerPlaceBlockPacket( new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()), - BlockFace.values()[packet.getBlockFace()], + BlockFace.values()[packet.getFace()], Hand.MAIN_HAND, packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(), false); session.sendDownstreamPacket(blockPacket); - // Otherwise boats will not be able to be placed in survival and buckets won't work on mobile - if (packet.getItemInHand() != null && ItemRegistry.BOATS.contains(packet.getItemInHand().getId())) { - ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); - session.sendDownstreamPacket(itemPacket); - } - // Check actions, otherwise buckets may be activated when block inventories are accessed - else if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId())) { - // Let the server decide if the bucket item should change, not the client, and revert the changes the client made - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.INVENTORY); - slotPacket.setSlot(packet.getHotbarSlot()); - slotPacket.setItem(packet.getItemInHand()); - session.sendUpstreamPacket(slotPacket); - // Delay the interaction in case the client doesn't intend to actually use the bucket - // See BedrockActionTranslator.java - session.setBucketScheduledFuture(session.getConnector().getGeneralThreadPool().schedule(() -> { - ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); - session.sendDownstreamPacket(itemPacket); - }, 5, TimeUnit.MILLISECONDS)); - } + // Otherwise boats will not be able to be placed in survival + if (packet.getItemInHand() != null && packet.getItemInHand().getId() == ItemRegistry.BOAT) { + ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); + session.sendDownstreamPacket(itemPacket); + } - if (packet.getActions().isEmpty()) { - if (session.getOpPermissionLevel() >= 2 && session.getGameMode() == GameMode.CREATIVE) { - // Otherwise insufficient permissions - int blockState = BlockTranslator.getJavaBlockState(packet.getBlockRuntimeId()); - String blockName = BlockTranslator.getJavaIdBlockMap().inverse().getOrDefault(blockState, ""); - // In the future this can be used for structure blocks too, however not all elements - // are available in each GUI - if (blockName.contains("jigsaw")) { - ContainerOpenPacket openPacket = new ContainerOpenPacket(); - openPacket.setBlockPosition(packet.getBlockPosition()); - openPacket.setId((byte) 1); - openPacket.setType(ContainerType.JIGSAW_EDITOR); - openPacket.setUniqueEntityId(-1); - session.sendUpstreamPacket(openPacket); - } - } + Vector3i blockPos = packet.getBlockPosition(); + // TODO: Find a better way to do this? + switch (packet.getFace()) { + case 0: + blockPos = blockPos.sub(0, 1, 0); + break; + case 1: + blockPos = blockPos.add(0, 1, 0); + break; + case 2: + blockPos = blockPos.sub(0, 0, 1); + break; + case 3: + blockPos = blockPos.add(0, 0, 1); + break; + case 4: + blockPos = blockPos.sub(1, 0, 0); + break; + case 5: + blockPos = blockPos.add(1, 0, 0); + break; } - ItemEntry handItem = ItemRegistry.getItem(packet.getItemInHand()); if (handItem.isBlock()) { session.setLastBlockPlacePosition(blockPos); session.setLastBlockPlacedId(handItem.getJavaIdentifier()); } + session.setLastInteractionPosition(packet.getBlockPosition()); session.setInteracting(true); break; case 1: ItemStack shieldSlot = session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36); - // Handled in Entity.java - if (shieldSlot != null && shieldSlot.getId() == ItemRegistry.SHIELD.getJavaId()) { + if (shieldSlot != null && shieldSlot.getId() == ItemRegistry.SHIELD) { break; - } - - // Handled in ITEM_USE if the item is not milk - if (packet.getItemInHand() != null && ItemRegistry.BUCKETS.contains(packet.getItemInHand().getId()) && - packet.getItemInHand().getId() != ItemRegistry.MILK_BUCKET.getBedrockId()) { - break; - } - + } // Handled in Entity.java ClientPlayerUseItemPacket useItemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); session.sendDownstreamPacket(useItemPacket); + // Used for sleeping in beds + session.setLastInteractionPosition(packet.getBlockPosition()); break; case 2: - int blockState = session.getGameMode() == GameMode.CREATIVE ? - session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition()) : session.getBreakingBlock(); + BlockState blockState = session.getConnector().getWorldManager().getBlockAt(session, packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()); + double blockHardness = BlockTranslator.JAVA_RUNTIME_ID_TO_HARDNESS.get(blockState.getId()); + if (session.getGameMode() == GameMode.CREATIVE || (session.getConnector().getConfig().isCacheChunks() && blockHardness == 0)) { + session.setLastBlockPlacedId(null); + session.setLastBlockPlacePosition(null); - session.setLastBlockPlacedId(null); - session.setLastBlockPlacePosition(null); - - // Same deal with vanilla block placing as above. - // This is working out the distance using 3d Pythagoras and the extra value added to the Y is the sneaking height of a java player. - playerPosition = session.getPlayerEntity().getPosition(); - Vector3f floatBlockPosition = packet.getBlockPosition().toFloat(); - diffX = playerPosition.getX() - (floatBlockPosition.getX() + 0.5f); - diffY = (playerPosition.getY() - EntityType.PLAYER.getOffset()) - (floatBlockPosition.getY() + 0.5f) + 1.5f; - diffZ = playerPosition.getZ() - (floatBlockPosition.getZ() + 0.5f); - float distanceSquared = diffX * diffX + diffY * diffY + diffZ * diffZ; - if (distanceSquared > MAXIMUM_BLOCK_DESTROYING_DISTANCE) { - restoreCorrectBlock(session, packet.getBlockPosition(), packet); - return; + LevelEventPacket blockBreakPacket = new LevelEventPacket(); + blockBreakPacket.setType(LevelEventType.DESTROY); + blockBreakPacket.setPosition(packet.getBlockPosition().toFloat()); + blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState)); + session.sendUpstreamPacket(blockBreakPacket); } - LevelEventPacket blockBreakPacket = new LevelEventPacket(); - blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); - blockBreakPacket.setPosition(packet.getBlockPosition().toFloat()); - blockBreakPacket.setData(BlockTranslator.getBedrockBlockId(blockState)); - session.sendUpstreamPacket(blockBreakPacket); - session.setBreakingBlock(BlockTranslator.JAVA_AIR_ID); - - long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()); - if (frameEntityId != -1 && session.getEntityCache().getEntityByJavaId(frameEntityId) != null) { - ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) frameEntityId, InteractAction.ATTACK, session.isSneaking()); + if (ItemFrameEntity.positionContainsItemFrame(session, packet.getBlockPosition()) && + session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition())) != null) { + ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, packet.getBlockPosition()), + InteractAction.ATTACK); session.sendDownstreamPacket(attackPacket); break; } PlayerAction action = session.getGameMode() == GameMode.CREATIVE ? PlayerAction.START_DIGGING : PlayerAction.FINISH_DIGGING; Position pos = new Position(packet.getBlockPosition().getX(), packet.getBlockPosition().getY(), packet.getBlockPosition().getZ()); - ClientPlayerActionPacket breakPacket = new ClientPlayerActionPacket(action, pos, BlockFace.values()[packet.getBlockFace()]); + ClientPlayerActionPacket breakPacket = new ClientPlayerActionPacket(action, pos, BlockFace.values()[packet.getFace()]); session.sendDownstreamPacket(breakPacket); break; } @@ -287,77 +189,23 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator 0) { + y = packet.getBlockPosition().getY() * 2; + } else { + y = (packet.getBlockPosition().getY() * -2) - 1; + } + Vector3i position = Vector3i.from(packet.getBlockPosition().getX(), y, packet.getBlockPosition().getZ()); ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) ItemFrameEntity.getItemFrameEntityId(session, position), - InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); + InteractAction.ATTACK, Hand.MAIN_HAND); session.sendDownstreamPacket(interactPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLevelSoundEventTranslator.java similarity index 76% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteListTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLevelSoundEventTranslator.java index 7e2238f3..6395f0a1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockLevelSoundEventTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 @@ package org.geysermc.connector.network.translators.bedrock; -import com.nukkitx.protocol.bedrock.packet.EmoteListPacket; +import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -@Translator(packet = EmoteListPacket.class) -public class BedrockEmoteListTranslator extends PacketTranslator { +@Translator(packet = LevelSoundEventPacket.class) +public class BedrockLevelSoundEventTranslator extends PacketTranslator { @Override - public void translate(EmoteListPacket packet, GeyserSession session) { - session.refreshEmotes(packet.getPieceIds()); + public void translate(LevelSoundEventPacket packet, GeyserSession session) { + // lol what even :thinking: + session.sendUpstreamPacket(packet); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMapInfoRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMapInfoRequestTranslator.java deleted file mode 100644 index 6d6ee5b2..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMapInfoRequestTranslator.java +++ /dev/null @@ -1,54 +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.connector.network.translators.bedrock; - -import com.nukkitx.protocol.bedrock.packet.ClientboundMapItemDataPacket; -import com.nukkitx.protocol.bedrock.packet.MapInfoRequestPacket; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -import java.util.concurrent.TimeUnit; - -@Translator(packet = MapInfoRequestPacket.class) -public class BedrockMapInfoRequestTranslator extends PacketTranslator { - - @Override - public void translate(MapInfoRequestPacket packet, GeyserSession session) { - long mapID = packet.getUniqueMapId(); - - if (session.getStoredMaps().containsKey(mapID)) { - // Delay the packet 100ms to prevent the client from ignoring the packet - GeyserConnector.getInstance().getGeneralThreadPool().schedule(() -> { - ClientboundMapItemDataPacket mapPacket = session.getStoredMaps().remove(mapID); - if (mapPacket != null) { - session.sendUpstreamPacket(mapPacket); - } - }, 100, TimeUnit.MILLISECONDS); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java index 47fb9702..5fc7f41a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMobEquipmentTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerChangeHeldItemPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket; -import org.geysermc.connector.utils.CooldownUtils; @Translator(packet = MobEquipmentPacket.class) public class BedrockMobEquipmentTranslator extends PacketTranslator { @@ -40,20 +39,13 @@ public class BedrockMobEquipmentTranslator extends PacketTranslator 8 || - packet.getContainerId() != ContainerId.INVENTORY || session.getInventory().getHeldItemSlot() == packet.getHotbarSlot()) { - // 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 + packet.getContainerId() != ContainerId.INVENTORY) { return; } - // Send book update before switching hotbar slot - session.getBookEditCache().checkForSend(); - session.getInventory().setHeldItemSlot(packet.getHotbarSlot()); ClientPlayerChangeHeldItemPacket changeHeldItemPacket = new ClientPlayerChangeHeldItemPacket(packet.getHotbarSlot()); session.sendDownstreamPacket(changeHeldItemPacket); - - // Java sends a cooldown indicator whenever you switch an item - CooldownUtils.sendCooldown(session); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java index f0b5a175..250965ec 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMoveEntityAbsoluteTranslator.java @@ -1,54 +1,46 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientVehicleMovePacket; import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import org.geysermc.connector.entity.BoatEntity; -import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -/** - * Sent by the client when moving a horse. - */ +// Used for horses @Translator(packet = MoveEntityAbsolutePacket.class) public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator { @Override public void translate(MoveEntityAbsolutePacket packet, GeyserSession session) { - float y = packet.getPosition().getY(); - if (session.getRidingVehicleEntity() instanceof BoatEntity) { - // Remove some Y position to prevents boats from looking like they're floating in water - // Not by the full boat offset because 1.16.100 complains and that's probably not good for the future - y -= (EntityType.BOAT.getOffset() - 0.5f); - } + ClientVehicleMovePacket clientVehicleMovePacket = new ClientVehicleMovePacket( - packet.getPosition().getX(), y, packet.getPosition().getZ(), + packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ(), packet.getRotation().getY() - 90, packet.getRotation().getX() ); session.sendDownstreamPacket(clientVehicleMovePacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java new file mode 100644 index 00000000..14d597fd --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockMovePlayerTranslator.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.bedrock; + +import com.nukkitx.math.vector.Vector3d; +import org.geysermc.common.ChatColor; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; +import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; +import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; + +@Translator(packet = MovePlayerPacket.class) +public class BedrockMovePlayerTranslator extends PacketTranslator { + + @Override + public void translate(MovePlayerPacket packet, GeyserSession session) { + PlayerEntity entity = session.getPlayerEntity(); + if (entity == null || !session.isSpawned() || session.getPendingDimSwitches().get() > 0) return; + + if (!session.getUpstream().isInitialized()) { + MoveEntityAbsolutePacket moveEntityBack = new MoveEntityAbsolutePacket(); + moveEntityBack.setRuntimeEntityId(entity.getGeyserId()); + moveEntityBack.setPosition(entity.getPosition()); + moveEntityBack.setRotation(entity.getBedrockRotation()); + moveEntityBack.setTeleported(true); + moveEntityBack.setOnGround(true); + session.sendUpstreamPacketImmediately(moveEntityBack); + return; + } + + // We need to parse the float as a string since casting a float to a double causes us to + // lose precision and thus, causes players to get stuck when walking near walls + double javaY = packet.getPosition().getY() - EntityType.PLAYER.getOffset(); + if (packet.isOnGround()) javaY = Math.ceil(javaY * 2) / 2; + + Vector3d position = Vector3d.from(Double.parseDouble(Float.toString(packet.getPosition().getX())), javaY, + Double.parseDouble(Float.toString(packet.getPosition().getZ()))); + + if(!session.confirmTeleport(position)){ + return; + } + + if (!isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) { + session.getConnector().getLogger().debug("Recalculating position..."); + recalculatePosition(session, entity, entity.getPosition()); + return; + } + + ClientPlayerPositionRotationPacket playerPositionRotationPacket = new ClientPlayerPositionRotationPacket( + packet.isOnGround(), position.getX(), position.getY(), position.getZ(), packet.getRotation().getY(), packet.getRotation().getX() + ); + + // head yaw, pitch, head yaw + Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY()); + entity.setPosition(packet.getPosition().sub(0, EntityType.PLAYER.getOffset(), 0)); + entity.setRotation(rotation); + entity.setOnGround(packet.isOnGround()); + + /* + boolean colliding = false; + Position position = new Position((int) packet.getPosition().getX(), + (int) Math.ceil(javaY * 2) / 2, (int) packet.getPosition().getZ()); + + BlockEntry block = session.getChunkCache().getBlockAt(position); + if (!block.getJavaIdentifier().contains("air")) + colliding = true; + + if (!colliding) + */ + session.sendDownstreamPacket(playerPositionRotationPacket); + } + + public boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) { + if (mode != MovePlayerPacket.Mode.NORMAL) + return true; + + double xRange = newPosition.getX() - currentPosition.getX(); + double yRange = newPosition.getY() - currentPosition.getY(); + double zRange = newPosition.getZ() - currentPosition.getZ(); + + if (xRange < 0) + xRange = -xRange; + if (yRange < 0) + yRange = -yRange; + if (zRange < 0) + zRange = -zRange; + + if ((xRange + yRange + zRange) > 100) { + session.getConnector().getLogger().debug(ChatColor.RED + session.getName() + " moved too quickly." + + " current position: " + currentPosition + ", new position: " + newPosition); + + return false; + } + + return true; + } + + public void recalculatePosition(GeyserSession session, Entity entity, Vector3f currentPosition) { + // Gravity might need to be reset... + SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); + entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); + entityDataPacket.getMetadata().putAll(entity.getMetadata()); + session.sendUpstreamPacket(entityDataPacket); + + MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); + movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); + movePlayerPacket.setPosition(entity.getPosition()); + movePlayerPacket.setRotation(entity.getBedrockRotation()); + movePlayerPacket.setMode(MovePlayerPacket.Mode.RESET); + session.sendUpstreamPacket(movePlayerPacket); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java deleted file mode 100644 index 38e5981e..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockNetworkStackLatencyTranslator.java +++ /dev/null @@ -1,55 +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.connector.network.translators.bedrock; - -import com.github.steveice10.mc.protocol.packet.ingame.client.ClientKeepAlivePacket; -import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.floodgate.util.DeviceOS; - -/** - * Used to send the keep alive packet back to the server - */ -@Translator(packet = NetworkStackLatencyPacket.class) -public class BedrockNetworkStackLatencyTranslator extends PacketTranslator { - - @Override - public void translate(NetworkStackLatencyPacket packet, GeyserSession session) { - long pingId; - // so apparently, as of 1.16.200 - // PS4 divides the network stack latency timestamp FOR US!!! - // WTF - if (session.getClientData().getDeviceOS().equals(DeviceOS.NX)) { - // Ignore the weird DeviceOS, our order is wrong and will be fixed in Floodgate 2.0 - pingId = packet.getTimestamp(); - } else { - pingId = packet.getTimestamp() / 1000; - } - session.sendDownstreamPacket(new ClientKeepAlivePacket(pingId)); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPacketViolationWarningTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPacketViolationWarningTranslator.java deleted file mode 100644 index b69cedcb..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPacketViolationWarningTranslator.java +++ /dev/null @@ -1,41 +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.connector.network.translators.bedrock; - -import com.nukkitx.protocol.bedrock.packet.PacketViolationWarningPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -@Translator(packet = PacketViolationWarningPacket.class) -public class BedrockPacketViolationWarningTranslator extends PacketTranslator { - - @Override - public void translate(PacketViolationWarningPacket packet, GeyserSession session) { - // Not translated since this is something that the developers need to know - session.getConnector().getLogger().error("Packet violation warning sent from client! " + packet.toString()); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java index a04e332c..960fbf48 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java @@ -1,28 +1,3 @@ -/* - * 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.connector.network.translators.bedrock; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerVehiclePacket; @@ -31,9 +6,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -/** - * Sent by the client for minecarts and boats. - */ +// Makes minecarts respond to player input @Translator(packet = PlayerInputPacket.class) public class BedrockPlayerInputTranslator extends PacketTranslator { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java deleted file mode 100644 index da760cdd..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPositionTrackingDBClientRequestTranslator.java +++ /dev/null @@ -1,79 +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.connector.network.translators.bedrock; - -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.packet.PositionTrackingDBClientRequestPacket; -import com.nukkitx.protocol.bedrock.packet.PositionTrackingDBServerBroadcastPacket; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.utils.DimensionUtils; -import org.geysermc.connector.utils.LoadstoneTracker; - -@Translator(packet = PositionTrackingDBClientRequestPacket.class) -public class BedrockPositionTrackingDBClientRequestTranslator extends PacketTranslator { - - @Override - public void translate(PositionTrackingDBClientRequestPacket packet, GeyserSession session) { - PositionTrackingDBServerBroadcastPacket broadcastPacket = new PositionTrackingDBServerBroadcastPacket(); - broadcastPacket.setTrackingId(packet.getTrackingId()); - - // Fetch the stored Loadstone - LoadstoneTracker.LoadstonePos pos = LoadstoneTracker.getPos(packet.getTrackingId()); - - // If we don't have data for that ID tell the client its not found - if (pos == null) { - broadcastPacket.setAction(PositionTrackingDBServerBroadcastPacket.Action.NOT_FOUND); - session.sendUpstreamPacket(broadcastPacket); - return; - } - - broadcastPacket.setAction(PositionTrackingDBServerBroadcastPacket.Action.UPDATE); - - // Build the nbt data for the update - NbtMapBuilder builder = NbtMap.builder(); - builder.putInt("dim", DimensionUtils.javaToBedrock(pos.getDimension())); - builder.putString("id", String.format("%08X", packet.getTrackingId())); - - builder.putByte("version", (byte) 1); // Not sure what this is for - builder.putByte("status", (byte) 0); // Not sure what this is for - - // Build the position for the update - IntList posList = new IntArrayList(); - posList.add(pos.getX()); - posList.add(pos.getY()); - posList.add(pos.getZ()); - builder.putList("pos", NbtType.INT, posList); - broadcastPacket.setTag(builder.build()); - - session.sendUpstreamPacket(broadcastPacket); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java index 2964bd65..8fc377ab 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,49 +25,27 @@ package org.geysermc.connector.network.translators.bedrock; -import com.github.steveice10.mc.protocol.data.game.ClientRequest; -import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; -import com.nukkitx.protocol.bedrock.packet.RespawnPacket; -import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; -import org.geysermc.connector.entity.player.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +import com.github.steveice10.mc.protocol.data.game.ClientRequest; +import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket; +import com.nukkitx.math.vector.Vector3f; +import com.nukkitx.protocol.bedrock.packet.RespawnPacket; + @Translator(packet = RespawnPacket.class) public class BedrockRespawnTranslator extends PacketTranslator { @Override public void translate(RespawnPacket packet, GeyserSession session) { 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); + respawnPacket.setState(RespawnPacket.State.SERVER_SEARCHING); session.sendUpstreamPacket(respawnPacket); - if (session.isSpawned()) { - // Client might be stuck; resend spawn information - PlayerEntity entity = session.getPlayerEntity(); - if (entity == null) return; - SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); - entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); - entityDataPacket.getMetadata().putAll(entity.getMetadata()); - session.sendUpstreamPacket(entityDataPacket); - - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); - movePlayerPacket.setPosition(entity.getPosition()); - movePlayerPacket.setRotation(entity.getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.RESPAWN); - session.sendUpstreamPacket(movePlayerPacket); - } - ClientRequestPacket javaRespawnPacket = new ClientRequestPacket(ClientRequest.RESPAWN); session.sendDownstreamPacket(javaRespawnPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java deleted file mode 100644 index 997bba8a..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockServerSettingsRequestTranslator.java +++ /dev/null @@ -1,47 +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.connector.network.translators.bedrock; - -import com.nukkitx.protocol.bedrock.packet.ServerSettingsRequestPacket; -import com.nukkitx.protocol.bedrock.packet.ServerSettingsResponsePacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.utils.SettingsUtils; - -@Translator(packet = ServerSettingsRequestPacket.class) -public class BedrockServerSettingsRequestTranslator extends PacketTranslator { - - @Override - public void translate(ServerSettingsRequestPacket packet, GeyserSession session) { - SettingsUtils.buildForm(session); - - ServerSettingsResponsePacket serverSettingsResponsePacket = new ServerSettingsResponsePacket(); - serverSettingsResponsePacket.setFormData(session.getSettingsForm().getJSONData()); - serverSettingsResponsePacket.setFormId(SettingsUtils.SETTINGS_FORM_ID); - session.sendUpstreamPacket(serverSettingsResponsePacket); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index ac6f543d..87da2d00 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 @@ package org.geysermc.connector.network.translators.bedrock; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket; -import org.geysermc.connector.entity.player.PlayerEntity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.skin.SkinManager; -import org.geysermc.connector.skin.SkullSkinManager; +import org.geysermc.connector.utils.SkinUtils; + +import com.nukkitx.protocol.bedrock.packet.SetLocalPlayerAsInitializedPacket; @Translator(packet = SetLocalPlayerAsInitializedPacket.class) public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslator { @@ -45,20 +44,10 @@ public class BedrockSetLocalPlayerAsInitializedTranslator extends PacketTranslat for (PlayerEntity entity : session.getEntityCache().getEntitiesByType(PlayerEntity.class)) { if (!entity.isValid()) { - SkinManager.requestAndHandleSkinAndCape(entity, session, null); - entity.sendPlayer(session); + // async skin loading + SkinUtils.requestAndHandleSkinAndCape(entity, session, skinAndCape -> entity.sendPlayer(session)); } } - - // Send Skulls - for (PlayerEntity entity : session.getSkullCache().values()) { - entity.spawnEntity(session); - - SkullSkinManager.requestAndHandleSkin(entity, session, (skin) -> { - entity.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false); - entity.updateBedrockMetadata(session); - }); - } } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockShowCreditsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockShowCreditsTranslator.java index c6c29222..4f0af78c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockShowCreditsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockShowCreditsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java index 9253372a..ad650f98 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockTextTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,16 +31,16 @@ import org.geysermc.connector.network.translators.Translator; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientChatPacket; import com.nukkitx.protocol.bedrock.packet.TextPacket; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; @Translator(packet = TextPacket.class) public class BedrockTextTranslator extends PacketTranslator { @Override public void translate(TextPacket packet, GeyserSession session) { - String message = packet.getMessage(); + String message = packet.getMessage().replaceAll("^\\.", "/").trim(); - if (MessageTranslator.isTooLong(message, session)) { + if (MessageUtils.isTooLong(message, session)) { return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java deleted file mode 100644 index a89bfdfb..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/BedrockEntityEventTranslator.java +++ /dev/null @@ -1,68 +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.connector.network.translators.bedrock.entity; - -import com.github.steveice10.mc.protocol.data.game.window.VillagerTrade; -import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientSelectTradePacket; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; -import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -@Translator(packet = EntityEventPacket.class) -public class BedrockEntityEventTranslator extends PacketTranslator { - - @Override - public void translate(EntityEventPacket packet, GeyserSession session) { - switch (packet.getType()) { - case EATING_ITEM: - // Resend the packet so we get the eating sounds - session.sendUpstreamPacket(packet); - return; - case COMPLETE_TRADE: - ClientSelectTradePacket selectTradePacket = new ClientSelectTradePacket(packet.getData()); - session.sendDownstreamPacket(selectTradePacket); - - Entity villager = session.getPlayerEntity(); - Inventory openInventory = session.getInventoryCache().getOpenInventory(); - if (openInventory != null && openInventory.getWindowType() == WindowType.MERCHANT) { - VillagerTrade[] trades = session.getVillagerTrades(); - if (trades != null && packet.getData() >= 0 && packet.getData() < trades.length) { - VillagerTrade trade = session.getVillagerTrades()[packet.getData()]; - openInventory.setItem(2, trade.getOutput()); - villager.getMetadata().put(EntityData.TRADE_XP, trade.getXp() + villager.getMetadata().getInt(EntityData.TRADE_XP)); - villager.updateBedrockMetadata(session); - } - } - return; - } - session.getConnector().getLogger().debug("Did not translate incoming EntityEventPacket: " + packet.toString()); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java deleted file mode 100644 index c08a2f31..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockInteractTranslator.java +++ /dev/null @@ -1,431 +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.connector.network.translators.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.packet.ingame.client.player.ClientPlayerInteractEntityPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerStatePacket; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityDataMap; -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; -import lombok.Getter; -import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; - -import java.util.Arrays; -import java.util.List; - -@Translator(packet = InteractPacket.class) -public class BedrockInteractTranslator extends PacketTranslator { - - /** - * A list of all foods a horse/donkey can eat on Java Edition. - * Used to display interactive tag if needed. - */ - private static final List DONKEY_AND_HORSE_FOODS = Arrays.asList("golden_apple", "enchanted_golden_apple", - "golden_carrot", "sugar", "apple", "wheat", "hay_block"); - - /** - * A list of all flowers. Used for feeding bees. - */ - private static final List FLOWERS = Arrays.asList("dandelion", "poppy", "blue_orchid", "allium", "azure_bluet", - "red_tulip", "pink_tulip", "white_tulip", "orange_tulip", "cornflower", "lily_of_the_valley", "wither_rose", - "sunflower", "lilac", "rose_bush", "peony"); - - /** - * All entity types that can be leashed on Java Edition - */ - private static final List LEASHABLE_MOB_TYPES = Arrays.asList(EntityType.BEE, EntityType.CAT, EntityType.CHICKEN, - EntityType.COW, EntityType.DOLPHIN, EntityType.DONKEY, EntityType.FOX, 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.STRIDER, EntityType.WOLF, EntityType.ZOGLIN); - - private static final List SADDLEABLE_WHEN_TAMED_MOB_TYPES = Arrays.asList(EntityType.DONKEY, EntityType.HORSE, - EntityType.ZOMBIE_HORSE, EntityType.MULE); - /** - * A list of all foods a wolf can eat on Java Edition. - * Used to display interactive tag if needed. - */ - private static final List WOLF_FOODS = Arrays.asList("pufferfish", "tropical_fish", "chicken", "cooked_chicken", - "porkchop", "beef", "rabbit", "cooked_porkchop", "cooked_beef", "rotten_flesh", "mutton", "cooked_mutton", - "cooked_rabbit"); - - @Override - public void translate(InteractPacket packet, GeyserSession session) { - Entity entity; - if (packet.getRuntimeEntityId() == session.getPlayerEntity().getGeyserId()) { - //Player is not in entity cache - entity = session.getPlayerEntity(); - } else { - entity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); - } - if (entity == null) - return; - - switch (packet.getAction()) { - case INTERACT: - if (session.getInventory().getItem(session.getInventory().getHeldItemSlot() + 36).getId() == ItemRegistry.SHIELD.getJavaId()) { - break; - } - ClientPlayerInteractEntityPacket interactPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), - InteractAction.INTERACT, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(interactPacket); - break; - case DAMAGE: - ClientPlayerInteractEntityPacket attackPacket = new ClientPlayerInteractEntityPacket((int) entity.getEntityId(), - InteractAction.ATTACK, Hand.MAIN_HAND, session.isSneaking()); - session.sendDownstreamPacket(attackPacket); - break; - case LEAVE_VEHICLE: - ClientPlayerStatePacket sneakPacket = new ClientPlayerStatePacket((int) 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 - if (packet.getRuntimeEntityId() != 0) { - Entity interactEntity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); - if (interactEntity == null) - return; - EntityDataMap entityMetadata = interactEntity.getMetadata(); - ItemEntry itemEntry = session.getInventory().getItemInHand() == null ? ItemEntry.AIR : ItemRegistry.getItem(session.getInventory().getItemInHand()); - String javaIdentifierStripped = itemEntry.getJavaIdentifier().replace("minecraft:", ""); - - // TODO - in the future, update these in the metadata? So the client doesn't have to wiggle their cursor around for it to happen - // TODO - also, might be good to abstract out the eating thing. I know there will need to be food tracked for https://github.com/GeyserMC/Geyser/issues/1005 but not all food is breeding food - InteractiveTag interactiveTag = InteractiveTag.NONE; - if (entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == session.getPlayerEntity().getGeyserId()) { - // Unleash the entity - interactiveTag = InteractiveTag.REMOVE_LEASH; - } else if (javaIdentifierStripped.equals("saddle") && !entityMetadata.getFlags().getFlag(EntityFlag.SADDLED) && - ((SADDLEABLE_WHEN_TAMED_MOB_TYPES.contains(interactEntity.getEntityType()) && entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) || - interactEntity.getEntityType() == EntityType.PIG || interactEntity.getEntityType() == 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.getInventory().getItemInHand().getNbt() != null && - session.getInventory().getItemInHand().getNbt().contains("display")) { - // Holding a named name tag - interactiveTag = InteractiveTag.NAME; - } else if (javaIdentifierStripped.equals("lead") && LEASHABLE_MOB_TYPES.contains(interactEntity.getEntityType()) && - entityMetadata.getLong(EntityData.LEASH_HOLDER_EID) == -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 { - switch (interactEntity.getEntityType()) { - case BEE: - if (FLOWERS.contains(javaIdentifierStripped)) { - interactiveTag = InteractiveTag.FEED; - } - break; - case BOAT: - interactiveTag = InteractiveTag.BOARD_BOAT; - break; - case CAT: - if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) { - interactiveTag = InteractiveTag.FEED; - } else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && - entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) { - // Tamed and owned by player - can sit/stand - interactiveTag = entityMetadata.getFlags().getFlag(EntityFlag.SITTING) ? InteractiveTag.STAND : InteractiveTag.SIT; - break; - } - break; - case CHICKEN: - if (javaIdentifierStripped.contains("seeds")) { - interactiveTag = InteractiveTag.FEED; - } - 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("wheat")) { - interactiveTag = InteractiveTag.FEED; - } else 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 (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && !entityMetadata.getFlags().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: - // have another switch statement as, while these share mount attributes they don't share food - switch (interactEntity.getEntityType()) { - case LLAMA: - case TRADER_LLAMA: - if (javaIdentifierStripped.equals("wheat") || javaIdentifierStripped.equals("hay_block")) { - interactiveTag = InteractiveTag.FEED; - break; - } - case DONKEY: - case HORSE: - // Undead can't eat - if (DONKEY_AND_HORSE_FOODS.contains(javaIdentifierStripped)) { - interactiveTag = InteractiveTag.FEED; - break; - } - } - if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY)) { - // Can't ride a baby - if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) { - interactiveTag = InteractiveTag.RIDE_HORSE; - } else if (!entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && itemEntry.equals(ItemEntry.AIR)) { - // Can't hide an untamed entity without having your hand empty - interactiveTag = InteractiveTag.MOUNT; - } - } - break; - case FOX: - if (javaIdentifierStripped.equals("sweet_berries")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case HOGLIN: - if (javaIdentifierStripped.equals("crimson_fungus")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case MINECART: - interactiveTag = InteractiveTag.RIDE_MINECART; - break; - case MINECART_CHEST: - case MINECART_COMMAND_BLOCK: - case MINECART_HOPPER: - interactiveTag = InteractiveTag.OPEN_CONTAINER; - break; - case OCELOT: - if (javaIdentifierStripped.equals("cod") || javaIdentifierStripped.equals("salmon")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case PANDA: - if (javaIdentifierStripped.equals("bamboo")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case PARROT: - if (javaIdentifierStripped.contains("seeds") || javaIdentifierStripped.equals("cookie")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case PIG: - if (javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("potato") || javaIdentifierStripped.equals("beetroot")) { - interactiveTag = InteractiveTag.FEED; - } else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) { - interactiveTag = InteractiveTag.MOUNT; - } - break; - case PIGLIN: - if (!entityMetadata.getFlags().getFlag(EntityFlag.BABY) && javaIdentifierStripped.equals("gold_ingot")) { - interactiveTag = InteractiveTag.BARTER; - } - break; - case RABBIT: - if (javaIdentifierStripped.equals("dandelion") || javaIdentifierStripped.equals("carrot") || javaIdentifierStripped.equals("golden_carrot")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case SHEEP: - if (javaIdentifierStripped.equals("wheat")) { - interactiveTag = InteractiveTag.FEED; - } else if (!entityMetadata.getFlags().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 (javaIdentifierStripped.equals("warped_fungus")) { - interactiveTag = InteractiveTag.FEED; - } else if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) { - interactiveTag = InteractiveTag.RIDE_STRIDER; - } - break; - case TURTLE: - if (javaIdentifierStripped.equals("seagrass")) { - interactiveTag = InteractiveTag.FEED; - } - break; - case VILLAGER: - if (entityMetadata.getInt(EntityData.VARIANT) != 14 && entityMetadata.getInt(EntityData.VARIANT) != 0 - && entityMetadata.getFloat(EntityData.SCALE) >= 0.75f) { // 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") && !entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) { - // Bone and untamed - can tame - interactiveTag = InteractiveTag.TAME; - } else if (WOLF_FOODS.contains(javaIdentifierStripped)) { - // Compatible food in hand - feed - // Sometimes just sits/stands when the wolf isn't hungry - there doesn't appear to be a way to fix this - interactiveTag = InteractiveTag.FEED; - } else if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED) && - entityMetadata.getLong(EntityData.OWNER_EID) == session.getPlayerEntity().getGeyserId()) { - // Tamed and owned by player - can sit/stand - interactiveTag = entityMetadata.getFlags().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().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue()); - session.getPlayerEntity().updateBedrockMetadata(session); - } else { - if (!session.getPlayerEntity().getMetadata().getString(EntityData.INTERACTIVE_TAG).isEmpty()) { - // No interactive tag should be sent - session.getPlayerEntity().getMetadata().remove(EntityData.INTERACTIVE_TAG); - session.getPlayerEntity().updateBedrockMetadata(session); - } - } - break; - case OPEN_INVENTORY: - if (!session.getInventory().isOpen()) { - ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) 0); - containerOpenPacket.setType(ContainerType.INVENTORY); - containerOpenPacket.setUniqueEntityId(-1); - containerOpenPacket.setBlockPosition(entity.getPosition().toInt()); - session.sendUpstreamPacket(containerOpenPacket); - session.getInventory().setOpen(true); - } - break; - } - } - - /** - * All interactive tags in enum form. For potential API usage. - */ - public enum InteractiveTag { - NONE(true), - 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(boolean isNone) { - this.value = ""; - } - - InteractiveTag(String value) { - this.value = "action.interact." + value; - } - - InteractiveTag() { - this.value = "action.interact." + name().toLowerCase(); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java deleted file mode 100644 index 2f6ba0d4..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockMovePlayerTranslator.java +++ /dev/null @@ -1,168 +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.connector.network.translators.bedrock.entity.player; - -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerPositionRotationPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerRotationPacket; -import com.github.steveice10.packetlib.packet.Packet; -import com.nukkitx.math.vector.Vector3d; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.MoveEntityAbsolutePacket; -import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; -import org.geysermc.connector.common.ChatColor; -import org.geysermc.connector.entity.player.PlayerEntity; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -@Translator(packet = MovePlayerPacket.class) -public class BedrockMovePlayerTranslator extends PacketTranslator { - - @Override - public void translate(MovePlayerPacket packet, GeyserSession session) { - PlayerEntity entity = session.getPlayerEntity(); - if (!session.isSpawned()) return; - - if (!session.getUpstream().isInitialized()) { - MoveEntityAbsolutePacket moveEntityBack = new MoveEntityAbsolutePacket(); - moveEntityBack.setRuntimeEntityId(entity.getGeyserId()); - moveEntityBack.setPosition(entity.getPosition()); - moveEntityBack.setRotation(entity.getBedrockRotation()); - moveEntityBack.setTeleported(true); - moveEntityBack.setOnGround(true); - session.sendUpstreamPacketImmediately(moveEntityBack); - return; - } - - session.setLastMovementTimestamp(System.currentTimeMillis()); - - // Send book update before the player moves - session.getBookEditCache().checkForSend(); - - if (session.confirmTeleport(packet.getPosition().toDouble().sub(0, EntityType.PLAYER.getOffset(), 0))) { - // head yaw, pitch, head yaw - Vector3f rotation = Vector3f.from(packet.getRotation().getY(), packet.getRotation().getX(), packet.getRotation().getY()); - - boolean positionChanged = !entity.getPosition().equals(packet.getPosition()); - boolean rotationChanged = !entity.getRotation().equals(rotation); - - // If only the pitch and yaw changed - // This isn't needed, but it makes the packets closer to vanilla - // It also means you can't "lag back" while only looking, in theory - if (!positionChanged && rotationChanged) { - ClientPlayerRotationPacket playerRotationPacket = new ClientPlayerRotationPacket( - packet.isOnGround(), packet.getRotation().getY(), packet.getRotation().getX()); - - entity.setRotation(rotation); - entity.setOnGround(packet.isOnGround()); - - session.sendDownstreamPacket(playerRotationPacket); - } else { - Vector3d position = session.getCollisionManager().adjustBedrockPosition(packet.getPosition(), packet.isOnGround()); - if (position != null) { // A null return value cancels the packet - if (isValidMove(session, packet.getMode(), entity.getPosition(), packet.getPosition())) { - Packet movePacket; - if (rotationChanged) { - // Send rotation updates as well - movePacket = new ClientPlayerPositionRotationPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ(), - packet.getRotation().getY(), packet.getRotation().getX()); - entity.setRotation(rotation); - } else { - // Rotation did not change; don't send an update with rotation - movePacket = new ClientPlayerPositionPacket(packet.isOnGround(), position.getX(), position.getY(), position.getZ()); - } - - // Compare positions here for void floor fix below before the player's position variable is set to the packet position - boolean notMovingUp = entity.getPosition().getY() >= packet.getPosition().getY(); - - entity.setPosition(packet.getPosition(), false); - entity.setOnGround(packet.isOnGround()); - - // Send final movement changes - session.sendDownstreamPacket(movePacket); - - if (notMovingUp) { - int floorY = position.getFloorY(); - if (floorY <= -38 && floorY >= -40) { - // Work around there being a floor at Y -40 and teleport the player below it - // Moving from below Y -40 to above the void floor works fine - //TODO: This will need to be changed for 1.17 - entity.setPosition(entity.getPosition().sub(0, 4f, 0)); - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); - movePlayerPacket.setPosition(entity.getPosition()); - movePlayerPacket.setRotation(entity.getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.TELEPORT); - movePlayerPacket.setTeleportationCause(MovePlayerPacket.TeleportationCause.BEHAVIOR); - session.sendUpstreamPacket(movePlayerPacket); - } - } - } else { - // Not a valid move - session.getConnector().getLogger().debug("Recalculating position..."); - session.getCollisionManager().recalculatePosition(); - } - } - } - } - - // Move parrots to match if applicable - if (entity.getLeftParrot() != null) { - entity.getLeftParrot().moveAbsolute(session, entity.getPosition(), entity.getRotation(), true, false); - } - if (entity.getRightParrot() != null) { - entity.getRightParrot().moveAbsolute(session, entity.getPosition(), entity.getRotation(), true, false); - } - } - - private boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) { - if (mode != MovePlayerPacket.Mode.NORMAL) - return true; - - double xRange = newPosition.getX() - currentPosition.getX(); - double yRange = newPosition.getY() - currentPosition.getY(); - double zRange = newPosition.getZ() - currentPosition.getZ(); - - if (xRange < 0) - xRange = -xRange; - if (yRange < 0) - yRange = -yRange; - if (zRange < 0) - zRange = -zRange; - - if ((xRange + yRange + zRange) > 100) { - session.getConnector().getLogger().debug(ChatColor.RED + session.getName() + " moved too quickly." + - " current position: " + currentPosition + ", new position: " + newPosition); - - return false; - } - - return true; - } -} - diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java deleted file mode 100644 index b8afe76c..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockSetPlayerGameTypeTranslator.java +++ /dev/null @@ -1,47 +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.connector.network.translators.bedrock.entity.player; - -import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -/** - * In vanilla Bedrock, if you have operator status, this sets the player's gamemode without confirmation from the server. - * Since we have a custom server option to request the gamemode, we just reset the gamemode and ignore this. - */ -@Translator(packet = SetPlayerGameTypePacket.class) -public class BedrockSetPlayerGameTypeTranslator extends PacketTranslator { - - @Override - public void translate(SetPlayerGameTypePacket packet, GeyserSession session) { - // no - SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); - playerGameTypePacket.setGamemode(session.getGameMode().ordinal()); - session.sendUpstreamPacket(playerGameTypePacket); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/world/BedrockLevelSoundEventTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/world/BedrockLevelSoundEventTranslator.java deleted file mode 100644 index c87692b8..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/world/BedrockLevelSoundEventTranslator.java +++ /dev/null @@ -1,50 +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.connector.network.translators.bedrock.world; - -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.utils.CooldownUtils; - -@Translator(packet = LevelSoundEventPacket.class) -public class BedrockLevelSoundEventTranslator extends PacketTranslator { - - @Override - public void translate(LevelSoundEventPacket packet, GeyserSession session) { - // lol what even :thinking: - session.sendUpstreamPacket(packet); - - // Yes, what even, but thankfully we can hijack this packet to send the cooldown - if (packet.getSound() == SoundEvent.ATTACK_NODAMAGE || packet.getSound() == SoundEvent.ATTACK || packet.getSound() == SoundEvent.ATTACK_STRONG) { - // Send a faux cooldown since Bedrock has no cooldown support - // Sent here because Java still sends a cooldown if the player doesn't hit anything but Bedrock always sends a sound - CooldownUtils.sendCooldown(session); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java deleted file mode 100644 index d04ce29d..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/chat/MessageTranslator.java +++ /dev/null @@ -1,273 +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.connector.network.translators.chat; - -import com.github.steveice10.mc.protocol.data.DefaultComponentSerializer; -import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.TextDecoration; -import net.kyori.adventure.text.renderer.TranslatableComponentRenderer; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.gson.legacyimpl.NBTLegacyHoverEventSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -public class MessageTranslator { - - // These are used for handling the translations of the messages - private static final TranslatableComponentRenderer RENDERER = TranslatableComponentRenderer.usingTranslationSource(new MinecraftTranslationRegistry()); - - // Construct our own {@link GsonComponentSerializer} since we need to change a setting - private static final GsonComponentSerializer GSON_SERIALIZER = GsonComponentSerializer.builder() - // Specify that we may be expecting legacy hover events - .legacyHoverEventSerializer(NBTLegacyHoverEventSerializer.get()) - .build(); - - // Store team colors for player names - private static final Map TEAM_FORMATS = new HashMap<>(); - - // Legacy formatting character - private static final String BASE = "\u00a7"; - - // Reset character - private static final String RESET = BASE + "r"; - - static { - TEAM_FORMATS.put(TeamColor.OBFUSCATED, TextDecoration.OBFUSCATED); - TEAM_FORMATS.put(TeamColor.BOLD, TextDecoration.BOLD); - TEAM_FORMATS.put(TeamColor.STRIKETHROUGH, TextDecoration.STRIKETHROUGH); - TEAM_FORMATS.put(TeamColor.ITALIC, TextDecoration.ITALIC); - - // Tell MCProtocolLib to use our serializer - DefaultComponentSerializer.set(GSON_SERIALIZER); - } - - /** - * Convert a Java message to the legacy format ready for bedrock - * - * @param message Java message - * @param locale Locale to use for translation strings - * @return Parsed and formatted message for bedrock - */ - public static String convertMessage(Component message, String locale) { - try { - // Get a Locale from the given locale string - Locale localeCode = Locale.forLanguageTag(locale.replace('_', '-')); - message = RENDERER.render(message, localeCode); - - String legacy = LegacyComponentSerializer.legacySection().serialize(message); - - // Strip strikethrough and underline as they are not supported on bedrock - legacy = legacy.replaceAll("\u00a7[mn]", ""); - - // Make color codes reset formatting like Java - // See https://minecraft.gamepedia.com/Formatting_codes#Usage - legacy = legacy.replaceAll("\u00a7([0-9a-f])", "\u00a7r\u00a7$1"); - legacy = legacy.replaceAll("\u00a7r\u00a7r", "\u00a7r"); - - return legacy; - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().debug(GSON_SERIALIZER.serialize(message)); - GeyserConnector.getInstance().getLogger().error("Failed to parse message", e); - - return ""; - } - } - - public static String convertMessage(String message, String locale) { - return convertMessage(GSON_SERIALIZER.deserialize(message), locale); - } - - public static String convertMessage(String message) { - return convertMessage(message, LanguageUtils.getDefaultLocale()); - } - - public static String convertMessage(Component message) { - return convertMessage(message, LanguageUtils.getDefaultLocale()); - } - - /** - * Verifies the message is valid JSON in case it's plaintext. Works around GsonComponentSeraializer not using lenient mode. - * See https://wiki.vg/Chat for messages sent in lenient mode, and for a description on leniency. - * - * @param message Potentially lenient JSON message - * @param locale Locale to use for translation strings - * @return Bedrock formatted message - */ - public static String convertMessageLenient(String message, String locale) { - if (message.trim().isEmpty()) { - return message; - } - - try { - return convertMessage(message, locale); - } catch (Exception ignored) { - String convertedMessage = convertMessage(convertToJavaMessage(message), locale); - - // We have to do this since Adventure strips the starting reset character - if (message.startsWith(RESET) && !convertedMessage.startsWith(RESET)) { - convertedMessage = RESET + convertedMessage; - } - - return convertedMessage; - } - } - - public static String convertMessageLenient(String message) { - return convertMessageLenient(message, LanguageUtils.getDefaultLocale()); - } - - /** - * Convert a Bedrock message string back to a format Java can understand - * - * @param message Message to convert - * @return The formatted JSON string - */ - public static String convertToJavaMessage(String message) { - Component component = LegacyComponentSerializer.legacySection().deserialize(message); - return GSON_SERIALIZER.serialize(component); - } - - /** - * Convert a {@link NamedTextColor} into a string for inserting into messages - * - * @param color {@link NamedTextColor} to convert - * @return The converted color string - */ - private static String getColor(NamedTextColor color) { - StringBuilder str = new StringBuilder(BASE); - if (color.equals(NamedTextColor.BLACK)) { - str.append("0"); - } else if (color.equals(NamedTextColor.DARK_BLUE)) { - str.append("1"); - } else if (color.equals(NamedTextColor.DARK_GREEN)) { - str.append("2"); - } else if (color.equals(NamedTextColor.DARK_AQUA)) { - str.append("3"); - } else if (color.equals(NamedTextColor.DARK_RED)) { - str.append("4"); - } else if (color.equals(NamedTextColor.DARK_PURPLE)) { - str.append("5"); - } else if (color.equals(NamedTextColor.GOLD)) { - str.append("6"); - } else if (color.equals(NamedTextColor.GRAY)) { - str.append("7"); - } else if (color.equals(NamedTextColor.DARK_GRAY)) { - str.append("8"); - } else if (color.equals(NamedTextColor.BLUE)) { - str.append("9"); - } else if (color.equals(NamedTextColor.GREEN)) { - str.append("a"); - } else if (color.equals(NamedTextColor.AQUA)) { - str.append("b"); - } else if (color.equals(NamedTextColor.RED)) { - str.append("c"); - } else if (color.equals(NamedTextColor.LIGHT_PURPLE)) { - str.append("d"); - } else if (color.equals(NamedTextColor.YELLOW)) { - str.append("e"); - } else if (color.equals(NamedTextColor.WHITE)) { - str.append("f"); - } else { - return ""; - } - - return str.toString(); - } - - /** - * Convert a {@link TextDecoration} into a string for inserting into messages - * - * @param format {@link TextDecoration} to convert - * @return The converted chat formatting string - */ - private static String getFormat(TextDecoration format) { - StringBuilder str = new StringBuilder(BASE); - switch (format) { - case OBFUSCATED: - str.append("k"); - break; - case BOLD: - str.append("l"); - break; - case STRIKETHROUGH: - str.append("m"); - break; - case UNDERLINED: - str.append("n"); - break; - case ITALIC: - str.append("o"); - break; - default: - return ""; - } - - return str.toString(); - } - - /** - * Convert a team color to a chat color - * - * @param teamColor Color or format to convert - * @return The chat color character - */ - public static String toChatColor(TeamColor teamColor) { - if (teamColor.equals(TeamColor.NONE)) { - return ""; - } - - NamedTextColor textColor = NamedTextColor.NAMES.value(teamColor.name().toLowerCase()); - if (textColor != null) { - return getColor(textColor); - } - - return getFormat(TEAM_FORMATS.get(teamColor)); - } - - /** - * Checks if the given message is over 256 characters (Java edition server chat limit) and sends a message to the user if it is - * - * @param message Message to check - * @param session {@link GeyserSession} for the user - * @return True if the message is too long, false if not - */ - public static boolean isTooLong(String message, GeyserSession session) { - if (message.length() > 256) { - session.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.chat.too_long", session.getLocale(), message.length())); - return true; - } - - return false; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/chat/MinecraftTranslationRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/chat/MinecraftTranslationRegistry.java deleted file mode 100644 index 95bf7b3d..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/chat/MinecraftTranslationRegistry.java +++ /dev/null @@ -1,76 +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.connector.network.translators.chat; - -import net.kyori.adventure.key.Key; -import net.kyori.adventure.translation.Translator; -import org.checkerframework.checker.nullness.qual.NonNull; -import org.checkerframework.checker.nullness.qual.Nullable; -import org.geysermc.connector.utils.LocaleUtils; - -import java.text.MessageFormat; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * This class is used for mapping a translation key with the already loaded Java locale data - * Used in MessageTranslator.java as part of the KyoriPowered/Adventure library - */ -public class MinecraftTranslationRegistry implements Translator { - @Override - public @NonNull Key name() { - return Key.key("geyser", "minecraft_translations"); - } - - @Override - public @Nullable MessageFormat translate(@NonNull String key, @NonNull Locale locale) { - // Get the locale string - String localeString = LocaleUtils.getLocaleString(key, locale.toString()); - - // Replace the `%s` with numbered inserts `{0}` - Pattern p = Pattern.compile("%s"); - Matcher m = p.matcher(localeString); - StringBuffer sb = new StringBuffer(); - int i = 0; - while (m.find()) { - m.appendReplacement(sb, "{" + (i++) + "}"); - } - m.appendTail(sb); - - // Replace the `%x$s` with numbered inserts `{x}` - p = Pattern.compile("%([0-9]+)\\$s"); - m = p.matcher(sb.toString()); - sb = new StringBuffer(); - while (m.find()) { - i = Integer.parseInt(m.group(1)) - 1; - m.appendReplacement(sb, "{" + i + "}"); - } - m.appendTail(sb); - - return new MessageFormat(sb.toString(), locale); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/BoundingBox.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/BoundingBox.java deleted file mode 100644 index a39e836b..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/BoundingBox.java +++ /dev/null @@ -1,52 +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.connector.network.translators.collision; - -import lombok.*; - -@Data -@AllArgsConstructor -public class BoundingBox { - private double middleX; - private double middleY; - private double middleZ; - - private double sizeX; - private double sizeY; - private double sizeZ; - - public void translate(double x, double y, double z) { - middleX += x; - middleY += y; - middleZ += z; - } - - public boolean checkIntersection(int offsetX, int offsetY, int offsetZ, BoundingBox otherBox) { - return (Math.abs((middleX + offsetX) - otherBox.getMiddleX()) * 2 < (sizeX + otherBox.getSizeX())) && - (Math.abs((middleY + offsetY) - otherBox.getMiddleY()) * 2 < (sizeY + otherBox.getSizeY())) && - (Math.abs((middleZ + offsetZ) - otherBox.getMiddleZ()) * 2 < (sizeZ + otherBox.getSizeZ())); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java deleted file mode 100644 index 203e4406..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionManager.java +++ /dev/null @@ -1,272 +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.connector.network.translators.collision; - -import com.nukkitx.math.vector.Vector3d; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlag; -import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; -import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; -import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; -import lombok.Getter; -import lombok.Setter; -import org.geysermc.connector.entity.player.PlayerEntity; -import org.geysermc.connector.entity.type.EntityType; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.translators.BlockCollision; - -import java.util.ArrayList; -import java.util.List; - -public class CollisionManager { - - private final GeyserSession session; - - @Getter - private BoundingBox playerBoundingBox; - - /** - * Whether the player is inside scaffolding - */ - @Setter - private boolean touchingScaffolding; - - /** - * Whether the player is on top of scaffolding - */ - @Setter - private boolean onScaffolding; - - /** - * Additional space where blocks are checked, which is helpful for fixing NoCheatPlus's Passable check. - * This check doesn't allow players right up against the block, so they must be pushed slightly away. - */ - public static final double COLLISION_TOLERANCE = 0.00001; - - public CollisionManager(GeyserSession session) { - this.session = session; - this.playerBoundingBox = new BoundingBox(0, 0, 0, 0.6, 1.8, 0.6); - } - - /** - * Updates the stored bounding box - * @param position The new position of the player - */ - public void updatePlayerBoundingBox(Vector3f position) { - updatePlayerBoundingBox(position.toDouble()); - } - - /** - * Updates the stored bounding box - * @param position The new position of the player - */ - public void updatePlayerBoundingBox(Vector3d position) { - updatePlayerBoundingBox(); - - playerBoundingBox.setMiddleX(position.getX()); - playerBoundingBox.setMiddleY(position.getY() + (playerBoundingBox.getSizeY() / 2)); - playerBoundingBox.setMiddleZ(position.getZ()); - } - - /** - * Updates the stored bounding box without passing a position, which currently just changes the height depending on if the player is sneaking. - */ - public void updatePlayerBoundingBox() { - if (playerBoundingBox == null) { - Vector3f playerPosition; - if (session.getPlayerEntity() == null) { - // Temporary position to prevent NullPointerException - playerPosition = Vector3f.ZERO; - } else { - playerPosition = session.getPlayerEntity().getPosition(); - } - playerBoundingBox = new BoundingBox(playerPosition.getX(), playerPosition.getY() + 0.9, playerPosition.getZ(), 0.6, 1.8, 0.6); - } else { - // According to the Minecraft Wiki, when sneaking: - // - In Bedrock Edition, the height becomes 1.65 blocks, allowing movement through spaces as small as 1.75 (2 - 1⁄4) blocks high. - // - In Java Edition, the height becomes 1.5 blocks. - // TODO: Have this depend on the player's literal bounding box variable - if (session.isSneaking()) { - playerBoundingBox.setSizeY(1.5); - } else { - playerBoundingBox.setSizeY(1.8); - } - } - } - - /** - * Adjust the Bedrock position before sending to the Java server to account for inaccuracies in movement between - * the two versions. - * - * @param bedrockPosition the current Bedrock position of the client - * @param onGround whether the Bedrock player is on the ground - * @return the position to send to the Java server, or null to cancel sending the packet - */ - public Vector3d adjustBedrockPosition(Vector3f bedrockPosition, boolean onGround) { - // We need to parse the float as a string since casting a float to a double causes us to - // lose precision and thus, causes players to get stuck when walking near walls - double javaY = bedrockPosition.getY() - EntityType.PLAYER.getOffset(); - - Vector3d position = Vector3d.from(Double.parseDouble(Float.toString(bedrockPosition.getX())), javaY, - Double.parseDouble(Float.toString(bedrockPosition.getZ()))); - - if (session.getConnector().getConfig().isCacheChunks()) { - // With chunk caching, we can do some proper collision checks - updatePlayerBoundingBox(position); - - // Correct player position - if (!correctPlayerPosition()) { - // Cancel the movement if it needs to be cancelled - recalculatePosition(); - return null; - } - - position = Vector3d.from(playerBoundingBox.getMiddleX(), - playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2), - playerBoundingBox.getMiddleZ()); - } else { - // When chunk caching is off, we have to rely on this - // It rounds the Y position up to the nearest 0.5 - // This snaps players to snap to the top of stairs and slabs like on Java Edition - // However, it causes issues such as the player floating on carpets - if (onGround) javaY = Math.ceil(javaY * 2) / 2; - position = position.up(javaY - position.getY()); - } - - return position; - } - - // TODO: This makes the player look upwards for some reason, rotation values must be wrong - public void recalculatePosition() { - PlayerEntity entity = session.getPlayerEntity(); - // Gravity might need to be reset... - SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); - entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); - entityDataPacket.getMetadata().putAll(entity.getMetadata()); - session.sendUpstreamPacket(entityDataPacket); - - MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); - movePlayerPacket.setRuntimeEntityId(entity.getGeyserId()); - movePlayerPacket.setPosition(entity.getPosition()); - movePlayerPacket.setRotation(entity.getBedrockRotation()); - movePlayerPacket.setMode(MovePlayerPacket.Mode.NORMAL); - session.sendUpstreamPacket(movePlayerPacket); - } - - public List getPlayerCollidableBlocks() { - List blocks = new ArrayList<>(); - - Vector3d position = Vector3d.from(playerBoundingBox.getMiddleX(), - playerBoundingBox.getMiddleY() - (playerBoundingBox.getSizeY() / 2), - playerBoundingBox.getMiddleZ()); - - // Loop through all blocks that could collide with the player - int minCollisionX = (int) Math.floor(position.getX() - ((playerBoundingBox.getSizeX() / 2) + COLLISION_TOLERANCE)); - int maxCollisionX = (int) Math.floor(position.getX() + (playerBoundingBox.getSizeX() / 2) + COLLISION_TOLERANCE); - - // Y extends 0.5 blocks down because of fence hitboxes - int minCollisionY = (int) Math.floor(position.getY() - 0.5); - - int maxCollisionY = (int) Math.floor(position.getY() + playerBoundingBox.getSizeY()); - - int minCollisionZ = (int) Math.floor(position.getZ() - ((playerBoundingBox.getSizeZ() / 2) + COLLISION_TOLERANCE)); - int maxCollisionZ = (int) Math.floor(position.getZ() + (playerBoundingBox.getSizeZ() / 2) + COLLISION_TOLERANCE); - - for (int y = minCollisionY; y < maxCollisionY + 1; y++) { - for (int x = minCollisionX; x < maxCollisionX + 1; x++) { - for (int z = minCollisionZ; z < maxCollisionZ + 1; z++) { - blocks.add(Vector3i.from(x, y, z)); - } - } - } - - return blocks; - } - - /** - * Returns false if the movement is invalid, and in this case it shouldn't be sent to the server and should be - * cancelled - * See {@link BlockCollision#correctPosition(GeyserSession, BoundingBox)} for more info - */ - public boolean correctPlayerPosition() { - - // These may be set to true by the correctPosition method in ScaffoldingCollision - touchingScaffolding = false; - onScaffolding = false; - - List collidableBlocks = getPlayerCollidableBlocks(); - - // Used when correction code needs to be run before the main correction - for (Vector3i blockPos : collidableBlocks) { - BlockCollision blockCollision = CollisionTranslator.getCollisionAt( - session, blockPos.getX(), blockPos.getY(), blockPos.getZ() - ); - if (blockCollision != null) { - blockCollision.beforeCorrectPosition(playerBoundingBox); - } - } - - // Main correction code - for (Vector3i blockPos : collidableBlocks) { - BlockCollision blockCollision = CollisionTranslator.getCollisionAt( - session, blockPos.getX(), blockPos.getY(), blockPos.getZ() - ); - if (blockCollision != null) { - if (!blockCollision.correctPosition(session, playerBoundingBox)) { - return false; - } - } - } - - updateScaffoldingFlags(); - - return true; - } - - /** - * Updates scaffolding entity flags - * Scaffolding needs to be checked per-move since it's a flag in Bedrock but Java does it client-side - */ - public void updateScaffoldingFlags() { - EntityFlags flags = session.getPlayerEntity().getMetadata().getFlags(); - boolean flagsChanged; - boolean isSneakingWithScaffolding = (touchingScaffolding || onScaffolding) && session.isSneaking(); - - flagsChanged = flags.getFlag(EntityFlag.FALL_THROUGH_SCAFFOLDING) != isSneakingWithScaffolding; - flagsChanged |= flags.getFlag(EntityFlag.OVER_SCAFFOLDING) != isSneakingWithScaffolding; - - flags.setFlag(EntityFlag.FALL_THROUGH_SCAFFOLDING, isSneakingWithScaffolding); - flags.setFlag(EntityFlag.OVER_SCAFFOLDING, isSneakingWithScaffolding); - - flagsChanged |= flags.getFlag(EntityFlag.IN_SCAFFOLDING) != touchingScaffolding; - flags.setFlag(EntityFlag.IN_SCAFFOLDING, touchingScaffolding); - - if (flagsChanged) { - session.getPlayerEntity().updateBedrockMetadata(session); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionRemapper.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionRemapper.java deleted file mode 100644 index aa0180ca..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionRemapper.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.connector.network.translators.collision; - -import java.lang.annotation.Repeatable; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -@Retention(value = RetentionPolicy.RUNTIME) -public @interface CollisionRemapper { - - /** - * Regex of block identifiers to apply this collision to - * Matches against just the block ID name, not including the namespace or parameters - */ - String regex(); - - /** - * Regex of block state parameters to apply this collision to - * Defaults to matching any value - */ - String paramRegex() default ".*"; - - /** - * Signals if a new instance needs to created for every block state - */ - boolean usesParams() default false; - - /** - * Signals if the default bounding boxes of this block as defined in collision.json should be passed to the - * constructor - */ - boolean passDefaultBoxes() default false; -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionTranslator.java deleted file mode 100644 index ad74371d..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/CollisionTranslator.java +++ /dev/null @@ -1,192 +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.connector.network.translators.collision; - -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.google.common.collect.BiMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.translators.BlockCollision; -import org.geysermc.connector.network.translators.collision.translators.EmptyCollision; -import org.geysermc.connector.network.translators.collision.translators.OtherCollision; -import org.geysermc.connector.network.translators.collision.translators.SolidCollision; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.FileUtils; -import org.reflections.Reflections; - -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.util.*; -import java.util.regex.Pattern; - -public class CollisionTranslator { - private static final Int2ObjectMap COLLISION_MAP = new Int2ObjectOpenHashMap<>(); - - public static void init() { - // If chunk caching is off then don't initialize - if (!GeyserConnector.getInstance().getConfig().isCacheChunks()) { - return; - } - - List> collisionTypes = new ArrayList<>(); - - Map, CollisionRemapper> annotationMap = new HashMap<>(); - - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.collision.translators") : new Reflections("org.geysermc.connector.network.translators.collision.translators"); - for (Class clazz : ref.getTypesAnnotatedWith(CollisionRemapper.class)) { - GeyserConnector.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName()); - - collisionTypes.add(clazz); - annotationMap.put(clazz, clazz.getAnnotation(CollisionRemapper.class)); - } - - // Load collision mappings file - InputStream stream = FileUtils.getResource("mappings/collision.json"); - - ArrayNode collisionList; - try { - collisionList = (ArrayNode) GeyserConnector.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError("Unable to load collision data", e); - } - - BiMap javaIdBlockMap = BlockTranslator.getJavaIdBlockMap(); - - // Map of classes that don't change based on parameters that have already been created - Map, BlockCollision> instantiatedCollision = new HashMap<>(); - - for (Map.Entry entry : javaIdBlockMap.entrySet()) { - BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getValue(), collisionTypes, annotationMap, instantiatedCollision, collisionList); - if (newCollision != null) { - instantiatedCollision.put(newCollision.getClass(), newCollision); - } - COLLISION_MAP.put(entry.getValue().intValue(), newCollision); - } - } - - private static BlockCollision instantiateCollision(String blockID, int numericBlockID, List> collisionTypes, Map, CollisionRemapper> annotationMap, Map, BlockCollision> instantiatedCollision, ArrayNode collisionList) { - - String blockName = blockID.split("\\[")[0].replace("minecraft:", ""); - String params = ""; - if (blockID.contains("[")) { - params = "[" + blockID.split("\\[")[1]; - } - int collisionIndex = BlockTranslator.JAVA_RUNTIME_ID_TO_COLLISION_INDEX.get(numericBlockID); - - for (Class type : collisionTypes) { - CollisionRemapper annotation = annotationMap.get(type); - - Pattern pattern = Pattern.compile(annotation.regex()); - Pattern paramsPattern = Pattern.compile(annotation.paramRegex()); - - if (pattern.matcher(blockName).find() && paramsPattern.matcher(params).find()) { - try { - if (!annotation.usesParams() && instantiatedCollision.containsKey(type)) { - return instantiatedCollision.get(type); - } - - // Return null when empty to save unnecessary checks - if (type == EmptyCollision.class) { - return null; - } - - BlockCollision collision; - if (annotation.passDefaultBoxes()) { - // Create an OtherCollision instance and get the bounding boxes - BoundingBox[] defaultBoxes = new OtherCollision((ArrayNode) collisionList.get(collisionIndex)).getBoundingBoxes(); - collision = (BlockCollision) type.getDeclaredConstructor(String.class, BoundingBox[].class).newInstance(params, defaultBoxes); - } else { - collision = (BlockCollision) type.getDeclaredConstructor(String.class).newInstance(params); - } - - // If there's an existing instance equal to this one, use that instead - for (Map.Entry, BlockCollision> entry : instantiatedCollision.entrySet()) { - if (entry.getValue().equals(collision)) { - collision = entry.getValue(); - break; - } - } - return collision; - } catch (IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) { - e.printStackTrace(); - return null; - } - } - } - - // Unless some of the low IDs are changed, which is unlikely, the first item should always be empty collision - if (collisionIndex == 0) { - if (instantiatedCollision.containsKey(EmptyCollision.class)) { - return instantiatedCollision.get(EmptyCollision.class); - } else { - return new EmptyCollision(params); - } - } - - // Unless some of the low IDs are changed, which is unlikely, the second item should always be full collision - if (collisionIndex == 1) { - if (instantiatedCollision.containsKey(SolidCollision.class)) { - return instantiatedCollision.get(SolidCollision.class); - } else { - return new SolidCollision(params); - } - } - - BlockCollision collision = new OtherCollision((ArrayNode) collisionList.get(collisionIndex)); - // If there's an existing instance equal to this one, use that instead - for (Map.Entry, BlockCollision> entry : instantiatedCollision.entrySet()) { - if (entry.getValue().equals(collision)) { - collision = entry.getValue(); - break; - } - } - - return collision; - } - - // Note: these reuse classes, so don't try to store more than once instance or coordinates will get overwritten - - public static BlockCollision getCollision(int blockID, int x, int y, int z) { - BlockCollision collision = COLLISION_MAP.get(blockID); - if (collision != null) { - collision.setPosition(x, y, z); - } - return collision; - } - - - public static BlockCollision getCollisionAt(GeyserSession session, int x, int y, int z) { - try { - return getCollision(session.getConnector().getWorldManager().getBlockAt(session, x, y, z), x, y, z); - } catch (ArrayIndexOutOfBoundsException e) { - // Block out of world - return null; - } - } - -} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/BlockCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/BlockCollision.java deleted file mode 100644 index 573a5564..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/BlockCollision.java +++ /dev/null @@ -1,154 +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.connector.network.translators.collision.translators; - -import com.nukkitx.math.vector.Vector3d; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.CollisionManager; -import org.geysermc.connector.network.translators.collision.BoundingBox; - -@EqualsAndHashCode -public class BlockCollision { - - @Getter - protected BoundingBox[] boundingBoxes; - - protected int x; - protected int y; - protected int z; - - /** - * This is used for the step up logic. - * Usually, the player can only step up a block if they are on the same Y level as its bottom face or higher - * For snow layers, due to its beforeCorrectPosition method the player can be slightly below (0.125 blocks) and - * still need to step up - * This used to be 0 but for now this has been set to 1 as it fixes bed collision - * I didn't just set it for beds because other collision may also be slightly raised off the ground. - * If this causes any problems, change this back to 0 and add an exception for beds. - */ - @EqualsAndHashCode.Exclude - protected double pushUpTolerance = 1; - - public void setPosition(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** - * Overridden in classes like SnowCollision and GrassPathCollision when correction code needs to be run before the - * main correction - */ - public void beforeCorrectPosition(BoundingBox playerCollision) {} - - /** - * Returns false if the movement is invalid, and in this case it shouldn't be sent to the server and should be - * cancelled - * While the Java server should do this, it could result in false flags by anticheat - * This functionality is currently only used in 6 or 7 layer snow - */ - public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) { - double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - for (BoundingBox b : this.boundingBoxes) { - double boxMinY = (b.getMiddleY() + y) - (b.getSizeY() / 2); - double boxMaxY = (b.getMiddleY() + y) + (b.getSizeY() / 2); - if (b.checkIntersection(x, y, z, playerCollision) && (playerMinY + pushUpTolerance) >= boxMinY) { - // Max steppable distance in Minecraft as far as we know is 0.5625 blocks (for beds) - if (boxMaxY - playerMinY <= 0.5625) { - playerCollision.translate(0, boxMaxY - playerMinY, 0); - // Update player Y for next collision box - playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - } - } - - // Make player collision slightly bigger to pick up on blocks that could cause problems with Passable - playerCollision.setSizeX(playerCollision.getSizeX() + CollisionManager.COLLISION_TOLERANCE * 2); - playerCollision.setSizeZ(playerCollision.getSizeZ() + CollisionManager.COLLISION_TOLERANCE * 2); - - // If the player still intersects the block, then push them out - // This fixes NoCheatPlus's Passable check - // This check doesn't allow players right up against the block, so they must be pushed slightly away - if (b.checkIntersection(x, y, z, playerCollision)) { - Vector3d relativePlayerPosition = Vector3d.from(playerCollision.getMiddleX() - x, - playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2) - y, - playerCollision.getMiddleZ() - z); - - Vector3d northFacePos = Vector3d.from(b.getMiddleX(), - b.getMiddleY(), - b.getMiddleZ() - (b.getSizeZ() / 2)); - - Vector3d southFacePos = Vector3d.from(b.getMiddleX(), - b.getMiddleY(), - b.getMiddleZ() + (b.getSizeZ() / 2)); - - Vector3d eastFacePos = Vector3d.from(b.getMiddleX() + (b.getSizeX() / 2), - b.getMiddleY(), - b.getMiddleZ()); - - Vector3d westFacePos = Vector3d.from(b.getMiddleX() - (b.getSizeX() / 2), - b.getMiddleY(), - b.getMiddleZ()); - - double translateDistance = northFacePos.getZ() - relativePlayerPosition.getZ() - (playerCollision.getSizeZ() / 2); - if (Math.abs(translateDistance) < CollisionManager.COLLISION_TOLERANCE * 1.1) { - playerCollision.translate(0, 0, translateDistance); - } - - translateDistance = southFacePos.getZ() - relativePlayerPosition.getZ() + (playerCollision.getSizeZ() / 2); - if (Math.abs(translateDistance) < CollisionManager.COLLISION_TOLERANCE * 1.1) { - playerCollision.translate(0, 0, translateDistance); - } - - translateDistance = eastFacePos.getX() - relativePlayerPosition.getX() + (playerCollision.getSizeX() / 2); - if (Math.abs(translateDistance) < CollisionManager.COLLISION_TOLERANCE * 1.1) { - playerCollision.translate(translateDistance, 0, 0); - } - - translateDistance = westFacePos.getX() - relativePlayerPosition.getX() - (playerCollision.getSizeX() / 2); - if (Math.abs(translateDistance) < CollisionManager.COLLISION_TOLERANCE * 1.1) { - playerCollision.translate(translateDistance, 0, 0); - } - } - - // Set the collision size back to normal - playerCollision.setSizeX(0.6); - playerCollision.setSizeZ(0.6); - } - - return true; - } - - public boolean checkIntersection(BoundingBox playerCollision) { - for (BoundingBox b : boundingBoxes) { - if (b.checkIntersection(x, y, z, playerCollision)) { - return true; - } - } - return false; - } -} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/DoorCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/DoorCollision.java deleted file mode 100644 index c9826998..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/DoorCollision.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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.BoundingBox; -import org.geysermc.connector.network.translators.collision.CollisionRemapper; - -@CollisionRemapper(regex = "_door$", usesParams = true, passDefaultBoxes = true) -public class DoorCollision extends BlockCollision { - /** - * 1 = north - * 2 = east - * 3 = south - * 4 = west - */ - private int facing; - - public DoorCollision(String params, BoundingBox[] defaultBoxes) { - super(); - boundingBoxes = defaultBoxes; - if (params.contains("facing=north")) { - facing = 1; - } else if (params.contains("facing=east")) { - facing = 2; - } else if (params.contains("facing=south")) { - facing = 3; - } else if (params.contains("facing=west")) { - facing = 4; - } - - // If the door is open it changes direction - if (params.contains("open=true")) { - facing = facing % 2 + 1; - } - } - - @Override - public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) { - boolean result = super.correctPosition(session, playerCollision); - // Hack to prevent false positives - playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001); - - // Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock) - if (this.checkIntersection(playerCollision)) { - switch (facing) { - case 1: // North - playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.5125); - break; - case 2: // East - playerCollision.setMiddleX(Math.floor(playerCollision.getMiddleX()) + 0.5125); - break; - case 3: // South - playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.4875); - break; - case 4: // West - playerCollision.setMiddleX(Math.floor(playerCollision.getMiddleX()) + 0.4875); - break; - } - } - - playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001); - return result; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/EmptyCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/EmptyCollision.java deleted file mode 100644 index 0a8a6a00..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/EmptyCollision.java +++ /dev/null @@ -1,35 +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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.translators.collision.BoundingBox; - -public class EmptyCollision extends BlockCollision { - public EmptyCollision(String params) { - super(); - boundingBoxes = new BoundingBox[0]; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/GrassPathCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/GrassPathCollision.java deleted file mode 100644 index 4d59171e..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/GrassPathCollision.java +++ /dev/null @@ -1,49 +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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.translators.collision.BoundingBox; -import org.geysermc.connector.network.translators.collision.CollisionRemapper; - -@CollisionRemapper(regex = "^grass_path$", passDefaultBoxes = true) -public class GrassPathCollision extends BlockCollision { - public GrassPathCollision(String params, BoundingBox[] defaultBoxes) { - super(); - boundingBoxes = defaultBoxes; - } - - // Needs to run before the main correction code or it can move the player into blocks - // This is counteracted by the main collision code pushing them out - @Override - public void beforeCorrectPosition(BoundingBox playerCollision) { - // In Bedrock, grass paths are small blocks so the player must be pushed down - double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - // If the player is in the buggy area, push them down - if (playerMinY == y + 1) { - playerCollision.translate(0, -0.0625, 0); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/OtherCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/OtherCollision.java deleted file mode 100644 index b31dd919..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/OtherCollision.java +++ /dev/null @@ -1,53 +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.connector.network.translators.collision.translators; - -import com.fasterxml.jackson.databind.node.ArrayNode; -import org.geysermc.connector.network.translators.collision.BoundingBox; - -import java.util.Arrays; -import java.util.Comparator; - -public class OtherCollision extends BlockCollision { - - public OtherCollision(ArrayNode collisionList) { - super(); - boundingBoxes = new BoundingBox[collisionList.size()]; - - for (int i = 0; i < collisionList.size(); i++) { - ArrayNode collisionBoxArray = (ArrayNode) collisionList.get(i); - boundingBoxes[i] = new BoundingBox(collisionBoxArray.get(0).asDouble(), - collisionBoxArray.get(1).asDouble(), - collisionBoxArray.get(2).asDouble(), - collisionBoxArray.get(3).asDouble(), - collisionBoxArray.get(4).asDouble(), - collisionBoxArray.get(5).asDouble()); - } - - // Sorting by lowest Y first fixes some bugs - Arrays.sort(boundingBoxes, Comparator.comparingDouble(BoundingBox::getMiddleY)); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/ScaffoldingCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/ScaffoldingCollision.java deleted file mode 100644 index ba997d30..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/ScaffoldingCollision.java +++ /dev/null @@ -1,72 +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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.BoundingBox; -import org.geysermc.connector.network.translators.collision.CollisionRemapper; - -/** - * In order for scaffolding to work on Bedrock, entity flags need to be sent to the player - */ -@CollisionRemapper(regex = "^scaffolding$", usesParams = true, passDefaultBoxes = true) -public class ScaffoldingCollision extends BlockCollision { - public ScaffoldingCollision(String params, BoundingBox[] defaultBoxes) { - super(); - boundingBoxes = defaultBoxes; - } - - @Override - public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) { - // Hack to not check below the player - playerCollision.setSizeY(playerCollision.getSizeY() - 0.001); - playerCollision.setMiddleY(playerCollision.getMiddleY() + 0.002); - - boolean intersected = this.checkIntersection(playerCollision); - - playerCollision.setSizeY(playerCollision.getSizeY() + 0.001); - playerCollision.setMiddleY(playerCollision.getMiddleY() - 0.002); - - if (intersected) { - session.getCollisionManager().setTouchingScaffolding(true); - session.getCollisionManager().setOnScaffolding(true); - } else { - // Hack to check slightly below the player - playerCollision.setSizeY(playerCollision.getSizeY() + 0.001); - playerCollision.setMiddleY(playerCollision.getMiddleY() - 0.002); - - if (this.checkIntersection(playerCollision)) { - session.getCollisionManager().setOnScaffolding(true); - } - - playerCollision.setSizeY(playerCollision.getSizeY() - 0.001); - playerCollision.setMiddleY(playerCollision.getMiddleY() + 0.002); - } - - // Normal move correction isn't really needed for scaffolding - return true; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/SnowCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/SnowCollision.java deleted file mode 100644 index 37ea4a1b..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/SnowCollision.java +++ /dev/null @@ -1,103 +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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.BoundingBox; -import org.geysermc.connector.network.translators.collision.CollisionRemapper; - -import java.util.regex.Pattern; -import java.util.regex.Matcher; - -@CollisionRemapper(regex = "^snow$", usesParams = true) -public class SnowCollision extends BlockCollision { - private final int layers; - - public SnowCollision(String params) { - super(); - Pattern layersPattern = Pattern.compile("layers=([0-8])"); - Matcher matcher = layersPattern.matcher(params); - //noinspection ResultOfMethodCallIgnored - matcher.find(); - - // Hitbox is 1 layer less (you sink in 1 layer) - layers = Integer.parseInt(matcher.group(1)); - - if (layers > 1) { - boundingBoxes = new BoundingBox[] { - // Take away 1 because you can go 1 layer into snow layers - new BoundingBox(0.5, ((layers - 1) * 0.125) / 2, 0.5, - 1, (layers - 1) * 0.125, 1) - }; - } else { - // Single layers have no collision - boundingBoxes = new BoundingBox[0]; - } - - pushUpTolerance = 0.125; - } - - // Needs to run before the main correction code or it can move the player into blocks - // This is counteracted by the main collision code pushing them out - @Override - public void beforeCorrectPosition(BoundingBox playerCollision) { - // In Bedrock, snow layers round down to half blocks but you can't sink into them at all - // This means the collision each half block reaches above where it should be on Java so the player has to be - // pushed down - if (layers == 4 || layers == 8) { - double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2); - // If the player is in the buggy area, push them down - if (playerMinY > boxMaxY && - playerMinY <= (boxMaxY + 0.125)) { - playerCollision.translate(0, boxMaxY - playerMinY, 0); - } - } - } - - @Override - public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) { - // Hack to prevent false positives - playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001); - - if (this.checkIntersection(playerCollision)) { - double playerMinY = playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2); - double boxMaxY = (boundingBoxes[0].getMiddleY() + y) + (boundingBoxes[0].getSizeY() / 2); - // If the player actually can't step onto it (they can step onto it from other snow layers) - if ((boxMaxY - playerMinY) > 0.5) { - // Cancel the movement - return false; - } - } - - playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001); - return super.correctPosition(session, playerCollision); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/SolidCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/SolidCollision.java deleted file mode 100644 index 05791501..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/SolidCollision.java +++ /dev/null @@ -1,39 +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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.translators.collision.BoundingBox; -import org.geysermc.connector.network.translators.collision.CollisionRemapper; - -@CollisionRemapper(regex = "shulker_box$") // These have no collision in the mappings as it depends on the NBT data -public class SolidCollision extends BlockCollision { - public SolidCollision(String params) { - super(); - boundingBoxes = new BoundingBox[]{ - new BoundingBox(0.5, 0.5, 0.5, 1, 1, 1) - }; - } -} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/TrapdoorCollision.java b/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/TrapdoorCollision.java deleted file mode 100644 index 63e97e1d..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/collision/translators/TrapdoorCollision.java +++ /dev/null @@ -1,105 +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.connector.network.translators.collision.translators; - -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.collision.BoundingBox; -import org.geysermc.connector.network.translators.collision.CollisionRemapper; - -@CollisionRemapper(regex = "_trapdoor$", usesParams = true, passDefaultBoxes = true) -public class TrapdoorCollision extends BlockCollision { - /** - * 1 = north - * 2 = east - * 3 = south - * 4 = west - * 5 = up - * 6 = down - */ - private int facing; - - public TrapdoorCollision(String params, BoundingBox[] defaultBoxes) { - super(); - boundingBoxes = defaultBoxes; - if (params.contains("open=true")) { - if (params.contains("facing=north")) { - facing = 1; - } else if (params.contains("facing=east")) { - facing = 2; - } else if (params.contains("facing=south")) { - facing = 3; - } else if (params.contains("facing=west")) { - facing = 4; - } - } else { - if (params.contains("half=bottom")) { - // Up - facing = 5; - } else { - // Down - facing = 6; - } - } - } - - @Override - public boolean correctPosition(GeyserSession session, BoundingBox playerCollision) { - boolean result = super.correctPosition(session, playerCollision); - // Hack to prevent false positives - playerCollision.setSizeX(playerCollision.getSizeX() - 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() - 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() - 0.0001); - - // Check for door bug (doors are 0.1875 blocks thick on Java but 0.1825 blocks thick on Bedrock) - if (this.checkIntersection(playerCollision)) { - switch (facing) { - case 1: // North - playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.5125); - break; - case 3: // South - playerCollision.setMiddleZ(Math.floor(playerCollision.getMiddleZ()) + 0.4875); - break; - case 4: // West - playerCollision.setMiddleX(Math.floor(playerCollision.getMiddleX()) + 0.4875); - break; - case 6: // Down - playerCollision.setMiddleY(Math.floor( - playerCollision.getMiddleY() - (playerCollision.getSizeY() / 2) - ) + 0.0125 + (playerCollision.getSizeY() / 2)); - break; - case 2: - case 5: - // Up-facing and east-facing trapdoors work fine - break; - } - } - - playerCollision.setSizeX(playerCollision.getSizeX() + 0.0001); - playerCollision.setSizeY(playerCollision.getSizeY() + 0.0001); - playerCollision.setSizeZ(playerCollision.getSizeZ() + 0.0001); - return result; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java index 2dd36e6e..4c58235a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/Effect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 @@ package org.geysermc.connector.network.translators.effect; -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; -import org.geysermc.connector.network.session.GeyserSession; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.Setter; -/** - * Represents an effect capable of translating itself into bedrock - */ -public interface Effect { - /** - * Translates the given {@link ServerPlayEffectPacket} into bedrock and sends it upstream. - * - * @param session GeyserSession - * @param packet the effect packet to handle - */ - void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet); -} +@Getter +@Setter +@AllArgsConstructor +public class Effect { + + private String javaName; + private String bedrockName; + private String type; + private int data; + private String identifier; + +} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java index c71aa4f1..50888090 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/effect/EffectRegistry.java @@ -1,39 +1,37 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.effect; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.data.game.world.effect.SoundEffect; import com.github.steveice10.mc.protocol.data.game.world.particle.ParticleType; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.data.SoundEvent; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import lombok.NonNull; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.FileUtils; @@ -48,22 +46,11 @@ import java.util.Map; */ public class EffectRegistry { - public static final Map SOUND_EFFECTS = new HashMap<>(); + public static final Map EFFECTS = new HashMap<>(); public static final Int2ObjectMap RECORDS = new Int2ObjectOpenHashMap<>(); - /** - * Java particle type to Bedrock particle ID - * Used for area effect clouds. - */ - private static final Object2IntMap PARTICLE_TO_ID = new Object2IntOpenHashMap<>(); - /** - * Java particle type to Bedrock level event - */ - private static final Map PARTICLE_TO_LEVEL_EVENT = new HashMap<>(); - /** - * Java particle type to Bedrock namespaced string ID - */ - private static final Map PARTICLE_TO_STRING = new HashMap<>(); + private static Map particleTypeMap = new HashMap<>(); + private static Map particleStringMap = new HashMap<>(); public static void init() { // no-op @@ -80,24 +67,22 @@ public class EffectRegistry { } Iterator> particlesIterator = particleEntries.fields(); - try { - while (particlesIterator.hasNext()) { - Map.Entry entry = particlesIterator.next(); - JsonNode bedrockId = entry.getValue().get("bedrockId"); - JsonNode bedrockIdNumeric = entry.getValue().get("bedrockNumericId"); - JsonNode eventType = entry.getValue().get("eventType"); - if (bedrockIdNumeric != null) { - PARTICLE_TO_ID.put(ParticleType.valueOf(entry.getKey().toUpperCase()), bedrockIdNumeric.asInt()); - } - if (bedrockId != null) { - PARTICLE_TO_STRING.put(ParticleType.valueOf(entry.getKey().toUpperCase()), bedrockId.asText()); - } - if (eventType != null) { - PARTICLE_TO_LEVEL_EVENT.put(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(eventType.asText().toUpperCase())); + while (particlesIterator.hasNext()) { + Map.Entry entry = particlesIterator.next(); + try { + particleTypeMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), LevelEventType.valueOf(entry.getValue().asText().toUpperCase())); + } catch (IllegalArgumentException e1) { + try { + particleStringMap.put(ParticleType.valueOf(entry.getKey().toUpperCase()), entry.getValue().asText()); + GeyserConnector.getInstance().getLogger().debug("Force to map particle " + + entry.getKey() + + "=>" + + entry.getValue().asText() + + ", it will take effect."); + } catch (IllegalArgumentException e2){ + GeyserConnector.getInstance().getLogger().warning("Fail to map particle " + entry.getKey() + "=>" + entry.getValue().asText()); } } - } catch (Exception e) { - e.printStackTrace(); } /* Load effects */ @@ -112,78 +97,27 @@ public class EffectRegistry { Iterator> effectsIterator = effects.fields(); while (effectsIterator.hasNext()) { Map.Entry entry = effectsIterator.next(); - JsonNode node = entry.getValue(); - try { - String type = node.get("type").asText(); - SoundEffect javaEffect = null; - Effect effect = null; - switch (type) { - case "soundLevel": { - javaEffect = SoundEffect.valueOf(entry.getKey()); - LevelEventType levelEventType = LevelEventType.valueOf(node.get("name").asText()); - int data = node.has("data") ? node.get("data").intValue() : 0; - effect = new SoundLevelEffect(levelEventType, data); - break; - } - case "soundEvent": { - javaEffect = SoundEffect.valueOf(entry.getKey()); - SoundEvent soundEvent = 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; - effect = new SoundEventEffect(soundEvent, identifier, extraData); - break; - } - case "playSound": { - javaEffect = SoundEffect.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() : false; - float pitchMul = node.has("pitch_mul") ? node.get("pitch_mul").floatValue() : 1.0f; - float pitchAdd = node.has("pitch_add") ? node.get("pitch_add").floatValue() : 0.0f; - boolean relative = node.has("relative") ? node.get("relative").booleanValue() : true; - effect = new PlaySoundEffect(name, volume, pitchSub, pitchMul, pitchAdd, relative); - break; - } - case "record": { - JsonNode records = entry.getValue().get("records"); - Iterator> recordsIterator = records.fields(); - while (recordsIterator.hasNext()) { - Map.Entry recordEntry = recordsIterator.next(); - RECORDS.put(Integer.parseInt(recordEntry.getKey()), SoundEvent.valueOf(recordEntry.getValue().asText())); - } - break; - } + // Separate records database since they're handled differently between the two versions + if (entry.getValue().has("records")) { + JsonNode records = entry.getValue().get("records"); + Iterator> recordsIterator = records.fields(); + while (recordsIterator.hasNext()) { + Map.Entry recordEntry = recordsIterator.next(); + RECORDS.put(Integer.parseInt(recordEntry.getKey()), SoundEvent.valueOf(recordEntry.getValue().asText())); } - if (javaEffect != null) { - SOUND_EFFECTS.put(javaEffect, effect); - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().warning("Failed to map sound effect " + entry.getKey() + " : " + e.toString()); } + String identifier = (entry.getValue().has("identifier")) ? entry.getValue().get("identifier").asText() : ""; + int data = (entry.getValue().has("data")) ? entry.getValue().get("data").asInt() : -1; + Effect effect = new Effect(entry.getKey(), entry.getValue().get("name").asText(), entry.getValue().get("type").asText(), data, identifier); + EFFECTS.put(entry.getKey(), effect); } } - /** - * @param type the Java particle to search for - * @return the Bedrock integer ID of the particle, or -1 if it does not exist - */ - public static int getParticleId(@NonNull ParticleType type) { - return PARTICLE_TO_ID.getOrDefault(type, -1); - } - - /** - * @param type the Java particle to search for - * @return the level event equivalent Bedrock particle - */ public static LevelEventType getParticleLevelEventType(@NonNull ParticleType type) { - return PARTICLE_TO_LEVEL_EVENT.getOrDefault(type, null); + return particleTypeMap.getOrDefault(type, null); } - /** - * @param type the Java particle to search for - * @return the namespaced ID equivalent for Bedrock - */ - public static String getParticleString(@NonNull ParticleType type) { - return PARTICLE_TO_STRING.getOrDefault(type, null); + public static String getParticleString(@NonNull ParticleType type){ + return particleStringMap.getOrDefault(type, null); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java deleted file mode 100644 index 2b130240..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/PlaySoundEffect.java +++ /dev/null @@ -1,80 +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.connector.network.translators.effect; - -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.packet.PlaySoundPacket; -import lombok.Value; -import org.geysermc.connector.network.session.GeyserSession; - -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; - -@Value -public class PlaySoundEffect implements Effect { - /** - * Bedrock playsound identifier - */ - String name; - - /** - * Volume of the sound - */ - float volume; - - /** - * If true, the initial value used for random pitch is the difference between two random floats. - * If false, it is a single random float - */ - boolean pitchSub; - - /** - * Multiplier for random pitch value - */ - float pitchMul; - - /** - * Constant addition to random pitch value after multiplier - */ - float pitchAdd; - - /** - * True if the sound is meant to be played in 3d space - */ - boolean relative; - - @Override - public void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet) { - Random rand = ThreadLocalRandom.current(); - PlaySoundPacket playSoundPacket = new PlaySoundPacket(); - playSoundPacket.setSound(name); - playSoundPacket.setPosition(!relative ? session.getPlayerEntity().getPosition() : Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); - playSoundPacket.setVolume(volume); - playSoundPacket.setPitch((pitchSub ? (rand.nextFloat() - rand.nextFloat()) : rand.nextFloat()) * pitchMul + pitchAdd); //replicates java client randomness - session.sendUpstreamPacket(playSoundPacket); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java deleted file mode 100644 index e9d876c7..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundEventEffect.java +++ /dev/null @@ -1,63 +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.connector.network.translators.effect; - -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import lombok.Value; -import org.geysermc.connector.network.session.GeyserSession; - -@Value -public class SoundEventEffect implements Effect { - /** - * Bedrock sound event - */ - SoundEvent soundEvent; - - /** - * Entity identifier. Usually an empty string - */ - String identifier; - - /** - * Extra data. Usually -1 - */ - int extraData; - - @Override - public void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet) { - LevelSoundEventPacket levelSoundEvent = new LevelSoundEventPacket(); - levelSoundEvent.setSound(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.setBabySound(false); - session.sendUpstreamPacket(levelSoundEvent); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java b/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java deleted file mode 100644 index 85dea329..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/effect/SoundLevelEffect.java +++ /dev/null @@ -1,55 +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.connector.network.translators.effect; - -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerPlayEffectPacket; -import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import lombok.Value; -import org.geysermc.connector.network.session.GeyserSession; - -@Value -public class SoundLevelEffect implements Effect { - /** - * Bedrock level event type - */ - LevelEventType levelEventType; - - /** - * Event data. Usually 0 - */ - int data; - - @Override - public void handleEffectPacket(GeyserSession session, ServerPlayEffectPacket packet) { - LevelEventPacket eventPacket = new LevelEventPacket(); - eventPacket.setType(levelEventType); - eventPacket.setData(data); - eventPacket.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f)); - session.sendUpstreamPacket(eventPacket); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java index fb487bea..f301d2b5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/AnvilInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.message.Message; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientRenameItemPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.google.gson.JsonSyntaxException; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.protocol.bedrock.data.inventory.*; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; import java.util.List; -import java.util.stream.Collectors; public class AnvilInventoryTranslator extends BlockInventoryTranslator { public AnvilInventoryTranslator() { @@ -48,7 +46,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { @Override public int bedrockSlotToJava(InventoryActionData action) { - if (action.getSource().getContainerId() == ContainerId.UI) { + if (action.getSource().getContainerId() == ContainerId.CURSOR) { switch (action.getSlot()) { case 1: return 0; @@ -58,9 +56,6 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { return 2; } } - if (action.getSource().getContainerId() == ContainerId.ANVIL_RESULT) { - return 2; - } return super.bedrockSlotToJava(action); } @@ -106,15 +101,9 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { } if (itemName != null) { String rename; - NbtMap tag = itemName.getTag(); - if (tag != null && tag.containsKey("display")) { - String name = tag.getCompound("display").getString("Name"); - try { - Component component = GsonComponentSerializer.gson().deserialize(name); - rename = LegacyComponentSerializer.legacySection().serialize(component); - } catch (JsonSyntaxException e) { - rename = name; - } + com.nukkitx.nbt.tag.CompoundTag tag = itemName.getTag(); + if (tag != null) { + rename = tag.getCompound("display").getString("Name"); } else { rename = ""; } @@ -122,13 +111,7 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { session.sendDownstreamPacket(renameItemPacket); } if (anvilResult != null) { - //Strip unnecessary actions - List strippedActions = actions.stream() - .filter(action -> action.getSource().getContainerId() == ContainerId.ANVIL_RESULT - || (action.getSource().getType() == InventorySource.Type.CONTAINER - && !(action.getSource().getContainerId() == ContainerId.UI && action.getSlot() != 0))) - .collect(Collectors.toList()); - super.translateActions(session, inventory, strippedActions); + //client will send another packet to grab anvil output return; } @@ -137,21 +120,17 @@ public class AnvilInventoryTranslator extends BlockInventoryTranslator { @Override public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - if (slot == 0) { + if (slot >= 0 && slot <= 2) { ItemStack item = inventory.getItem(slot); if (item != null) { String rename; CompoundTag tag = item.getNbt(); if (tag != null) { CompoundTag displayTag = tag.get("display"); - if (displayTag != null && displayTag.contains("Name")) { + if (displayTag != null) { String itemName = displayTag.get("Name").getValue().toString(); - try { - Component component = GsonComponentSerializer.gson().deserialize(itemName); - rename = LegacyComponentSerializer.legacySection().serialize(component); - } catch (JsonSyntaxException e) { - rename = itemName; - } + Message message = Message.fromString(itemName); + rename = message.getText(); } else { rename = ""; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java index ca241e29..5deb0370 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BaseInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java index 8f70189d..ab410ea8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BlockInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.nukkitx.protocol.bedrock.data.ContainerType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -39,7 +40,7 @@ public class BlockInventoryTranslator extends BaseInventoryTranslator { public BlockInventoryTranslator(int size, String javaBlockIdentifier, ContainerType containerType, InventoryUpdater updater) { super(size); - int javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); + BlockState javaBlockState = BlockTranslator.getJavaBlockState(javaBlockIdentifier); int blockId = BlockTranslator.getBedrockBlockId(javaBlockState); this.holder = new BlockInventoryHolder(blockId, containerType); this.updater = updater; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java index 2242a979..acda7c91 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/BrewingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java index 3bc587b1..13684a60 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/ChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java index 18cbbae7..e31eb1e3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/CraftingInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,33 +26,65 @@ package org.geysermc.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.InventorySource; +import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; import org.geysermc.connector.utils.InventoryUtils; import java.util.List; -public class CraftingInventoryTranslator extends BlockInventoryTranslator { +public class CraftingInventoryTranslator extends BaseInventoryTranslator { + private final InventoryUpdater updater; + public CraftingInventoryTranslator() { - super(10, "minecraft:crafting_table", ContainerType.WORKBENCH, new CursorInventoryUpdater()); + super(10); + this.updater = new CursorInventoryUpdater(); + } + + @Override + public void prepareInventory(GeyserSession session, Inventory inventory) { + // + } + + @Override + public void openInventory(GeyserSession session, Inventory inventory) { + ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.WORKBENCH.id()); + containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); + containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); + session.sendUpstreamPacket(containerOpenPacket); + } + + @Override + public void closeInventory(GeyserSession session, Inventory inventory) { + // + } + + @Override + public void updateInventory(GeyserSession session, Inventory inventory) { + updater.updateInventory(this, session, inventory); + } + + @Override + public void updateSlot(GeyserSession session, Inventory inventory, int slot) { + updater.updateSlot(this, session, inventory, slot); } @Override public int bedrockSlotToJava(InventoryActionData action) { - if (action.getSlot() == 50) { - // Slot 50 is used for crafting with a controller. - return 0; - } - - if (action.getSource().getContainerId() == ContainerId.UI) { + if (action.getSource().getContainerId() == ContainerId.CURSOR) { int slotnum = action.getSlot(); if (slotnum >= 32 && 42 >= slotnum) { return slotnum - 31; + } else if (slotnum == 50) { + return 0; } } return super.bedrockSlotToJava(action); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java index 14ccf745..6d6cadd7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/DoubleChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.inventory.updater.ChestInventoryUpdater; +import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { private final int blockId; public DoubleChestInventoryTranslator(int size) { super(size, 54); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); + BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); this.blockId = BlockTranslator.getBedrockBlockId(javaBlockState); } @@ -57,14 +60,14 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); - NbtMap tag = NbtMap.builder() - .putString("id", "Chest") - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .putInt("pairx", pairPosition.getX()) - .putInt("pairz", pairPosition.getZ()) - .putString("CustomName", inventory.getTitle()).build(); + CompoundTag tag = CompoundTag.builder() + .stringTag("id", "Chest") + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .intTag("pairx", pairPosition.getX()) + .intTag("pairz", pairPosition.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag); dataPacket.setBlockPosition(position); @@ -77,14 +80,14 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { blockPacket.getFlags().addAll(UpdateBlockPacket.FLAG_ALL_PRIORITY); session.sendUpstreamPacket(blockPacket); - tag = NbtMap.builder() - .putString("id", "Chest") - .putInt("x", pairPosition.getX()) - .putInt("y", pairPosition.getY()) - .putInt("z", pairPosition.getZ()) - .putInt("pairx", position.getX()) - .putInt("pairz", position.getZ()) - .putString("CustomName", inventory.getTitle()).build(); + tag = CompoundTag.builder() + .stringTag("id", "Chest") + .intTag("x", pairPosition.getX()) + .intTag("y", pairPosition.getY()) + .intTag("z", pairPosition.getZ()) + .intTag("pairx", position.getX()) + .intTag("pairz", position.getZ()) + .stringTag("CustomName", inventory.getTitle()).buildRootTag(); dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag); dataPacket.setBlockPosition(pairPosition); @@ -96,8 +99,8 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { @Override public void openInventory(GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) inventory.getId()); - containerOpenPacket.setType(ContainerType.CONTAINER); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) ContainerType.CONTAINER.id()); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); session.sendUpstreamPacket(containerOpenPacket); @@ -107,7 +110,7 @@ public class DoubleChestInventoryTranslator extends ChestInventoryTranslator { public void closeInventory(GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); + BlockState realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java index b7b98bf7..ba7f8cc7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/EnchantmentInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,240 +25,18 @@ package org.geysermc.connector.network.translators.inventory; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientClickWindowButtonPacket; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; -import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import lombok.Getter; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.ToString; -import org.geysermc.connector.common.ChatColor; +import com.nukkitx.protocol.bedrock.data.ContainerType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.utils.InventoryUtils; -import org.geysermc.connector.utils.LocaleUtils; +import org.geysermc.connector.network.translators.inventory.updater.ContainerInventoryUpdater; -import java.util.*; - -/** - * A temporary reconstruction of the enchantment table UI until our inventory rewrite is complete. - * The enchantment table on Bedrock without server authoritative inventories doesn't tell us which button is pressed - * when selecting an enchantment. - */ public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { - - private static final int DYE_ID = ItemRegistry.getItemEntry("minecraft:lapis_lazuli").getBedrockId(); - private static final int ENCHANTED_BOOK_ID = ItemRegistry.getItemEntry("minecraft:enchanted_book").getBedrockId(); - - public EnchantmentInventoryTranslator(InventoryUpdater updater) { - super(2, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, updater); - } - - @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == inventory.getId()) { - // This is the hopper UI - switch (action.getSlot()) { - case 1: - // Don't allow the slot to be put through if the item isn't lapis - if ((action.getToItem().getId() != DYE_ID) && action.getToItem() != ItemData.AIR) { - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - } - break; - case 2: - case 3: - case 4: - // The books here act as buttons - ClientClickWindowButtonPacket packet = new ClientClickWindowButtonPacket(inventory.getId(), action.getSlot() - 2); - session.sendDownstreamPacket(packet); - updateInventory(session, inventory); - InventoryUtils.updateCursor(session); - return; - default: - break; - } - } - } - - super.translateActions(session, inventory, actions); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - super.updateInventory(session, inventory); - List items = new ArrayList<>(5); - items.add(ItemTranslator.translateToBedrock(session, inventory.getItem(0))); - items.add(ItemTranslator.translateToBedrock(session, inventory.getItem(1))); - for (int i = 0; i < 3; i++) { - items.add(session.getEnchantmentSlotData()[i].getItem() != null ? session.getEnchantmentSlotData()[i].getItem() : createEnchantmentBook()); - } - - InventoryContentPacket contentPacket = new InventoryContentPacket(); - contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(items); - session.sendUpstreamPacket(contentPacket); + public EnchantmentInventoryTranslator() { + super(2, "minecraft:enchanting_table", ContainerType.ENCHANTMENT, new ContainerInventoryUpdater()); } @Override public void updateProperty(GeyserSession session, Inventory inventory, int key, int value) { - int bookSlotToUpdate; - switch (key) { - case 0: - case 1: - case 2: - // Experience required - bookSlotToUpdate = key; - session.getEnchantmentSlotData()[bookSlotToUpdate].setExperienceRequired(value); - break; - case 4: - case 5: - case 6: - // Enchantment name - bookSlotToUpdate = key - 4; - if (value != -1) { - session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentType(EnchantmentTableEnchantments.values()[value - 1]); - } else { - // -1 means no enchantment specified - session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentType(null); - } - break; - case 7: - case 8: - case 9: - // Enchantment level - bookSlotToUpdate = key - 7; - session.getEnchantmentSlotData()[bookSlotToUpdate].setEnchantmentLevel(value); - break; - default: - return; - } - updateEnchantmentBook(session, inventory, bookSlotToUpdate); - } - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - super.openInventory(session, inventory); - for (int i = 0; i < session.getEnchantmentSlotData().length; i++) { - session.getEnchantmentSlotData()[i] = new EnchantmentSlotData(); - } - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - super.closeInventory(session, inventory); - Arrays.fill(session.getEnchantmentSlotData(), null); - } - - private ItemData createEnchantmentBook() { - NbtMapBuilder root = NbtMap.builder(); - NbtMapBuilder display = NbtMap.builder(); - - display.putString("Name", ChatColor.RESET + "No Enchantment"); - - root.put("display", display.build()); - return ItemData.of(ENCHANTED_BOOK_ID, (short) 0, 1, root.build()); - } - - private void updateEnchantmentBook(GeyserSession session, Inventory inventory, int slot) { - NbtMapBuilder root = NbtMap.builder(); - NbtMapBuilder display = NbtMap.builder(); - EnchantmentSlotData data = session.getEnchantmentSlotData()[slot]; - if (data.getEnchantmentType() != null) { - display.putString("Name", ChatColor.ITALIC + data.getEnchantmentType().toString(session) + - (data.getEnchantmentLevel() != -1 ? " " + toRomanNumeral(session, data.getEnchantmentLevel()) : "") + "?"); - } else { - display.putString("Name", ChatColor.RESET + "No Enchantment"); - } - - display.putList("Lore", NbtType.STRING, Collections.singletonList(ChatColor.DARK_GRAY + data.getExperienceRequired() + "xp")); - root.put("display", display.build()); - ItemData book = ItemData.of(ENCHANTED_BOOK_ID, (short) 0, 1, root.build()); - - InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(inventory.getId()); - slotPacket.setSlot(slot + 2); - slotPacket.setItem(book); - session.sendUpstreamPacket(slotPacket); - data.setItem(book); - } - - private String toRomanNumeral(GeyserSession session, int level) { - return LocaleUtils.getLocaleString("enchantment.level." + level, - session.getLocale()); - } - - /** - * Stores the data of each slot in an enchantment table - */ - @NoArgsConstructor - @Getter - @Setter - @ToString - public static class EnchantmentSlotData { - private EnchantmentTableEnchantments enchantmentType = null; - private int enchantmentLevel = 0; - private int experienceRequired = 0; - private ItemData item; - } - - /** - * Classifies enchantments by Java order - */ - public enum EnchantmentTableEnchantments { - PROTECTION, - FIRE_PROTECTION, - FEATHER_FALLING, - BLAST_PROTECTION, - PROJECTILE_PROTECTION, - RESPIRATION, - AQUA_AFFINITY, - THORNS, - DEPTH_STRIDER, - FROST_WALKER, - BINDING_CURSE, - SHARPNESS, - SMITE, - BANE_OF_ARTHROPODS, - KNOCKBACK, - FIRE_ASPECT, - LOOTING, - SWEEPING, - EFFICIENCY, - SILK_TOUCH, - UNBREAKING, - FORTUNE, - POWER, - PUNCH, - FLAME, - INFINITY, - LUCK_OF_THE_SEA, - LURE, - LOYALTY, - IMPALING, - RIPTIDE, - CHANNELING, - MENDING, - VANISHING_CURSE, // After this is not documented - MULTISHOT, - PIERCING, - QUICK_CHARGE, - SOUL_SPEED; - - public String toString(GeyserSession session) { - return LocaleUtils.getLocaleString("enchantment.minecraft." + this.toString().toLowerCase(), - session.getLocale()); - } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java index c7bc6acf..5c6de0e8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/FurnaceInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.packet.ContainerSetDataPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java index 87448ff5..174cfbc1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/GrindstoneInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; public class GrindstoneInventoryTranslator extends BlockInventoryTranslator { @@ -39,7 +38,7 @@ public class GrindstoneInventoryTranslator extends BlockInventoryTranslator { @Override public int bedrockSlotToJava(InventoryActionData action) { final int slot = super.bedrockSlotToJava(action); - if (action.getSource().getContainerId() == ContainerId.UI) { + if (action.getSource().getContainerId() == 124) { switch (slot) { case 16: return 0; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java index f8ef0f7c..7b4b26e6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/InventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.inventory; import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.ContainerType; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -53,9 +53,8 @@ public abstract class InventoryTranslator { put(WindowType.BREWING_STAND, new BrewingInventoryTranslator()); put(WindowType.ANVIL, new AnvilInventoryTranslator()); put(WindowType.CRAFTING, new CraftingInventoryTranslator()); - //put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); //FIXME - put(WindowType.MERCHANT, new MerchantInventoryTranslator()); - //put(WindowType.SMITHING, new SmithingInventoryTranslator()); //TODO for server authoritative inventories + put(WindowType.GRINDSTONE, new GrindstoneInventoryTranslator()); + //put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator()); //TODO InventoryTranslator furnace = new FurnaceInventoryTranslator(); put(WindowType.FURNACE, furnace); @@ -63,7 +62,6 @@ public abstract class InventoryTranslator { put(WindowType.SMOKER, furnace); InventoryUpdater containerUpdater = new ContainerInventoryUpdater(); - put(WindowType.ENCHANTMENT, new EnchantmentInventoryTranslator(containerUpdater)); //TODO put(WindowType.GENERIC_3X3, new BlockInventoryTranslator(9, "minecraft:dispenser[facing=north,triggered=false]", ContainerType.DISPENSER, containerUpdater)); put(WindowType.HOPPER, new BlockInventoryTranslator(5, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, containerUpdater)); put(WindowType.SHULKER_BOX, new BlockInventoryTranslator(27, "minecraft:shulker_box[facing=north]", ContainerType.CONTAINER, containerUpdater)); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java deleted file mode 100644 index aa36a8a8..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/MerchantInventoryTranslator.java +++ /dev/null @@ -1,124 +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.connector.network.translators.inventory; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import org.geysermc.connector.inventory.Inventory; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; -import org.geysermc.connector.network.translators.inventory.updater.InventoryUpdater; - -import java.util.List; - -public class MerchantInventoryTranslator extends BaseInventoryTranslator { - - private final InventoryUpdater updater; - - public MerchantInventoryTranslator() { - super(3); - this.updater = new CursorInventoryUpdater(); - } - - @Override - public int javaSlotToBedrock(int slot) { - switch (slot) { - case 0: - return 4; - case 1: - return 5; - case 2: - return 50; - } - return super.javaSlotToBedrock(slot); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - switch (action.getSource().getContainerId()) { - case ContainerId.UI: - switch (action.getSlot()) { - case 4: - return 0; - case 5: - return 1; - case 50: - return 2; - } - break; - case -28: // Trading 1? - return 0; - case -29: // Trading 2? - return 1; - case -30: // Trading Output? - return 2; - } - return super.bedrockSlotToJava(action); - } - - @Override - public SlotType getSlotType(int javaSlot) { - if (javaSlot == 2) { - return SlotType.OUTPUT; - } - return SlotType.NORMAL; - } - - @Override - public void prepareInventory(GeyserSession session, Inventory inventory) { - - } - - @Override - public void openInventory(GeyserSession session, Inventory inventory) { - - } - - @Override - public void closeInventory(GeyserSession session, Inventory inventory) { - session.setLastInteractedVillagerEid(-1); - session.setVillagerTrades(null); - } - - @Override - public void updateInventory(GeyserSession session, Inventory inventory) { - updater.updateInventory(this, session, inventory); - } - - @Override - public void updateSlot(GeyserSession session, Inventory inventory, int slot) { - updater.updateSlot(this, session, inventory, slot); - } - - @Override - public void translateActions(GeyserSession session, Inventory inventory, List actions) { - if (actions.stream().anyMatch(a -> a.getSource().getContainerId() == -31)) { - return; - } - - super.translateActions(session, inventory, actions); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java index 0ff20772..28986e58 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/PlayerInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.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.packet.ingame.client.window.ClientCreativeInventoryActionPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.InventorySource; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; @@ -39,14 +39,12 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.action.InventoryActionDataTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; -import org.geysermc.connector.utils.LanguageUtils; -import java.util.Arrays; -import java.util.Collections; import java.util.List; public class PlayerInventoryTranslator extends InventoryTranslator { - private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.creative")); + private static final ItemData UNUSUABLE_CRAFTING_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock( + "The creative crafting grid is\nunavailable in Java Edition"); public PlayerInventoryTranslator() { super(46); @@ -67,7 +65,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { for (int i = 36; i < 45; i++) { contents[i - 36] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } - inventoryContentPacket.setContents(Arrays.asList(contents)); + inventoryContentPacket.setContents(contents); session.sendUpstreamPacket(inventoryContentPacket); // Armor @@ -77,13 +75,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { for (int i = 5; i < 9; i++) { contents[i - 5] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } - armorContentPacket.setContents(Arrays.asList(contents)); + armorContentPacket.setContents(contents); session.sendUpstreamPacket(armorContentPacket); // Offhand InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(Collections.singletonList(ItemTranslator.translateToBedrock(session, inventory.getItem(45)))); + offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(45))}); session.sendUpstreamPacket(offhandPacket); } @@ -96,7 +94,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { // Crafting grid for (int i = 1; i < 5; i++) { InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); + slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(i + 27); if (session.getGameMode() == GameMode.CREATIVE) { @@ -124,7 +122,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { slotPacket.setContainerId(ContainerId.ARMOR); slotPacket.setSlot(slot - 5); } else { - slotPacket.setContainerId(ContainerId.UI); + slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(slot + 27); } slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(slot))); @@ -132,7 +130,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { } else if (slot == 45) { InventoryContentPacket offhandPacket = new InventoryContentPacket(); offhandPacket.setContainerId(ContainerId.OFFHAND); - offhandPacket.setContents(Collections.singletonList(ItemTranslator.translateToBedrock(session, inventory.getItem(slot)))); + offhandPacket.setContents(new ItemData[]{ItemTranslator.translateToBedrock(session, inventory.getItem(slot))}); session.sendUpstreamPacket(offhandPacket); } } @@ -158,13 +156,13 @@ public class PlayerInventoryTranslator extends InventoryTranslator { break; case ContainerId.OFFHAND: return 45; - case ContainerId.UI: + case ContainerId.CURSOR: if (slotnum >= 28 && 31 >= slotnum) { return slotnum - 27; + } else if (slotnum == 50) { + return 0; } break; - case ContainerId.CRAFTING_RESULT: - return 0; } return slotnum; } @@ -186,7 +184,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { if (session.getGameMode() == GameMode.CREATIVE) { //crafting grid is not visible in creative mode in java edition for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == ContainerId.UI && (action.getSlot() >= 28 && 31 >= action.getSlot())) { + if (action.getSource().getContainerId() == ContainerId.CURSOR && (action.getSlot() >= 28 && 31 >= action.getSlot())) { updateInventory(session, inventory); InventoryUtils.updateCursor(session); return; @@ -209,7 +207,7 @@ public class PlayerInventoryTranslator extends InventoryTranslator { session.sendDownstreamPacket(creativePacket); inventory.setItem(javaSlot, javaItem); break; - case ContainerId.UI: + case ContainerId.CURSOR: if (action.getSlot() == 0) { session.getInventory().setCursor(ItemTranslator.translateToJava(action.getToItem())); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java index 462762d0..3f1a58f4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SingleChestInventoryTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ package org.geysermc.connector.network.translators.inventory; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.nukkitx.protocol.bedrock.data.ContainerType; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.holder.BlockInventoryHolder; @@ -37,7 +38,7 @@ public class SingleChestInventoryTranslator extends ChestInventoryTranslator { public SingleChestInventoryTranslator(int size) { super(size, 27); - int javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); + BlockState javaBlockState = BlockTranslator.getJavaBlockState("minecraft:chest[facing=north,type=single,waterlogged=false]"); this.holder = new BlockInventoryHolder(BlockTranslator.getBedrockBlockId(javaBlockState), ContainerType.CONTAINER); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java index d4df48a5..045adbd3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SlotType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java deleted file mode 100644 index 19c2522e..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/SmithingInventoryTranslator.java +++ /dev/null @@ -1,69 +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.connector.network.translators.inventory; - -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; - -public class SmithingInventoryTranslator extends BlockInventoryTranslator { - - public SmithingInventoryTranslator() { - super(3, "minecraft:smithing_table", ContainerType.SMITHING_TABLE, new CursorInventoryUpdater()); - } - - @Override - public int bedrockSlotToJava(InventoryActionData action) { - final int slot = super.bedrockSlotToJava(action); - if (action.getSource().getContainerId() == ContainerId.UI) { - switch (slot) { - case 51: - return 0; - case 52: - return 1; - case 50: - return 2; - default: - return slot; - } - } return slot; - } - - @Override - public int javaSlotToBedrock(int slot) { - switch (slot) { - case 0: - return 51; - case 1: - return 52; - case 2: - return 50; - } - return super.javaSlotToBedrock(slot); - } - -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java index fdfc2d57..1fdfa364 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/Click.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java index c72954bf..a9c1eddc 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/ClickPlan.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java index c313e366..209df074 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/action/InventoryActionDataTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,10 +32,10 @@ import com.github.steveice10.mc.protocol.data.game.window.*; import com.github.steveice10.mc.protocol.data.game.world.block.BlockFace; import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlayerActionPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientWindowActionPacket; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.InventoryActionData; -import com.nukkitx.protocol.bedrock.data.inventory.InventorySource; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.InventoryActionData; +import com.nukkitx.protocol.bedrock.data.InventorySource; +import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; @@ -55,11 +55,11 @@ public class InventoryActionDataTranslator { InventoryActionData containerAction = null; boolean refresh = false; for (InventoryActionData action : actions) { - if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT) { + if (action.getSource().getContainerId() == ContainerId.CRAFTING_USE_INGREDIENT || action.getSource().getContainerId() == ContainerId.CRAFTING_RESULT) { return; } else if (action.getSource().getType() == InventorySource.Type.WORLD_INTERACTION) { worldAction = action; - } else if (action.getSource().getContainerId() == ContainerId.UI && action.getSlot() == 0) { + } else if (action.getSource().getContainerId() == ContainerId.CURSOR && action.getSlot() == 0) { cursorAction = action; ItemData translatedCursor = ItemTranslator.translateToBedrock(session, session.getInventory().getCursor()); if (!translatedCursor.equals(action.getFromItem())) { @@ -120,9 +120,9 @@ public class InventoryActionDataTranslator { session.sendDownstreamPacket(dropPacket); } } - ItemStack item = inventory.getItem(javaSlot); + ItemStack item = session.getInventory().getItem(javaSlot); if (item != null) { - inventory.setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt())); + session.getInventory().setItem(javaSlot, new ItemStack(item.getId(), item.getAmount() - dropAmount, item.getNbt())); } return; } else { //clicking outside of inventory diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java index 6b47cf70..67ce2ce1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/BlockInventoryHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 @@ package org.geysermc.connector.network.translators.inventory.holder; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.protocol.bedrock.data.ContainerType; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import lombok.AllArgsConstructor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.inventory.InventoryTranslator; +import org.geysermc.connector.utils.LocaleUtils; @AllArgsConstructor public class BlockInventoryHolder extends InventoryHolder { @@ -55,11 +57,11 @@ public class BlockInventoryHolder extends InventoryHolder { session.sendUpstreamPacket(blockPacket); inventory.setHolderPosition(position); - NbtMap tag = NbtMap.builder() - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .putString("CustomName", inventory.getTitle()).build(); + CompoundTag tag = CompoundTag.builder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .stringTag("CustomName", LocaleUtils.getLocaleString(inventory.getTitle(), session.getClientData().getLanguageCode())).buildRootTag(); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag); dataPacket.setBlockPosition(position); @@ -69,8 +71,8 @@ public class BlockInventoryHolder extends InventoryHolder { @Override public void openInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.setId((byte) inventory.getId()); - containerOpenPacket.setType(containerType); + containerOpenPacket.setWindowId((byte) inventory.getId()); + containerOpenPacket.setType((byte) containerType.id()); containerOpenPacket.setBlockPosition(inventory.getHolderPosition()); containerOpenPacket.setUniqueEntityId(inventory.getHolderId()); session.sendUpstreamPacket(containerOpenPacket); @@ -80,7 +82,7 @@ public class BlockInventoryHolder extends InventoryHolder { public void closeInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { Vector3i holderPos = inventory.getHolderPosition(); Position pos = new Position(holderPos.getX(), holderPos.getY(), holderPos.getZ()); - int realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); + BlockState realBlock = session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()); UpdateBlockPacket blockPacket = new UpdateBlockPacket(); blockPacket.setDataLayer(0); blockPacket.setBlockPosition(holderPos); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java index 8b5c5473..5a9e736e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/holder/InventoryHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java index 73c1f2eb..6ec8d481 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ChestInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 @@ package org.geysermc.connector.network.translators.inventory.updater; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import lombok.AllArgsConstructor; @@ -34,14 +34,11 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.utils.InventoryUtils; -import org.geysermc.connector.utils.LanguageUtils; - -import java.util.ArrayList; -import java.util.List; @AllArgsConstructor public class ChestInventoryUpdater extends InventoryUpdater { - private static final ItemData UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock(LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.slot")); + private static final ItemData UNUSUABLE_SPACE_BLOCK = InventoryUtils.createUnusableSpaceBlock( + "This slot does not exist in the inventory\non Java Edition, as there is less\nrows than possible in Bedrock"); private final int paddedSize; @@ -49,12 +46,12 @@ public class ChestInventoryUpdater extends InventoryUpdater { public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { super.updateInventory(translator, session, inventory); - List bedrockItems = new ArrayList<>(paddedSize); - for (int i = 0; i < paddedSize; i++) { + ItemData[] bedrockItems = new ItemData[paddedSize]; + for (int i = 0; i < bedrockItems.length; i++) { if (i < translator.size) { - bedrockItems.add(ItemTranslator.translateToBedrock(session, inventory.getItem(i))); + bedrockItems[i] = ItemTranslator.translateToBedrock(session, inventory.getItem(i)); } else { - bedrockItems.add(UNUSUABLE_SPACE_BLOCK); + bedrockItems[i] = UNUSUABLE_SPACE_BLOCK; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java index d7bdbde4..ec6175c3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/ContainerInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 @@ package org.geysermc.connector.network.translators.inventory.updater; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; @@ -33,8 +33,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; -import java.util.Arrays; - public class ContainerInventoryUpdater extends InventoryUpdater { @Override public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { @@ -47,7 +45,7 @@ public class ContainerInventoryUpdater extends InventoryUpdater { InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(inventory.getId()); - contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContents(bedrockItems); session.sendUpstreamPacket(contentPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java index 89abdd84..adbbdbac 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/CursorInventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 @@ package org.geysermc.connector.network.translators.inventory.updater; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; +import com.nukkitx.protocol.bedrock.data.ContainerId; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; @@ -33,8 +33,6 @@ import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; public class CursorInventoryUpdater extends InventoryUpdater { - - //TODO: Consider renaming this? Since the Protocol enum updated @Override public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { super.updateInventory(translator, session, inventory); @@ -44,7 +42,7 @@ public class CursorInventoryUpdater extends InventoryUpdater { if (bedrockSlot == 50) continue; InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); + slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(bedrockSlot); slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(i))); session.sendUpstreamPacket(slotPacket); @@ -57,7 +55,7 @@ public class CursorInventoryUpdater extends InventoryUpdater { return true; InventorySlotPacket slotPacket = new InventorySlotPacket(); - slotPacket.setContainerId(ContainerId.UI); + slotPacket.setContainerId(ContainerId.CURSOR); slotPacket.setSlot(translator.javaSlotToBedrock(javaSlot)); slotPacket.setItem(ItemTranslator.translateToBedrock(session, inventory.getItem(javaSlot))); session.sendUpstreamPacket(slotPacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java index 020f7467..88157df0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/inventory/updater/InventoryUpdater.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.inventory.updater; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.InventoryContentPacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; import org.geysermc.connector.inventory.Inventory; @@ -34,8 +34,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.network.translators.item.ItemTranslator; -import java.util.Arrays; - public abstract class InventoryUpdater { public void updateInventory(InventoryTranslator translator, GeyserSession session, Inventory inventory) { ItemData[] bedrockItems = new ItemData[36]; @@ -45,7 +43,7 @@ public abstract class InventoryUpdater { } InventoryContentPacket contentPacket = new InventoryContentPacket(); contentPacket.setContainerId(ContainerId.INVENTORY); - contentPacket.setContents(Arrays.asList(bedrockItems)); + contentPacket.setContents(bedrockItems); session.sendUpstreamPacket(contentPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java index 769cbd63..b9348e25 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Enchantment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +66,7 @@ public enum Enchantment { CHANNELING, MULTISHOT, PIERCING, - QUICK_CHARGE, - SOUL_SPEED; + QUICK_CHARGE; private final String javaIdentifier; @@ -77,7 +76,7 @@ public enum Enchantment { public static Enchantment getByJavaIdentifier(String javaIdentifier) { for (Enchantment enchantment : Enchantment.values()) { - if (enchantment.javaIdentifier.equals(javaIdentifier) || enchantment.name().toLowerCase(Locale.ENGLISH).equalsIgnoreCase(javaIdentifier)) { + if (enchantment.javaIdentifier.equals(javaIdentifier)) { return enchantment; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java index f61c3d70..9c072ad1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,14 @@ package org.geysermc.connector.network.translators.item; import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.ToString; @Getter @AllArgsConstructor -@ToString public class ItemEntry { - public static ItemEntry AIR = new ItemEntry("minecraft:air", "minecraft:air", 0, 0, 0, false); + public static ItemEntry AIR = new ItemEntry("minecraft:air", 0, 0, 0, false); private final String javaIdentifier; - private final String bedrockIdentifier; private final int javaId; private final int bedrockId; private final int bedrockData; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java index e9b82158..ed99ece3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemRegistry.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.item; @@ -28,22 +29,23 @@ package org.geysermc.connector.network.translators.item; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Base64; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; /** * Registry for anything item related. @@ -52,53 +54,15 @@ public class ItemRegistry { private static final Map JAVA_IDENTIFIER_MAP = new HashMap<>(); - /** - * A list of all identifiers that only exist on Java. Used to prevent creative items from becoming these unintentionally. - */ - private static final List JAVA_ONLY_ITEMS = Arrays.asList("minecraft:spectral_arrow", "minecraft:debug_stick", - "minecraft:knowledge_book"); - public static final ItemData[] CREATIVE_ITEMS; public static final List ITEMS = new ArrayList<>(); public static final Int2ObjectMap ITEM_ENTRIES = new Int2ObjectOpenHashMap<>(); - /** - * Bamboo item entry, used in PandaEntity.java - */ - public static ItemEntry BAMBOO; - /** - * Boat item entries, used in BedrockInventoryTransactionTranslator.java - */ - public static IntList BOATS = new IntArrayList(); - /** - * Bucket item entries (excluding the milk bucket), used in BedrockInventoryTransactionTranslator.java - */ - public static IntList BUCKETS = new IntArrayList(); - /** - * Empty item bucket, used in BedrockInventoryTransactionTranslator.java - */ - public static ItemEntry MILK_BUCKET; - /** - * Egg item entry, used in JavaEntityStatusTranslator.java - */ - public static ItemEntry EGG; - /** - * Gold item entry, used in PiglinEntity.java - */ - public static ItemEntry GOLD; - /** - * Shield item entry, used in Entity.java and LivingEntity.java - */ - public static ItemEntry SHIELD; - /** - * Wheat item entry, used in AbstractHorseEntity.java - */ - public static ItemEntry WHEAT; - /** - * Writable book item entry, used in BedrockBookEditTranslator.java - */ - public static ItemEntry WRITABLE_BOOK; + // Shield ID, used in Entity.java + public static final int SHIELD = 829; + // Boat ID, used in BedrockInventoryTransactionTranslator.java + public static final int BOAT = 333; public static int BARRIER_INDEX = 0; @@ -108,29 +72,20 @@ public class ItemRegistry { static { /* Load item palette */ - InputStream stream = FileUtils.getResource("bedrock/runtime_item_states.json"); + InputStream stream = FileUtils.getResource("bedrock/items.json"); TypeReference> itemEntriesType = new TypeReference>() { }; - // Used to get the Bedrock namespaced ID (in instances where there are small differences) - Int2ObjectMap bedrockIdToIdentifier = new Int2ObjectOpenHashMap<>(); - List itemEntries; try { itemEntries = GeyserConnector.JSON_MAPPER.readValue(stream, itemEntriesType); } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_bedrock"), e); + throw new AssertionError("Unable to load Bedrock runtime item IDs", e); } - int lodestoneCompassId = 0; - for (JsonNode entry : itemEntries) { ITEMS.add(new StartGamePacket.ItemEntry(entry.get("name").textValue(), (short) entry.get("id").intValue())); - bedrockIdToIdentifier.put(entry.get("id").intValue(), entry.get("name").textValue()); - if (entry.get("name").textValue().equals("minecraft:lodestone_compass")) { - lodestoneCompassId = entry.get("id").intValue(); - } } stream = FileUtils.getResource("mappings/items.json"); @@ -139,85 +94,45 @@ public class ItemRegistry { try { items = GeyserConnector.JSON_MAPPER.readTree(stream); } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); + throw new AssertionError("Unable to load Java runtime item IDs", e); } int itemIndex = 0; Iterator> iterator = items.fields(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); - int bedrockId = entry.getValue().get("bedrock_id").intValue(); - String bedrockIdentifier = bedrockIdToIdentifier.get(bedrockId); - if (bedrockIdentifier == null) { - throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId); - } if (entry.getValue().has("tool_type")) { if (entry.getValue().has("tool_tier")) { ITEM_ENTRIES.put(itemIndex, new ToolItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, + entry.getKey(), itemIndex, + entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue(), entry.getValue().get("tool_type").textValue(), entry.getValue().get("tool_tier").textValue(), - entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue())); + entry.getValue().get("is_block").booleanValue())); } else { ITEM_ENTRIES.put(itemIndex, new ToolItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, + entry.getKey(), itemIndex, + entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue(), entry.getValue().get("tool_type").textValue(), - "", entry.getValue().get("is_block").booleanValue())); + "", + entry.getValue().get("is_block").booleanValue())); } } else { ITEM_ENTRIES.put(itemIndex, new ItemEntry( - entry.getKey(), bedrockIdentifier, itemIndex, bedrockId, + entry.getKey(), itemIndex, + entry.getValue().get("bedrock_id").intValue(), entry.getValue().get("bedrock_data").intValue(), - entry.getValue().get("is_block") != null && entry.getValue().get("is_block").booleanValue())); + entry.getValue().get("is_block").booleanValue())); } - switch (entry.getKey()) { - case "minecraft:barrier": - BARRIER_INDEX = itemIndex; - break; - case "minecraft:bamboo": - BAMBOO = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:egg": - EGG = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:gold_ingot": - GOLD = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:shield": - SHIELD = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:milk_bucket": - MILK_BUCKET = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:wheat": - WHEAT = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:writable_book": - WRITABLE_BOOK = ITEM_ENTRIES.get(itemIndex); - break; - default: - break; - } - - if (entry.getKey().contains("boat")) { - BOATS.add(entry.getValue().get("bedrock_id").intValue()); - } else if (entry.getKey().contains("bucket") && !entry.getKey().contains("milk")) { - BUCKETS.add(entry.getValue().get("bedrock_id").intValue()); + if (entry.getKey().equals("minecraft:barrier")) { + BARRIER_INDEX = itemIndex; } itemIndex++; } - if (lodestoneCompassId == 0) { - throw new RuntimeException("Lodestone compass not found in item palette!"); - } - - // Add the loadstone compass since it doesn't exist on java but we need it for item conversion - ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestone_compass", "minecraft:lodestone_compass", itemIndex, - lodestoneCompassId, 0, false)); - /* Load creative items */ stream = FileUtils.getResource("bedrock/creative_items.json"); @@ -225,14 +140,27 @@ public class ItemRegistry { try { creativeItemEntries = GeyserConnector.JSON_MAPPER.readTree(stream).get("items"); } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.creative"), e); + throw new AssertionError("Unable to load creative items", e); } - int netId = 1; List creativeItems = new ArrayList<>(); for (JsonNode itemNode : creativeItemEntries) { - ItemData item = getBedrockItemFromJson(itemNode); - creativeItems.add(ItemData.fromNet(netId++, item.getId(), item.getDamage(), item.getCount(), item.getTag())); + short damage = 0; + if (itemNode.has("damage")) { + damage = itemNode.get("damage").numberValue().shortValue(); + } + if (itemNode.has("nbt_b64")) { + byte[] bytes = Base64.getDecoder().decode(itemNode.get("nbt_b64").asText()); + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + try { + com.nukkitx.nbt.tag.CompoundTag tag = (com.nukkitx.nbt.tag.CompoundTag) NbtUtils.createReaderLE(bais).readTag(); + creativeItems.add(ItemData.of(itemNode.get("id").asInt(), damage, 1, tag)); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + creativeItems.add(ItemData.of(itemNode.get("id").asInt(), damage, 1)); + } } CREATIVE_ITEMS = creativeItems.toArray(new ItemData[0]); } @@ -255,20 +183,19 @@ public class ItemRegistry { */ public static ItemEntry getItem(ItemData data) { for (ItemEntry itemEntry : ITEM_ENTRIES.values()) { - if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || - // Make exceptions for potions and tipped arrows, whose damage values can vary - (itemEntry.getJavaIdentifier().endsWith("potion") || itemEntry.getJavaIdentifier().equals("minecraft:arrow")))) { - if (!JAVA_ONLY_ITEMS.contains(itemEntry.getJavaIdentifier())) { - // From a Bedrock item data, we aren't getting one of these items - return itemEntry; - } + if (itemEntry.getBedrockId() == data.getId() && (itemEntry.getBedrockData() == data.getDamage() || itemEntry.getJavaIdentifier().endsWith("potion"))) { + return itemEntry; + } + } + // If item find was unsuccessful first time, we try again while ignoring damage + // Fixes piston, sticky pistons, dispensers and droppers turning into air from creative inventory + for (ItemEntry itemEntry : ITEM_ENTRIES.values()) { + if (itemEntry.getBedrockId() == data.getId()) { + return itemEntry; } } - // This will hide the message when the player clicks with an empty hand - if (data.getId() != 0 && data.getDamage() != 0) { - GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); - } + GeyserConnector.getInstance().getLogger().debug("Missing mapping for bedrock item " + data.getId() + ":" + data.getDamage()); return ItemEntry.AIR; } @@ -280,40 +207,7 @@ public class ItemRegistry { * @return an item entry from the given java edition identifier */ public static ItemEntry getItemEntry(String javaIdentifier) { - return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> { - for (ItemEntry entry : ITEM_ENTRIES.values()) { - if (entry.getJavaIdentifier().equals(key)) { - return entry; - } - } - return null; - }); - } - - /** - * Gets a Bedrock {@link ItemData} from a {@link JsonNode} - * @param itemNode the JSON node that contains ProxyPass-compatible Bedrock item data - * @return - */ - public static ItemData getBedrockItemFromJson(JsonNode itemNode) { - int count = 1; - short damage = 0; - NbtMap tag = null; - if (itemNode.has("damage")) { - damage = itemNode.get("damage").numberValue().shortValue(); - } - if (itemNode.has("count")) { - count = itemNode.get("count").asInt(); - } - if (itemNode.has("nbt_b64")) { - byte[] bytes = Base64.getDecoder().decode(itemNode.get("nbt_b64").asText()); - ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - try { - tag = (NbtMap) NbtUtils.createReaderLE(bais).readTag(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return ItemData.of(itemNode.get("id").asInt(), damage, count, tag); + return JAVA_IDENTIFIER_MAP.computeIfAbsent(javaIdentifier, key -> ITEM_ENTRIES.values() + .stream().filter(itemEntry -> itemEntry.getJavaIdentifier().equals(key)).findFirst().orElse(null)); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java index 90acb781..273226fe 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ItemTranslator.java @@ -1,52 +1,55 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.item; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.message.Message; +import com.nukkitx.nbt.CompoundTagBuilder; 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 com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.nbt.tag.Tag; +import com.nukkitx.protocol.bedrock.data.ItemData; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.chat.MessageTranslator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.utils.MessageUtils; import org.reflections.Reflections; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public abstract class ItemTranslator { + private static final Int2ObjectMap ITEM_STACK_TRANSLATORS = new Int2ObjectOpenHashMap<>(); private static final List NBT_TRANSLATORS; @@ -59,7 +62,7 @@ public abstract class ItemTranslator { static { /* Load item translators */ - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.item") : new Reflections("org.geysermc.connector.network.translators.item"); + Reflections ref = new Reflections("org.geysermc.connector.network.translators.item"); Map loadedNbtItemTranslators = new HashMap<>(); for (Class clazz : ref.getTypesAnnotatedWith(ItemRemapper.class)) { @@ -78,13 +81,14 @@ public abstract class ItemTranslator { for (ItemEntry item : appliedItems) { ItemTranslator registered = ITEM_STACK_TRANSLATORS.get(item.getJavaId()); if (registered != null) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.item.already_registered", clazz.getCanonicalName(), registered.getClass().getCanonicalName(), item.getJavaIdentifier())); + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "." + + " Item translator " + registered.getClass().getCanonicalName() + " is already registered for the item " + item.getJavaIdentifier()); continue; } ITEM_STACK_TRANSLATORS.put(item.getJavaId(), itemStackTranslator); } } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.item.failed", clazz.getCanonicalName())); + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated item translator " + clazz.getCanonicalName() + "."); } } @@ -111,10 +115,6 @@ public abstract class ItemTranslator { translator.translateToJava(itemStack.getNbt(), javaItem); } } - if (itemStack.getNbt().isEmpty()) { - // Otherwise, seems to causes issues with villagers accepting books, and I don't see how this will break anything else. - Camotoy - itemStack = new ItemStack(itemStack.getId(), itemStack.getAmount(), null); - } } return itemStack; } @@ -126,26 +126,16 @@ public abstract class ItemTranslator { ItemEntry bedrockItem = ItemRegistry.getItem(stack); - com.github.steveice10.opennbt.tag.builtin.CompoundTag nbt = stack.getNbt() != null ? stack.getNbt().clone() : null; + ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), stack.getNbt() != null ? stack.getNbt().clone() : null); - // This is a fallback for maps with no nbt - if (nbt == null && bedrockItem.getJavaIdentifier().equals("minecraft:filled_map")) { - nbt = new CompoundTag(""); - nbt.put(new IntTag("map", 0)); - } - - ItemStack itemStack = new ItemStack(stack.getId(), stack.getAmount(), nbt); - - if (nbt != null) { + if (itemStack.getNbt() != null) { for (NbtItemStackTranslator translator : NBT_TRANSLATORS) { if (translator.acceptItem(bedrockItem)) { - translator.translateToBedrock(session, nbt, bedrockItem); + translator.translateToBedrock(itemStack.getNbt(), bedrockItem); } } } - translateDisplayProperties(session, nbt); - ItemData itemData; ItemTranslator itemStackTranslator = ITEM_STACK_TRANSLATORS.get(bedrockItem.getJavaId()); if (itemStackTranslator != null) { @@ -154,43 +144,36 @@ public abstract class ItemTranslator { itemData = DEFAULT_TRANSLATOR.translateToBedrock(itemStack, bedrockItem); } - if (nbt != null) { - // Translate the canDestroy and canPlaceOn Java NBT - ListTag canDestroy = nbt.get("CanDestroy"); - String[] canBreak = new String[0]; - ListTag canPlaceOn = nbt.get("CanPlaceOn"); - String[] canPlace = new String[0]; - canBreak = getCanModify(canDestroy, canBreak); - canPlace = getCanModify(canPlaceOn, canPlace); - itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), itemData.getTag(), canPlace, canBreak); + + // Get the display name of the item + CompoundTag tag = itemData.getTag(); + if (tag != null) { + CompoundTag display = tag.getCompound("display"); + if (display != null) { + String name = display.getString("Name"); + + // Check if its a message to translate + if (MessageUtils.isMessage(name)) { + // Get the translated name + name = MessageUtils.getTranslatedBedrockMessage(Message.fromString(name), session.getClientData().getLanguageCode()); + + // Build the new display tag + CompoundTagBuilder displayBuilder = display.toBuilder(); + displayBuilder.stringTag("Name", name); + + // Build the new root tag + CompoundTagBuilder builder = tag.toBuilder(); + builder.tag(displayBuilder.build("display")); + + // Create a new item with the original data + updated name + itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag()); + } + } } return itemData; } - /** - * Translates the Java NBT of canDestroy and canPlaceOn to its Bedrock counterparts. - * In Java, this is treated as normal NBT, but in Bedrock, these arguments are extra parts of the item data itself. - * @param canModifyJava the list of items in Java - * @param canModifyBedrock the empty list of items in Bedrock - * @return the new list of items in Bedrock - */ - private static String[] getCanModify(ListTag canModifyJava, String[] canModifyBedrock) { - if (canModifyJava != null && canModifyJava.size() > 0) { - canModifyBedrock = new String[canModifyJava.size()]; - for (int i = 0; i < canModifyBedrock.length; i++) { - // Get the Java identifier of the block that can be placed - String block = ((StringTag) canModifyJava.get(i)).getValue(); - // Sometimes this is done but it's still valid - if (!block.startsWith("minecraft:")) block = "minecraft:" + block; - // Get the Bedrock identifier of the item and replace it. - // This will unfortunately be limited - for example, beds and banners will be translated weirdly - canModifyBedrock[i] = BlockTranslator.getBedrockBlockIdentifier(block).replace("minecraft:", ""); - } - } - return canModifyBedrock; - } - private static final ItemTranslator DEFAULT_TRANSLATOR = new ItemTranslator() { @Override public List getAppliedItems() { @@ -213,99 +196,108 @@ public abstract class ItemTranslator { if (itemData.getTag() == null) { return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), new com.github.steveice10.opennbt.tag.builtin.CompoundTag("")); } - return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT("", itemData.getTag())); + return new ItemStack(itemEntry.getJavaId(), itemData.getCount(), this.translateToJavaNBT(itemData.getTag())); } public abstract List getAppliedItems(); - public NbtMap translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) { - NbtMapBuilder builder = NbtMap.builder(); + public CompoundTag translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) { + Map> javaValue = new HashMap<>(); if (tag.getValue() != null && !tag.getValue().isEmpty()) { for (String str : tag.getValue().keySet()) { - Tag javaTag = tag.get(str); - Object translatedTag = translateToBedrockNBT(javaTag); + com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str); + com.nukkitx.nbt.tag.Tag translatedTag = translateToBedrockNBT(javaTag); if (translatedTag == null) continue; - builder.put(javaTag.getName(), translatedTag); + javaValue.put(translatedTag.getName(), translatedTag); } } - return builder.build(); + + return new CompoundTag(tag.getName(), javaValue); } - private Object translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) { + private Tag translateToBedrockNBT(com.github.steveice10.opennbt.tag.builtin.Tag tag) { if (tag instanceof ByteArrayTag) { - return ((ByteArrayTag) tag).getValue(); + ByteArrayTag byteArrayTag = (ByteArrayTag) tag; + return new com.nukkitx.nbt.tag.ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); } if (tag instanceof ByteTag) { - return ((ByteTag) tag).getValue(); + ByteTag byteTag = (ByteTag) tag; + return new com.nukkitx.nbt.tag.ByteTag(byteTag.getName(), byteTag.getValue()); } if (tag instanceof DoubleTag) { - return ((DoubleTag) tag).getValue(); + DoubleTag doubleTag = (DoubleTag) tag; + return new com.nukkitx.nbt.tag.DoubleTag(doubleTag.getName(), doubleTag.getValue()); } if (tag instanceof FloatTag) { - return ((FloatTag) tag).getValue(); + FloatTag floatTag = (FloatTag) tag; + return new com.nukkitx.nbt.tag.FloatTag(floatTag.getName(), floatTag.getValue()); } if (tag instanceof IntArrayTag) { - return ((IntArrayTag) tag).getValue(); + IntArrayTag intArrayTag = (IntArrayTag) tag; + return new com.nukkitx.nbt.tag.IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); } if (tag instanceof IntTag) { - return ((IntTag) tag).getValue(); + IntTag intTag = (IntTag) tag; + return new com.nukkitx.nbt.tag.IntTag(intTag.getName(), intTag.getValue()); } if (tag instanceof LongArrayTag) { - //Long array tag does not exist in BE - //LongArrayTag longArrayTag = (LongArrayTag) tag; - //return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); - return null; + LongArrayTag longArrayTag = (LongArrayTag) tag; + return new com.nukkitx.nbt.tag.LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); } if (tag instanceof LongTag) { - return ((LongTag) tag).getValue(); + LongTag longTag = (LongTag) tag; + return new com.nukkitx.nbt.tag.LongTag(longTag.getName(), longTag.getValue()); } if (tag instanceof ShortTag) { - return ((ShortTag) tag).getValue(); + ShortTag shortTag = (ShortTag) tag; + return new com.nukkitx.nbt.tag.ShortTag(shortTag.getName(), shortTag.getValue()); } if (tag instanceof StringTag) { - return ((StringTag) tag).getValue(); + StringTag stringTag = (StringTag) tag; + return new com.nukkitx.nbt.tag.StringTag(stringTag.getName(), stringTag.getValue()); } if (tag instanceof ListTag) { ListTag listTag = (ListTag) tag; - List tagList = new ArrayList<>(); + List> tagList = new ArrayList<>(); for (com.github.steveice10.opennbt.tag.builtin.Tag value : listTag) { tagList.add(translateToBedrockNBT(value)); } - NbtType type = NbtType.COMPOUND; + Class clazz = CompoundTag.class; if (!tagList.isEmpty()) { - type = NbtType.byClass(tagList.get(0).getClass()); + clazz = tagList.get(0).getClass(); } - return new NbtList(type, tagList); + return new com.nukkitx.nbt.tag.ListTag(listTag.getName(), clazz, tagList); } - if (tag instanceof CompoundTag) { - CompoundTag compoundTag = (CompoundTag) tag; + if (tag instanceof com.github.steveice10.opennbt.tag.builtin.CompoundTag) { + com.github.steveice10.opennbt.tag.builtin.CompoundTag compoundTag = (com.github.steveice10.opennbt.tag.builtin.CompoundTag) tag; + return translateNbtToBedrock(compoundTag); } return null; } - public CompoundTag translateToJavaNBT(String name, NbtMap tag) { - CompoundTag javaTag = new CompoundTag(name); - Map javaValue = javaTag.getValue(); - if (tag != null && !tag.isEmpty()) { - for (String str : tag.keySet()) { - Object bedrockTag = tag.get(str); - Tag translatedTag = translateToJavaNBT(str, bedrockTag); + public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(com.nukkitx.nbt.tag.CompoundTag tag) { + com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(tag.getName()); + Map javaValue = javaTag.getValue(); + if (tag.getValue() != null && !tag.getValue().isEmpty()) { + for (String str : tag.getValue().keySet()) { + Tag bedrockTag = tag.get(str); + com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(bedrockTag); if (translatedTag == null) continue; @@ -317,132 +309,81 @@ public abstract class ItemTranslator { return javaTag; } - private Tag translateToJavaNBT(String name, Object object) { - if (object instanceof int[]) { - return new IntArrayTag(name, (int[]) object); + private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(com.nukkitx.nbt.tag.Tag tag) { + if (tag instanceof com.nukkitx.nbt.tag.ByteArrayTag) { + com.nukkitx.nbt.tag.ByteArrayTag byteArrayTag = (com.nukkitx.nbt.tag.ByteArrayTag) tag; + return new ByteArrayTag(byteArrayTag.getName(), byteArrayTag.getValue()); } - if (object instanceof byte[]) { - return new ByteArrayTag(name, (byte[]) object); - } - - if (object instanceof Byte) { - return new ByteTag(name, (byte) object); + if (tag instanceof com.nukkitx.nbt.tag.ByteTag) { + com.nukkitx.nbt.tag.ByteTag byteTag = (com.nukkitx.nbt.tag.ByteTag) tag; + return new ByteTag(byteTag.getName(), byteTag.getValue()); } - if (object instanceof Float) { - return new FloatTag(name, (float) object); + if (tag instanceof com.nukkitx.nbt.tag.DoubleTag) { + com.nukkitx.nbt.tag.DoubleTag doubleTag = (com.nukkitx.nbt.tag.DoubleTag) tag; + return new DoubleTag(doubleTag.getName(), doubleTag.getValue()); } - if (object instanceof Double) { - return new DoubleTag(name, (double) object); + if (tag instanceof com.nukkitx.nbt.tag.FloatTag) { + com.nukkitx.nbt.tag.FloatTag floatTag = (com.nukkitx.nbt.tag.FloatTag) tag; + return new FloatTag(floatTag.getName(), floatTag.getValue()); } - if (object instanceof Integer) { - return new IntTag(name, (int) object); + if (tag instanceof com.nukkitx.nbt.tag.IntArrayTag) { + com.nukkitx.nbt.tag.IntArrayTag intArrayTag = (com.nukkitx.nbt.tag.IntArrayTag) tag; + return new IntArrayTag(intArrayTag.getName(), intArrayTag.getValue()); } - if (object instanceof long[]) { - return new LongArrayTag(name, (long[]) object); + if (tag instanceof com.nukkitx.nbt.tag.IntTag) { + com.nukkitx.nbt.tag.IntTag intTag = (com.nukkitx.nbt.tag.IntTag) tag; + return new IntTag(intTag.getName(), intTag.getValue()); } - if (object instanceof Long) { - return new LongTag(name, (long) object); + if (tag instanceof com.nukkitx.nbt.tag.LongArrayTag) { + com.nukkitx.nbt.tag.LongArrayTag longArrayTag = (com.nukkitx.nbt.tag.LongArrayTag) tag; + return new LongArrayTag(longArrayTag.getName(), longArrayTag.getValue()); } - if (object instanceof Short) { - return new ShortTag(name, (short) object); + if (tag instanceof com.nukkitx.nbt.tag.LongTag) { + com.nukkitx.nbt.tag.LongTag longTag = (com.nukkitx.nbt.tag.LongTag) tag; + return new LongTag(longTag.getName(), longTag.getValue()); } - if (object instanceof String) { - return new StringTag(name, (String) object); + if (tag instanceof com.nukkitx.nbt.tag.ShortTag) { + com.nukkitx.nbt.tag.ShortTag shortTag = (com.nukkitx.nbt.tag.ShortTag) tag; + return new ShortTag(shortTag.getName(), shortTag.getValue()); } - if (object instanceof List) { - List tags = new ArrayList<>(); + if (tag instanceof com.nukkitx.nbt.tag.StringTag) { + com.nukkitx.nbt.tag.StringTag stringTag = (com.nukkitx.nbt.tag.StringTag) tag; + return new StringTag(stringTag.getName(), stringTag.getValue()); + } - for (Object value : (List) object) { - Tag javaTag = translateToJavaNBT("", value); + if (tag instanceof com.nukkitx.nbt.tag.ListTag) { + com.nukkitx.nbt.tag.ListTag listTag = (com.nukkitx.nbt.tag.ListTag) tag; + + List tags = new ArrayList<>(); + + for (Object value : listTag.getValue()) { + if (!(value instanceof com.nukkitx.nbt.tag.Tag)) + continue; + + com.nukkitx.nbt.tag.Tag tagValue = (com.nukkitx.nbt.tag.Tag) value; + com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT(tagValue); if (javaTag != null) tags.add(javaTag); } - return new ListTag(name, tags); + return new ListTag(listTag.getName(), tags); } - if (object instanceof NbtMap) { - NbtMap map = (NbtMap) object; - return translateToJavaNBT(name, map); + if (tag instanceof com.nukkitx.nbt.tag.CompoundTag) { + com.nukkitx.nbt.tag.CompoundTag compoundTag = (com.nukkitx.nbt.tag.CompoundTag) tag; + return translateToJavaNBT(compoundTag); } return null; } - /** - * Translates the display name of the item - * @param session the Bedrock client's session - * @param tag the tag to translate - */ - public static void translateDisplayProperties(GeyserSession session, CompoundTag tag) { - if (tag != null) { - CompoundTag display = tag.get("display"); - if (display != null && display.contains("Name")) { - String name = ((StringTag) display.get("Name")).getValue(); - - // Get the translated name and prefix it with a reset char - name = MessageTranslator.convertMessageLenient(name, session.getLocale()); - - // Add the new name tag - display.put(new StringTag("Name", name)); - - // Add to the new root tag - tag.put(display); - } - } - } - - /** - * Checks if an {@link ItemStack} is equal to another item stack - * - * @param itemStack the item stack to check - * @param equalsItemStack the item stack to check if equal to - * @param checkAmount if the amount should be taken into account - * @param trueIfAmountIsGreater if this should return true if the amount of the - * first item stack is greater than that of the second - * @param checkNbt if NBT data should be checked - * @return if an item stack is equal to another item stack - */ - public boolean equals(ItemStack itemStack, ItemStack equalsItemStack, boolean checkAmount, boolean trueIfAmountIsGreater, boolean checkNbt) { - if (itemStack.getId() != equalsItemStack.getId()) { - return false; - } - if (checkAmount) { - if (trueIfAmountIsGreater) { - if (itemStack.getAmount() < equalsItemStack.getAmount()) { - return false; - } - } else { - if (itemStack.getAmount() != equalsItemStack.getAmount()) { - return false; - } - } - } - - if (!checkNbt) { - return true; - } - if ((itemStack.getNbt() == null || itemStack.getNbt().isEmpty()) && (equalsItemStack.getNbt() != null && !equalsItemStack.getNbt().isEmpty())) { - return false; - } - - if ((itemStack.getNbt() != null && !itemStack.getNbt().isEmpty() && (equalsItemStack.getNbt() == null || !equalsItemStack.getNbt().isEmpty()))) { - return false; - } - - if (itemStack.getNbt() != null && equalsItemStack.getNbt() != null) { - return itemStack.getNbt().equals(equalsItemStack.getNbt()); - } - - return true; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java index bfd1d777..d8fcbc4a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/NbtItemStackTranslator.java @@ -1,58 +1,43 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.item; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import org.geysermc.connector.network.session.GeyserSession; public class NbtItemStackTranslator { - /** - * Translate the item NBT to Bedrock - * @param session the client's current session - * @param itemTag the item's CompoundTag - * @param itemEntry Geyser's item entry - */ - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { } - /** - * Translate the item NBT to Java. - * @param itemTag the item's CompoundTag - * @param itemEntry Geyser's item entry - */ public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { } - /** - * @param itemEntry Geyser's item entry - * @return if the item should be processed under this class - */ public boolean acceptItem(ItemEntry itemEntry) { return true; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java index d81e059e..51ae36e4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/Potion.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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 enum Potion { STRONG_SWIFTNESS(16), LONG_SWIFTNESS(15), SLOWNESS(17), - STRONG_SLOWNESS(42), + STRONG_SLOWNESS(18), //does not exist LONG_SLOWNESS(18), WATER_BREATHING(19), LONG_WATER_BREATHING(20), diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java deleted file mode 100644 index 16cbc54a..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/PotionMixRegistry.java +++ /dev/null @@ -1,112 +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.connector.network.translators.item; - -import com.nukkitx.protocol.bedrock.data.inventory.PotionMixData; - -import java.util.*; - -/** - * Generates a {@link Collection} of {@link PotionMixData} that enables the - * Bedrock client to place brewing items into the brewing stand. - * (Does not contain actual potion mixes.) - * - * Designed to replicate Java Edition behavior. - * (Ex: Bedrock cannot normally place glass bottles or fully upgraded - * potions into the brewing stand, but Java can.) - */ -public class PotionMixRegistry { - public static final Collection POTION_MIXES; - - private PotionMixRegistry() { - } - - public static void init() { - // no-op - } - - static { - List ingredients = new ArrayList<>(); - ingredients.add(getNonNull("minecraft:nether_wart")); - ingredients.add(getNonNull("minecraft:redstone")); - ingredients.add(getNonNull("minecraft:glowstone_dust")); - ingredients.add(getNonNull("minecraft:fermented_spider_eye")); - ingredients.add(getNonNull("minecraft:gunpowder")); - ingredients.add(getNonNull("minecraft:dragon_breath")); - ingredients.add(getNonNull("minecraft:sugar")); - ingredients.add(getNonNull("minecraft:rabbit_foot")); - ingredients.add(getNonNull("minecraft:glistering_melon_slice")); - ingredients.add(getNonNull("minecraft:spider_eye")); - ingredients.add(getNonNull("minecraft:pufferfish")); - ingredients.add(getNonNull("minecraft:magma_cream")); - ingredients.add(getNonNull("minecraft:golden_carrot")); - ingredients.add(getNonNull("minecraft:blaze_powder")); - ingredients.add(getNonNull("minecraft:ghast_tear")); - ingredients.add(getNonNull("minecraft:turtle_helmet")); - ingredients.add(getNonNull("minecraft:phantom_membrane")); - - List inputs = new ArrayList<>(); - inputs.add(getNonNull("minecraft:potion")); - inputs.add(getNonNull("minecraft:splash_potion")); - inputs.add(getNonNull("minecraft:lingering_potion")); - - ItemEntry glassBottle = getNonNull("minecraft:glass_bottle"); - - Set potionMixes = new HashSet<>(); - - // Add all types of potions as inputs - ItemEntry fillerIngredient = ingredients.get(0); - for (ItemEntry input : inputs) { - for (Potion potion : Potion.values()) { - potionMixes.add(new PotionMixData( - input.getBedrockId(), potion.getBedrockId(), - fillerIngredient.getBedrockId(), fillerIngredient.getBedrockData(), - glassBottle.getBedrockId(), glassBottle.getBedrockData()) - ); - } - } - - // Add all brewing ingredients - // Also adds glass bottle as input - for (ItemEntry ingredient : ingredients) { - potionMixes.add(new PotionMixData( - glassBottle.getBedrockId(), glassBottle.getBedrockData(), - ingredient.getBedrockId(), ingredient.getBedrockData(), - glassBottle.getBedrockId(), glassBottle.getBedrockData()) - ); - } - - POTION_MIXES = potionMixes; - } - - private static ItemEntry getNonNull(String javaIdentifier) { - ItemEntry itemEntry = ItemRegistry.getItemEntry(javaIdentifier); - if (itemEntry == null) - throw new NullPointerException("No item entry exists for java identifier: " + javaIdentifier); - - return itemEntry; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java deleted file mode 100644 index 7e307281..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java +++ /dev/null @@ -1,197 +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.connector.network.translators.item; - -import com.fasterxml.jackson.databind.JsonNode; -import com.nukkitx.protocol.bedrock.data.inventory.CraftingData; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; - -import java.io.InputStream; -import java.util.*; - -/** - * Manages any recipe-related storing - */ -public class RecipeRegistry { - - /** - * Stores the last used recipe network ID. Since 1.16.200 (and for server-authoritative inventories), - * each recipe needs a unique network ID (or else in .200 the client crashes). - */ - public static int LAST_RECIPE_NET_ID = 0; - - /** - * A list of all possible leather armor dyeing recipes. - * Created manually. - */ - public static final List LEATHER_DYEING_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible firework rocket recipes, including the base rocket. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List FIREWORK_ROCKET_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible firework star recipes. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List FIREWORK_STAR_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible shulker box dyeing options. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List SHULKER_BOX_DYEING_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible suspicious stew recipes. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List SUSPICIOUS_STEW_RECIPES = new ObjectArrayList<>(); - /** - * A list of all possible tipped arrow recipes. - * Obtained from a ProxyPass dump of protocol v407 - */ - public static final List TIPPED_ARROW_RECIPES = new ObjectArrayList<>(); - - /** - * Recipe data that, when sent to the client, enables book cloning - */ - public static final CraftingData BOOK_CLONING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables tool repairing in a crafting table - */ - public static final CraftingData TOOL_REPAIRING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables map extending in a crafting table - */ - public static final CraftingData MAP_EXTENDING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables map cloning in a crafting table - */ - public static final CraftingData MAP_CLONING_RECIPE_DATA; - /** - * Recipe data that, when sent to the client, enables banner duplicating - */ - public static final CraftingData BANNER_DUPLICATING_RECIPE_DATA; - - - static { - BOOK_CLONING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("d1ca6b84-338e-4f2f-9c6b-76cc8b4bd98d"), LAST_RECIPE_NET_ID++); - TOOL_REPAIRING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("00000000-0000-0000-0000-000000000001"), LAST_RECIPE_NET_ID++); - MAP_EXTENDING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("d392b075-4ba1-40ae-8789-af868d56f6ce"), LAST_RECIPE_NET_ID++); - MAP_CLONING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("85939755-ba10-4d9d-a4cc-efb7a8e943c4"), LAST_RECIPE_NET_ID++); - BANNER_DUPLICATING_RECIPE_DATA = CraftingData.fromMulti(UUID.fromString("b5c5d105-75a2-4076-af2b-923ea2bf4bf0"), LAST_RECIPE_NET_ID++); - // https://github.com/pmmp/PocketMine-MP/blob/stable/src/pocketmine/inventory/MultiRecipe.php - - // Get all recipes that are not directly sent from a Java server - InputStream stream = FileUtils.getResource("mappings/recipes.json"); - - JsonNode items; - try { - items = GeyserConnector.JSON_MAPPER.readTree(stream); - } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_java"), e); - } - - for (JsonNode entry: items.get("leather_armor")) { - // This won't be perfect, as we can't possibly send every leather input for every kind of color - // But it does display the correct output from a base leather armor, and besides visuals everything works fine - LEATHER_DYEING_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("firework_rockets")) { - FIREWORK_ROCKET_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("firework_stars")) { - FIREWORK_STAR_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("shulker_boxes")) { - SHULKER_BOX_DYEING_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("suspicious_stew")) { - SUSPICIOUS_STEW_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - for (JsonNode entry : items.get("tipped_arrows")) { - TIPPED_ARROW_RECIPES.add(getCraftingDataFromJsonNode(entry)); - } - } - - /** - * Computes a Bedrock crafting recipe from the given JSON data. - * @param node the JSON data to compute - * @return the {@link CraftingData} to send to the Bedrock client. - */ - private static CraftingData getCraftingDataFromJsonNode(JsonNode node) { - ItemData output = ItemRegistry.getBedrockItemFromJson(node.get("output").get(0)); - UUID uuid = UUID.randomUUID(); - if (node.get("type").asInt() == 1) { - // Shaped recipe - List shape = new ArrayList<>(); - // Get the shape of the recipe - for (JsonNode chars : node.get("shape")) { - shape.add(chars.asText()); - } - - // In recipes.json each recipe is mapped by a letter - Map letterToRecipe = new HashMap<>(); - Iterator> iterator = node.get("input").fields(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - letterToRecipe.put(entry.getKey(), ItemRegistry.getBedrockItemFromJson(entry.getValue())); - } - - List inputs = new ArrayList<>(shape.size() * shape.get(0).length()); - int i = 0; - // Create a linear array of items from the "cube" of the shape - for (int j = 0; i < shape.size() * shape.get(0).length(); j++) { - for (char c : shape.get(j).toCharArray()) { - ItemData data = letterToRecipe.getOrDefault(String.valueOf(c), ItemData.AIR); - inputs.add(data); - i++; - } - } - - return CraftingData.fromShaped(uuid.toString(), shape.get(0).length(), shape.size(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); - } - List inputs = new ObjectArrayList<>(); - for (JsonNode entry : node.get("input")) { - inputs.add(ItemRegistry.getBedrockItemFromJson(entry)); - } - if (node.get("type").asInt() == 5) { - // Shulker box - return CraftingData.fromShulkerBox(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); - } - return CraftingData.fromShapeless(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); - } - - public static void init() { - // no-op - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/TippedArrowPotion.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/TippedArrowPotion.java deleted file mode 100644 index 0125dae0..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/TippedArrowPotion.java +++ /dev/null @@ -1,151 +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.connector.network.translators.item; - -import lombok.Getter; - -import java.util.Locale; - -/** - * Potion identifiers and their respective Bedrock IDs used with arrows. - * https://minecraft.gamepedia.com/Arrow#Item_Data - */ -@Getter -public enum TippedArrowPotion { - MUNDANE(2, ArrowParticleColors.NONE), // 3 is extended? - THICK(4, ArrowParticleColors.NONE), - AWKWARD(5, ArrowParticleColors.NONE), - NIGHT_VISION(6, ArrowParticleColors.NIGHT_VISION), - LONG_NIGHT_VISION(7, ArrowParticleColors.NIGHT_VISION), - INVISIBILITY(8, ArrowParticleColors.INVISIBILITY), - LONG_INVISIBILITY(9, ArrowParticleColors.INVISIBILITY), - LEAPING(10, ArrowParticleColors.LEAPING), - LONG_LEAPING(11, ArrowParticleColors.LEAPING), - STRONG_LEAPING(12, ArrowParticleColors.LEAPING), - FIRE_RESISTANCE(13, ArrowParticleColors.FIRE_RESISTANCE), - LONG_FIRE_RESISTANCE(14, ArrowParticleColors.FIRE_RESISTANCE), - SWIFTNESS(15, ArrowParticleColors.SWIFTNESS), - LONG_SWIFTNESS(16, ArrowParticleColors.SWIFTNESS), - STRONG_SWIFTNESS(17, ArrowParticleColors.SWIFTNESS), - SLOWNESS(18, ArrowParticleColors.SLOWNESS), - LONG_SLOWNESS(19, ArrowParticleColors.SLOWNESS), - STRONG_SLOWNESS(43, ArrowParticleColors.SLOWNESS), - WATER_BREATHING(20, ArrowParticleColors.WATER_BREATHING), - LONG_WATER_BREATHING(21, ArrowParticleColors.WATER_BREATHING), - HEALING(22, ArrowParticleColors.HEALING), - STRONG_HEALING(23, ArrowParticleColors.HEALING), - HARMING(24, ArrowParticleColors.HARMING), - STRONG_HARMING(25, ArrowParticleColors.HARMING), - POISON(26, ArrowParticleColors.POISON), - LONG_POISON(27, ArrowParticleColors.POISON), - STRONG_POISON(28, ArrowParticleColors.POISON), - REGENERATION(29, ArrowParticleColors.REGENERATION), - LONG_REGENERATION(30, ArrowParticleColors.REGENERATION), - STRONG_REGENERATION(31, ArrowParticleColors.REGENERATION), - STRENGTH(32, ArrowParticleColors.STRENGTH), - LONG_STRENGTH(33, ArrowParticleColors.STRENGTH), - STRONG_STRENGTH(34, ArrowParticleColors.STRENGTH), - WEAKNESS(35, ArrowParticleColors.WEAKNESS), - LONG_WEAKNESS(36, ArrowParticleColors.WEAKNESS), - LUCK(2, ArrowParticleColors.NONE), // does not exist in Bedrock - TURTLE_MASTER(38, ArrowParticleColors.TURTLE_MASTER), - LONG_TURTLE_MASTER(39, ArrowParticleColors.TURTLE_MASTER), - STRONG_TURTLE_MASTER(40, ArrowParticleColors.TURTLE_MASTER), - SLOW_FALLING(41, ArrowParticleColors.SLOW_FALLING), - LONG_SLOW_FALLING(42, ArrowParticleColors.SLOW_FALLING); - - private final String javaIdentifier; - private final short bedrockId; - /** - * The Java color associated with this ID. - * Used for looking up Java arrow color entity metadata as Bedrock potion IDs, which is what is used for entities in Bedrock - */ - private final int javaColor; - - TippedArrowPotion(int bedrockId, ArrowParticleColors arrowParticleColor) { - this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ENGLISH); - this.bedrockId = (short) bedrockId; - this.javaColor = arrowParticleColor.getColor(); - } - - public static TippedArrowPotion getByJavaIdentifier(String javaIdentifier) { - for (TippedArrowPotion potion : TippedArrowPotion.values()) { - if (potion.javaIdentifier.equals(javaIdentifier)) { - return potion; - } - } - return null; - } - - public static TippedArrowPotion getByBedrockId(short bedrockId) { - for (TippedArrowPotion potion : TippedArrowPotion.values()) { - if (potion.bedrockId == bedrockId) { - return potion; - } - } - return null; - } - - /** - * @param color the potion color to look up - * @return the tipped arrow potion that most closely resembles that color. - */ - public static TippedArrowPotion getByJavaColor(int color) { - for (TippedArrowPotion potion : TippedArrowPotion.values()) { - if (potion.javaColor == color) { - return potion; - } - } - return null; - } - - private enum ArrowParticleColors { - NONE(-1), - NIGHT_VISION(2039713), - INVISIBILITY(8356754), - LEAPING(2293580), - FIRE_RESISTANCE(14981690), - SWIFTNESS(8171462), - SLOWNESS(5926017), - TURTLE_MASTER(7691106), - WATER_BREATHING(3035801), - HEALING(16262179), - HARMING(4393481), - POISON(5149489), - REGENERATION(13458603), - STRENGTH(9643043), - WEAKNESS(4738376), - LUCK(3381504), - SLOW_FALLING(16773073); - - @Getter - private final int color; - - ArrowParticleColors(int color) { - this.color = color; - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java index 5352938c..cfc05a4a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/ToolItemEntry.java @@ -1,28 +1,3 @@ -/* - * 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.connector.network.translators.item; import lombok.Getter; @@ -32,8 +7,8 @@ public class ToolItemEntry extends ItemEntry { private final String toolType; private final String toolTier; - public ToolItemEntry(String javaIdentifier, String bedrockIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier, boolean isBlock) { - super(javaIdentifier, bedrockIdentifier, javaId, bedrockId, bedrockData, isBlock); + public ToolItemEntry(String javaIdentifier, int javaId, int bedrockId, int bedrockData, String toolType, String toolTier, boolean isBlock) { + super(javaIdentifier, javaId, bedrockId, bedrockData, isBlock); this.toolType = toolType; this.toolTier = toolTier; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java index 25bfe3d2..f4f545ff 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/BannerTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 @@ package org.geysermc.connector.network.translators.item.translators; 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 com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +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 com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; import java.util.ArrayList; import java.util.HashMap; @@ -45,135 +46,27 @@ import java.util.stream.Collectors; @ItemRemapper public class BannerTranslator extends ItemTranslator { - /** - * Holds what a Java ominous banner pattern looks like. - * - * Translating the patterns over to Bedrock does not work effectively, but Bedrock has a dedicated type for - * ominous banners that we set instead. This variable is used to detect Java ominous banner patterns, and apply - * the correct ominous banner pattern if Bedrock pulls the item from creative. - */ - public static final ListTag OMINOUS_BANNER_PATTERN; - private final List appliedItems; - - static { - OMINOUS_BANNER_PATTERN = new ListTag("Patterns"); - // Construct what an ominous banner is supposed to look like - OMINOUS_BANNER_PATTERN.add(getPatternTag("mr", 9)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("bs", 8)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("cs", 7)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("bo", 8)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("ms", 15)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("hh", 8)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("mc", 8)); - OMINOUS_BANNER_PATTERN.add(getPatternTag("bo", 15)); - } - - private static CompoundTag getPatternTag(String pattern, int color) { - StringTag patternType = new StringTag("Pattern", pattern); - IntTag colorTag = new IntTag("Color", color); - CompoundTag tag = new CompoundTag(""); - tag.put(patternType); - tag.put(colorTag); - return tag; - } + private List appliedItems; public BannerTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values() - .stream() - .filter(entry -> entry.getJavaIdentifier().endsWith("banner")) - .collect(Collectors.toList()); - } - - /** - * Convert a list of patterns from Java nbt to Bedrock nbt - * - * @param patterns The patterns to convert - * @return The new converted patterns - */ - 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); - } - } - - return new NbtList<>(NbtType.COMPOUND, tagsList); - } - - /** - * Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist - * - * @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; - } - - return NbtMap.builder() - .putInt("Color", 15 - (int) pattern.get("Color").getValue()) - .putString("Pattern", patternName) - .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 (Object patternTag : patterns) { - tagsList.add(getJavaBannerPattern((NbtMap) patternTag)); - } - - return new ListTag("Patterns", tagsList); - } - - /** - * Convert the Bedrock edition banner pattern nbt to Java edition - * - * @param pattern Bedorck edition pattern nbt - * @return The Java edition format pattern nbt - */ - public static CompoundTag getJavaBannerPattern(NbtMap pattern) { - Map tags = new HashMap<>(); - tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color"))); - tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern"))); - - return new CompoundTag("", tags); + appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("banner")).collect(Collectors.toList()); } @Override public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { - if (itemStack.getNbt() == null) { - return super.translateToBedrock(itemStack, itemEntry); - } + if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); ItemData itemData = super.translateToBedrock(itemStack, itemEntry); CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag"); - if (blockEntityTag != null && blockEntityTag.contains("Patterns")) { + if (blockEntityTag.contains("Patterns")) { ListTag patterns = blockEntityTag.get("Patterns"); - NbtMapBuilder builder = itemData.getTag().toBuilder(); - if (patterns.equals(OMINOUS_BANNER_PATTERN)) { - // Remove the current patterns and set the ominous banner type - builder.remove("Patterns"); - builder.putInt("Type", 1); - } else { - builder.put("Patterns", convertBannerPattern(patterns)); - } + CompoundTagBuilder builder = itemData.getTag().toBuilder(); + builder.tag(convertBannerPattern(patterns)); - itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build()); + itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.buildRootTag()); } return itemData; @@ -181,22 +74,13 @@ public class BannerTranslator extends ItemTranslator { @Override public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { - if (itemData.getTag() == null) { - return super.translateToJava(itemData, itemEntry); - } + if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry); ItemStack itemStack = super.translateToJava(itemData, itemEntry); - NbtMap nbtTag = itemData.getTag(); - if (nbtTag.containsKey("Type", NbtType.INT) && nbtTag.getInt("Type") == 1) { - // Ominous banner pattern - itemStack.getNbt().remove("Type"); - CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(OMINOUS_BANNER_PATTERN); - - itemStack.getNbt().put(blockEntityTag); - } else if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) { - List patterns = nbtTag.getList("Patterns", NbtType.COMPOUND); + com.nukkitx.nbt.tag.CompoundTag nbtTag = itemData.getTag(); + if (nbtTag.contains("Patterns")) { + com.nukkitx.nbt.tag.ListTag patterns = nbtTag.get("Patterns"); CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); blockEntityTag.put(convertBannerPattern(patterns)); @@ -211,4 +95,73 @@ public class BannerTranslator extends ItemTranslator { public List getAppliedItems() { return appliedItems; } + + /** + * Convert a list of patterns from Java nbt to Bedrock nbt + * + * @param patterns The patterns to convert + * @return The new converted patterns + */ + public static com.nukkitx.nbt.tag.ListTag convertBannerPattern(ListTag patterns) { + List tagsList = new ArrayList<>(); + for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { + com.nukkitx.nbt.tag.CompoundTag newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); + if (newPatternTag != null) { + tagsList.add(newPatternTag); + } + } + + return new com.nukkitx.nbt.tag.ListTag<>("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, tagsList); + } + + /** + * Convert the Java edition banner pattern nbt to Bedrock edition, null if the pattern doesn't exist + * + * @param pattern Java edition pattern nbt + * @return The Bedrock edition format pattern nbt + */ + public static com.nukkitx.nbt.tag.CompoundTag 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; + } + + return CompoundTagBuilder.builder() + .intTag("Color", 15 - (int) pattern.get("Color").getValue()) + .stringTag("Pattern", (String) pattern.get("Pattern").getValue()) + .stringTag("Pattern", patternName) + .buildRootTag(); + } + + /** + * 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(com.nukkitx.nbt.tag.ListTag patterns) { + List tagsList = new ArrayList<>(); + for (Object patternTag : patterns.getValue()) { + CompoundTag newPatternTag = getJavaBannerPattern((com.nukkitx.nbt.tag.CompoundTag) patternTag); + tagsList.add(newPatternTag); + } + + return new ListTag("Patterns", tagsList); + } + + /** + * Convert the Bedrock edition banner pattern nbt to Java edition + * + * @param pattern Bedorck edition pattern nbt + * @return The Java edition format pattern nbt + */ + public static CompoundTag getJavaBannerPattern(com.nukkitx.nbt.tag.CompoundTag pattern) { + Map tags = new HashMap<>(); + tags.put("Color", new IntTag("Color", 15 - pattern.getInt("Color"))); + tags.put("Pattern", new StringTag("Pattern", pattern.getString("Pattern"))); + + return new CompoundTag("", tags); + } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java deleted file mode 100644 index 9e3bf7d4..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/CompassTranslator.java +++ /dev/null @@ -1,121 +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.connector.network.translators.item.translators; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.*; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.utils.LoadstoneTracker; - -import java.util.List; -import java.util.stream.Collectors; - -@ItemRemapper -public class CompassTranslator extends ItemTranslator { - - private final List appliedItems; - - public CompassTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("compass")).collect(Collectors.toList()); - } - - @Override - public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { - if (itemStack.getNbt() == null) return super.translateToBedrock(itemStack, itemEntry); - - Tag lodestoneTag = itemStack.getNbt().get("LodestoneTracked"); - if (lodestoneTag instanceof ByteTag) { - // Get the fake lodestonecompass entry - itemEntry = ItemRegistry.getItemEntry("minecraft:lodestone_compass"); - - // Get the loadstone pos - CompoundTag loadstonePos = itemStack.getNbt().get("LodestonePos"); - if (loadstonePos != null) { - // Get all info needed for tracking - int x = ((IntTag) loadstonePos.get("X")).getValue(); - int y = ((IntTag) loadstonePos.get("Y")).getValue(); - int z = ((IntTag) loadstonePos.get("Z")).getValue(); - String dim = ((StringTag) itemStack.getNbt().get("LodestoneDimension")).getValue(); - - // Store the info - int trackID = LoadstoneTracker.store(x, y, z, dim); - - // Set the bedrock tracking id - itemStack.getNbt().put(new IntTag("trackingHandle", trackID)); - } else { - // The loadstone was removed just set the tracking id to 0 - itemStack.getNbt().put(new IntTag("trackingHandle", 0)); - } - } - - ItemData itemData = super.translateToBedrock(itemStack, itemEntry); - - return itemData; - } - - @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { - boolean isLoadstone = false; - if (itemEntry.getBedrockIdentifier().equals("minecraft:lodestone_compass")) { - // Revert the entry back to the compass - itemEntry = ItemRegistry.getItemEntry("minecraft:compass"); - - isLoadstone = true; - } - - ItemStack itemStack = super.translateToJava(itemData, itemEntry); - - if (isLoadstone) { - // Get the tracking id - int trackingID = ((IntTag) itemStack.getNbt().get("trackingHandle")).getValue(); - - // Fetch the tracking info from the id - LoadstoneTracker.LoadstonePos pos = LoadstoneTracker.getPos(trackingID); - if (pos != null) { - // Build the new NBT data for the fetched tracking info - itemStack.getNbt().put(new StringTag("LodestoneDimension", pos.getDimension())); - - CompoundTag posTag = new CompoundTag("LodestonePos"); - posTag.put(new IntTag("X", pos.getX())); - posTag.put(new IntTag("Y", pos.getY())); - posTag.put(new IntTag("Z", pos.getZ())); - - itemStack.getNbt().put(posTag); - } - } - - return itemStack; - } - - @Override - public List getAppliedItems() { - return appliedItems; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java index 20a36c9e..2fdde31d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/PotionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +28,7 @@ package org.geysermc.connector.network.translators.item.translators; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.opennbt.tag.builtin.StringTag; import com.github.steveice10.opennbt.tag.builtin.Tag; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ItemData; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; @@ -42,7 +42,7 @@ import java.util.stream.Collectors; @ItemRemapper public class PotionTranslator extends ItemTranslator { - private final List appliedItems; + private List appliedItems; public PotionTranslator() { appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("potion")).collect(Collectors.toList()); @@ -57,7 +57,7 @@ public class PotionTranslator extends ItemTranslator { if (potion != null) { return ItemData.of(itemEntry.getBedrockId(), potion.getBedrockId(), itemStack.getAmount(), translateNbtToBedrock(itemStack.getNbt())); } - GeyserConnector.getInstance().getLogger().debug("Unknown Java potion: " + potionTag.getValue()); + GeyserConnector.getInstance().getLogger().debug("Unknown java potion: " + potionTag.getValue()); } return super.translateToBedrock(itemStack, itemEntry); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java deleted file mode 100644 index dd151dcd..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/TippedArrowTranslator.java +++ /dev/null @@ -1,87 +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.connector.network.translators.item.translators; - -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.item.TippedArrowPotion; - -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 = ItemRegistry.getItemEntry("minecraft:tipped_arrow").getJavaId(); - - public TippedArrowTranslator() { - appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> - entry.getJavaIdentifier().contains("arrow") && !entry.getJavaIdentifier().contains("spectral")).collect(Collectors.toList()); - } - - @Override - public ItemData translateToBedrock(ItemStack itemStack, ItemEntry itemEntry) { - if (!itemEntry.getJavaIdentifier().equals("minecraft:tipped_arrow") || itemStack.getNbt() == null) { - // We're only concerned about minecraft:arrow when translating Bedrock -> Java - return super.translateToBedrock(itemStack, itemEntry); - } - Tag potionTag = itemStack.getNbt().get("Potion"); - if (potionTag instanceof StringTag) { - TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByJavaIdentifier(((StringTag) potionTag).getValue()); - if (tippedArrowPotion != null) { - return ItemData.of(itemEntry.getBedrockId(), tippedArrowPotion.getBedrockId(), itemStack.getAmount(), translateNbtToBedrock(itemStack.getNbt())); - } - GeyserConnector.getInstance().getLogger().debug("Unknown Java potion (tipped arrow): " + potionTag.getValue()); - } - return super.translateToBedrock(itemStack, itemEntry); - } - - @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { - TippedArrowPotion tippedArrowPotion = TippedArrowPotion.getByBedrockId(itemData.getDamage()); - ItemStack itemStack = super.translateToJava(itemData, itemEntry); - if (tippedArrowPotion != null) { - itemStack = new ItemStack(TIPPED_ARROW_JAVA_ID, itemStack.getAmount(), itemStack.getNbt()); - StringTag potionTag = new StringTag("Potion", tippedArrowPotion.getJavaIdentifier()); - itemStack.getNbt().put(potionTag); - } - return itemStack; - } - - @Override - public List getAppliedItems() { - return appliedItems; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java index efb50a76..776cec72 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BasicItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,14 @@ 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.Component; -import net.kyori.adventure.text.TextComponent; -import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; -import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; -import org.geysermc.connector.network.session.GeyserSession; +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.serializer.gson.GsonComponentSerializer; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; +import org.geysermc.connector.utils.MessageUtils; import java.util.ArrayList; import java.util.List; @@ -45,7 +45,7 @@ import java.util.List; public class BasicItemTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { if (!itemTag.contains("display")) { return; } @@ -100,16 +100,16 @@ public class BasicItemTranslator extends NbtItemStackTranslator { if (message.startsWith("§r")) { message = message.replaceFirst("§r", ""); } - Component component = Component.text(message); - return GsonComponentSerializer.gson().serialize(component); + Component component = TextComponent.of(message); + return GsonComponentSerializer.INSTANCE.serialize(component); } private String toBedrockMessage(StringTag tag) { String message = tag.getValue(); if (message == null) return null; - TextComponent component = (TextComponent) GsonComponentSerializer.gson().deserialize(message); - String legacy = LegacyComponentSerializer.legacySection().serialize(component); - if (hasFormatting(LegacyComponentSerializer.legacySection().deserialize(legacy))) { + TextComponent component = (TextComponent) MessageUtils.phraseJavaMessage(message); + String legacy = LegacyComponentSerializer.legacy().serialize(component); + if (hasFormatting(LegacyComponentSerializer.legacy().deserialize(legacy))) { return "§r" + legacy; } return legacy; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java index 90eef3bc..e802f017 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/BookPagesTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,11 +29,10 @@ 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 org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; import java.util.ArrayList; import java.util.List; @@ -42,7 +41,7 @@ import java.util.List; public class BookPagesTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { if (!itemTag.contains("pages")) { return; } @@ -56,7 +55,7 @@ public class BookPagesTranslator extends NbtItemStackTranslator { CompoundTag pageTag = new CompoundTag(""); pageTag.put(new StringTag("photoname", "")); - pageTag.put(new StringTag("text", MessageTranslator.convertMessageLenient(textTag.getValue()))); + pageTag.put(new StringTag("text", MessageUtils.getBedrockMessageLenient(textTag.getValue()))); pages.add(pageTag); } @@ -78,8 +77,9 @@ public class BookPagesTranslator extends NbtItemStackTranslator { CompoundTag pageTag = (CompoundTag) tag; StringTag textTag = pageTag.get("text"); - pages.add(new StringTag("", textTag.getValue())); + pages.add(new StringTag(MessageUtils.getJavaMessage(textTag.getValue()))); } + itemTag.remove("pages"); itemTag.put(new ListTag("pages", pages)); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java index 2af80380..3c5271eb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/CrossbowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,37 +25,30 @@ package org.geysermc.connector.network.translators.item.translators.nbt; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; -import com.github.steveice10.opennbt.tag.builtin.*; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; -import org.geysermc.connector.network.session.GeyserSession; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +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 org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper public class CrossbowTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { if (itemTag.get("ChargedProjectiles") != null) { ListTag chargedProjectiles = itemTag.get("ChargedProjectiles"); if (!chargedProjectiles.getValue().isEmpty()) { CompoundTag projectile = (CompoundTag) chargedProjectiles.getValue().get(0); - ItemEntry projectileEntry = ItemRegistry.getItemEntry((String) projectile.get("id").getValue()); - if (projectileEntry == null) return; - CompoundTag tag = projectile.get("tag"); - ItemStack itemStack = new ItemStack(itemEntry.getJavaId(), (byte) projectile.get("Count").getValue(), tag); - ItemData itemData = ItemTranslator.translateToBedrock(session, itemStack); - CompoundTag newProjectile = new CompoundTag("chargedItem"); - newProjectile.put(new ByteTag("Count", (byte) itemData.getCount())); - newProjectile.put(new StringTag("Name", projectileEntry.getBedrockIdentifier())); + newProjectile.put(new ByteTag("Count", (byte) projectile.get("Count").getValue())); + newProjectile.put(new StringTag("Name", (String) projectile.get("id").getValue())); - newProjectile.put(new ShortTag("Damage", itemData.getDamage())); + // Not sure what this is for + newProjectile.put(new ByteTag("Damage", (byte) 0)); itemTag.put(newProjectile); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java index cc01feb4..63ac6c51 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantedBookTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +28,6 @@ package org.geysermc.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; -import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @@ -37,7 +36,7 @@ import org.geysermc.connector.network.translators.item.ItemEntry; public class EnchantedBookTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { if (!itemTag.contains("StoredEnchantments")) { return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java index 2e381d22..404d7824 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/EnchantmentTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.*; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.Enchantment; @@ -41,7 +40,7 @@ import java.util.Map; public class EnchantmentTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { List newTags = new ArrayList<>(); if (itemTag.contains("Enchantments")) { ListTag enchantmentTag = itemTag.get("Enchantments"); @@ -115,7 +114,7 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { itemTag.put(new ListTag("Enchantments", enchantments)); } if (!storedEnchantments.isEmpty()) { - itemTag.put(new ListTag("StoredEnchantments", storedEnchantments)); + itemTag.put(new ListTag("StoredEnchantments", enchantments)); } itemTag.remove("ench"); } @@ -123,7 +122,7 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { private CompoundTag remapEnchantment(CompoundTag tag) { Tag javaEnchLvl = tag.get("lvl"); - if (!(javaEnchLvl instanceof ShortTag || javaEnchLvl instanceof IntTag)) + if (!(javaEnchLvl instanceof ShortTag)) return null; Tag javaEnchId = tag.get("id"); @@ -138,7 +137,7 @@ public class EnchantmentTranslator extends NbtItemStackTranslator { CompoundTag bedrockTag = new CompoundTag(""); bedrockTag.put(new ShortTag("id", (short) enchantment.ordinal())); - bedrockTag.put(new ShortTag("lvl", ((Number) javaEnchLvl.getValue()).shortValue())); + bedrockTag.put(new ShortTag("lvl", ((ShortTag) javaEnchLvl).getValue())); return bedrockTag; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java index 8c5b74f1..5b5182a5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/FireworkTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.*; -import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; @@ -37,7 +36,7 @@ import org.geysermc.connector.utils.MathUtils; public class FireworkTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { if (!itemTag.contains("Fireworks")) { return; } @@ -99,17 +98,11 @@ public class FireworkTranslator extends NbtItemStackTranslator { @Override public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { - if (!itemTag.contains("Fireworks")) { - return; - } CompoundTag fireworks = itemTag.get("Fireworks"); - if (fireworks.contains("Flight")) { + if (fireworks.get("Flight") != null) { fireworks.put(new ByteTag("Flight", MathUtils.convertByte(fireworks.get("Flight").getValue()))); } - if (!itemTag.contains("Explosions")) { - return; - } ListTag explosions = fireworks.get("Explosions"); for (Tag effect : explosions.getValue()) { CompoundTag effectData = (CompoundTag) effect; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java index f78eadc2..9f864ccf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/LeatherArmorTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; -import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @@ -38,7 +37,7 @@ public class LeatherArmorTranslator extends NbtItemStackTranslator { private static final String[] ITEMS = new String[]{"minecraft:leather_helmet", "minecraft:leather_chestplate", "minecraft:leather_leggings", "minecraft:leather_boots"}; @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { if (!itemTag.contains("display")) { return; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java index 79db364b..8c418c0f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/MapItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,27 @@ package org.geysermc.connector.network.translators.item.translators.nbt; -import com.github.steveice10.opennbt.tag.builtin.*; -import org.geysermc.connector.network.session.GeyserSession; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.StringTag; import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper public class MapItemTranslator extends NbtItemStackTranslator { @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { - // Can be either an IntTag or ShortTag - Tag mapId = itemTag.get("map"); - if (mapId == null) return; + public void translateToBedrock(CompoundTag itemTag, ItemEntry itemEntry) { + IntTag mapId = itemTag.get("map"); - int mapValue; - if (mapId.getValue() instanceof Short) { - // Convert to int if necessary - mapValue = (int) (short) mapId.getValue(); - } else { - mapValue = (int) mapId.getValue(); + if (mapId != null) { + itemTag.put(new StringTag("map_uuid", mapId.getValue().toString())); + itemTag.put(new IntTag("map_name_index", mapId.getValue())); + itemTag.put(new ByteTag("map_display_players", (byte) 1)); + itemTag.remove("map"); } - - itemTag.put(new LongTag("map_uuid", mapValue)); - itemTag.put(new IntTag("map_name_index", mapValue)); - itemTag.put(new ByteTag("map_display_players", (byte) 1)); - itemTag.remove("map"); } @Override @@ -63,9 +57,4 @@ public class MapItemTranslator extends NbtItemStackTranslator { itemTag.remove("map_uuid"); } } - - @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().equals("minecraft:filled_map"); - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java deleted file mode 100644 index 3824ff3c..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/PlayerHeadTranslator.java +++ /dev/null @@ -1,72 +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.connector.network.translators.item.translators.nbt; - -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 org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; -import org.geysermc.connector.utils.LocaleUtils; - -@ItemRemapper -public class PlayerHeadTranslator extends NbtItemStackTranslator { - - @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { - if (!itemTag.contains("display") || !((CompoundTag) itemTag.get("display")).contains("Name")) { - if (itemTag.contains("SkullOwner")) { - StringTag name; - Tag skullOwner = itemTag.get("SkullOwner"); - if (skullOwner instanceof StringTag) { - name = (StringTag) skullOwner; - } else { - StringTag skullName; - if (skullOwner instanceof CompoundTag && (skullName = ((CompoundTag) skullOwner).get("Name")) != null) { - name = skullName; - } else { - session.getConnector().getLogger().debug("Not sure how to handle skull head item display. " + itemTag); - return; - } - } - // Add correct name of player skull - // TODO: It's always yellow, even with a custom name. Handle? - String displayName = "\u00a7r\u00a7e" + LocaleUtils.getLocaleString("block.minecraft.player_head.named", session.getLocale()).replace("%s", name.getValue()); - if (!itemTag.contains("display")) { - itemTag.put(new CompoundTag("display")); - } - ((CompoundTag) itemTag.get("display")).put(new StringTag("Name", displayName)); - } - } - } - - @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().equals("minecraft:player_head"); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java deleted file mode 100644 index 5ddaa997..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/item/translators/nbt/ShulkerBoxItemTranslator.java +++ /dev/null @@ -1,83 +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.connector.network.translators.item.translators.nbt; - -import com.github.steveice10.opennbt.tag.builtin.*; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.ItemRemapper; -import org.geysermc.connector.network.translators.item.ItemEntry; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.item.NbtItemStackTranslator; - -@ItemRemapper -public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { - - @Override - public void translateToBedrock(GeyserSession session, CompoundTag itemTag, ItemEntry itemEntry) { - if (!itemTag.contains("BlockEntityTag")) return; // Empty shulker box - - CompoundTag blockEntityTag = itemTag.get("BlockEntityTag"); - if (blockEntityTag.get("Items") == null) return; - ListTag itemsList = new ListTag("Items"); - for (Tag item : (ListTag) blockEntityTag.get("Items")) { - CompoundTag itemData = (CompoundTag) item; // Information about the item - CompoundTag boxItemTag = new CompoundTag(""); // Final item tag to add to the list - boxItemTag.put(new ByteTag("Slot", ((ByteTag) itemData.get("Slot")).getValue())); - boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ??? - - ItemEntry boxItemEntry = ItemRegistry.getItemEntry(((StringTag) itemData.get("id")).getValue()); - - boxItemTag.put(new StringTag("Name", boxItemEntry.getBedrockIdentifier())); - boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData())); - boxItemTag.put(new ByteTag("Count", ((ByteTag) itemData.get("Count")).getValue())); - if (itemData.contains("tag")) { - // Only the display name is what we have interest in, so just translate that if relevant - CompoundTag displayTag = itemData.get("tag"); - ItemTranslator.translateDisplayProperties(session, displayTag); - boxItemTag.put(displayTag); - } - - itemsList.add(boxItemTag); - } - itemTag.put(itemsList); - // Don't actually bother with removing the block entity tag. Too risky to translate - // if the user is on creative and messing with a shulker box - //itemTag.remove("BlockEntityTag"); - } - - @Override - public void translateToJava(CompoundTag itemTag, ItemEntry itemEntry) { - if (itemTag.contains("Items")) { // Remove any extraneous Bedrock tag and don't touch the Java one - itemTag.remove("Items"); - } - } - - @Override - public boolean acceptItem(ItemEntry itemEntry) { - return itemEntry.getJavaIdentifier().contains("shulker_box"); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTabTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTabTranslator.java deleted file mode 100644 index 17a3b379..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTabTranslator.java +++ /dev/null @@ -1,45 +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.connector.network.translators.java; - -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerAdvancementTabPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.cache.AdvancementsCache; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -/** - * Indicates that the client should open a particular advancement tab - */ -@Translator(packet = ServerAdvancementTabPacket.class) -public class JavaAdvancementsTabTranslator extends PacketTranslator { - - @Override - public void translate(ServerAdvancementTabPacket packet, GeyserSession session) { - session.getAdvancementsCache().setCurrentAdvancementCategoryId(packet.getTabId()); - session.sendForm(session.getAdvancementsCache().buildListForm(), AdvancementsCache.ADVANCEMENTS_LIST_FORM_ID); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java deleted file mode 100644 index 714578e9..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaAdvancementsTranslator.java +++ /dev/null @@ -1,103 +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.connector.network.translators.java; - -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerAdvancementsPacket; -import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.chat.MessageTranslator; -import org.geysermc.connector.network.session.cache.AdvancementsCache; -import org.geysermc.connector.utils.GeyserAdvancement; -import org.geysermc.connector.utils.LocaleUtils; - -import java.util.Map; - -@Translator(packet = ServerAdvancementsPacket.class) -public class JavaAdvancementsTranslator extends PacketTranslator { - - @Override - public void translate(ServerAdvancementsPacket packet, GeyserSession session) { - AdvancementsCache advancementsCache = session.getAdvancementsCache(); - if (packet.isReset()) { - advancementsCache.getStoredAdvancements().clear(); - advancementsCache.getStoredAdvancementProgress().clear(); - } - - // Removes removed advancements from player's stored advancements - for (String removedAdvancement : packet.getRemovedAdvancements()) { - advancementsCache.getStoredAdvancements().remove(removedAdvancement); - } - - advancementsCache.getStoredAdvancementProgress().putAll(packet.getProgress()); - - sendToolbarAdvancementUpdates(session, packet); - - // Adds advancements to the player's stored advancements when advancements are sent - for (Advancement advancement : packet.getAdvancements()) { - if (advancement.getDisplayData() != null && !advancement.getDisplayData().isHidden()) { - GeyserAdvancement geyserAdvancement = GeyserAdvancement.from(advancement); - advancementsCache.getStoredAdvancements().put(advancement.getId(), geyserAdvancement); - } else { - advancementsCache.getStoredAdvancements().remove(advancement.getId()); - } - } - } - - /** - * Handle all advancements progress updates - */ - public void sendToolbarAdvancementUpdates(GeyserSession session, ServerAdvancementsPacket packet) { - if (packet.isReset()) { - // Advancements are being cleared, so they can't be granted - return; - } - for (Map.Entry> progress : packet.getProgress().entrySet()) { - GeyserAdvancement advancement = session.getAdvancementsCache().getStoredAdvancements().get(progress.getKey()); - 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"; - 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 + "[" + LocaleUtils.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); - session.sendUpstreamPacket(titlePacket); - } - } - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java index 45e65f47..3da76a22 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaBossBarTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java index a5988050..53ce6811 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaChatTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 +25,16 @@ package org.geysermc.connector.network.translators.java; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; -import com.nukkitx.protocol.bedrock.packet.TextPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; + +import com.github.steveice10.mc.protocol.data.message.TranslationMessage; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; +import com.nukkitx.protocol.bedrock.packet.TextPacket; + +import java.util.List; @Translator(packet = ServerChatPacket.class) public class JavaChatTranslator extends PacketTranslator { @@ -56,8 +60,21 @@ public class JavaChatTranslator extends PacketTranslator { break; } - textPacket.setNeedsTranslation(false); - textPacket.setMessage(MessageTranslator.convertMessage(packet.getMessage(), session.getLocale())); + String locale = session.getClientData().getLanguageCode(); + + if (packet.getMessage() instanceof TranslationMessage) { + textPacket.setType(TextPacket.Type.TRANSLATION); + textPacket.setNeedsTranslation(true); + + List paramsTranslated = MessageUtils.getTranslationParams(((TranslationMessage) packet.getMessage()).getTranslationParams(), locale); + textPacket.setParameters(paramsTranslated); + + textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, true), paramsTranslated)); + } else { + textPacket.setNeedsTranslation(false); + + textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, false)); + } session.sendUpstreamPacket(textPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java index f6664c1a..053630d5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaDeclareCommandsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,9 @@ package org.geysermc.connector.network.translators.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.packet.ingame.server.ServerDeclareCommandsPacket; -import com.nukkitx.protocol.bedrock.data.command.CommandData; -import com.nukkitx.protocol.bedrock.data.command.CommandEnumData; -import com.nukkitx.protocol.bedrock.data.command.CommandParamData; -import com.nukkitx.protocol.bedrock.data.command.CommandParamType; +import com.nukkitx.protocol.bedrock.data.CommandData; +import com.nukkitx.protocol.bedrock.data.CommandEnumData; +import com.nukkitx.protocol.bedrock.data.CommandParamData; import com.nukkitx.protocol.bedrock.packet.AvailableCommandsPacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -41,10 +40,7 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; @Translator(packet = ServerDeclareCommandsPacket.class) public class JavaDeclareCommandsTranslator extends PacketTranslator { @@ -52,14 +48,9 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator commandData = new ArrayList<>(); Int2ObjectMap commands = new Int2ObjectOpenHashMap<>(); Int2ObjectMap> commandArgs = new Int2ObjectOpenHashMap<>(); @@ -88,14 +79,14 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator flags = Collections.emptyList(); + List flags = new ArrayList<>(); // Loop through all the found commands for (int commandID : commands.keySet()) { String commandName = commands.get(commandID); // Create a basic alias - CommandEnumData aliases = new CommandEnumData(commandName + "Aliases", new String[] { commandName.toLowerCase() }, false); + CommandEnumData aliases = new CommandEnumData( commandName + "Aliases", new String[] { commandName.toLowerCase() }, false); // Get and parse all params CommandParamData[][] params = getParams(packet.getNodes()[commandID], packet.getNodes()); @@ -107,7 +98,9 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator { + private static final Collection POTION_MIXES = + Arrays.stream(new int[]{372, 331, 348, 376, 289, 437, 353, 414, 382, 375, 462, 378, 396, 377, 370, 469, 470}) + .mapToObj(ingredient -> new PotionMixData(0, ingredient, 0)) + .collect(Collectors.toList()); @Override public void translate(ServerDeclareRecipesPacket packet, GeyserSession session) { - // Get the last known network ID (first used for the pregenerated recipes) and increment from there. - int networkId = RecipeRegistry.LAST_RECIPE_NET_ID; CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); for (Recipe recipe : packet.getRecipes()) { @@ -65,7 +70,7 @@ public class JavaDeclareRecipesTranslator extends PacketTranslator { - - @Override - public void translate(ServerDisconnectPacket packet, GeyserSession session) { - session.disconnect(MessageTranslator.convertMessage(packet.getReason(), session.getLocale())); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java index e9a1901d..8d8c0aff 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaJoinGameTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,22 @@ package org.geysermc.connector.network.translators.java; -import com.github.steveice10.mc.protocol.data.game.entity.player.HandPreference; +import com.github.steveice10.mc.protocol.data.game.entity.player.Hand; 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.packet.ingame.client.ClientPluginMessagePacket; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientSettingsPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; -import com.nukkitx.protocol.bedrock.data.GameRuleData; -import com.nukkitx.protocol.bedrock.data.PlayerPermission; -import com.nukkitx.protocol.bedrock.packet.*; -import org.geysermc.connector.entity.player.PlayerEntity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.DimensionUtils; -import org.geysermc.connector.utils.PluginMessageUtils; + +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; +import com.nukkitx.protocol.bedrock.data.PlayerPermission; +import com.nukkitx.protocol.bedrock.packet.AdventureSettingsPacket; +import com.nukkitx.protocol.bedrock.packet.PlayStatusPacket; +import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; import java.util.Arrays; import java.util.List; @@ -51,16 +52,6 @@ public class JavaJoinGameTranslator extends PacketTranslator("doimmediaterespawn", !packet.isEnableRespawnScreen())); - session.sendUpstreamPacket(gamerulePacket); - session.setRenderDistance(packet.getViewDistance()); // We need to send our skin parts to the server otherwise java sees us with no hat, jacket etc - String locale = session.getLocale(); + String locale = session.getClientData().getLanguageCode(); List skinParts = Arrays.asList(SkinPart.values()); - ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND); + ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, Hand.MAIN_HAND); session.sendDownstreamPacket(clientSettingsPacket); - session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData())); - - if (!newDimension.equals(session.getDimension())) { - DimensionUtils.switchDimension(session, newDimension); + if (DimensionUtils.javaToBedrock(packet.getDimension()) != entity.getDimension()) { + DimensionUtils.switchDimension(session, packet.getDimension()); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaKeepAliveTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaKeepAliveTranslator.java deleted file mode 100644 index 76e9b095..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaKeepAliveTranslator.java +++ /dev/null @@ -1,47 +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.connector.network.translators.java; - -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket; -import com.nukkitx.protocol.bedrock.packet.NetworkStackLatencyPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; - -/** - * Used to forward the keep alive packet to the client in order to get back a reliable ping. - */ -@Translator(packet = ServerKeepAlivePacket.class) -public class JavaKeepAliveTranslator extends PacketTranslator { - - @Override - public void translate(ServerKeepAlivePacket packet, GeyserSession session) { - NetworkStackLatencyPacket latencyPacket = new NetworkStackLatencyPacket(); - latencyPacket.setFromServer(true); - latencyPacket.setTimestamp(packet.getPingId() * 1000); - session.sendUpstreamPacket(latencyPacket); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginDisconnectTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginDisconnectTranslator.java deleted file mode 100644 index 3433edcc..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginDisconnectTranslator.java +++ /dev/null @@ -1,42 +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.connector.network.translators.java; - -import com.github.steveice10.mc.protocol.packet.login.server.LoginDisconnectPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.chat.MessageTranslator; - -@Translator(packet = LoginDisconnectPacket.class) -public class JavaLoginDisconnectTranslator extends PacketTranslator { - - @Override - public void translate(LoginDisconnectPacket packet, GeyserSession session) { - // The client doesn't manually get disconnected so we have to do it ourselves - session.disconnect(MessageTranslator.convertMessage(packet.getReason(), session.getLocale())); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginPluginMessageTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginPluginMessageTranslator.java index 74583b79..f2a2bf02 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginPluginMessageTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaLoginPluginMessageTranslator.java @@ -1,28 +1,3 @@ -/* - * 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.connector.network.translators.java; import org.geysermc.connector.network.session.GeyserSession; diff --git a/connector/src/main/java/org/geysermc/connector/utils/PluginMessageUtils.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaPluginMessageTranslator.java similarity index 64% rename from connector/src/main/java/org/geysermc/connector/utils/PluginMessageUtils.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/JavaPluginMessageTranslator.java index c5a7d9e8..85c7ab13 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/PluginMessageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaPluginMessageTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,30 +23,39 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.utils; +package org.geysermc.connector.network.translators.java; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; + +import com.github.steveice10.mc.protocol.packet.ingame.client.ClientPluginMessagePacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPluginMessagePacket; import java.nio.charset.StandardCharsets; -public class PluginMessageUtils { +@Translator(packet = ServerPluginMessagePacket.class) +public class JavaPluginMessageTranslator extends PacketTranslator { - private static final byte[] BRAND_DATA; + private static byte[] brandData; static { byte[] data = GeyserConnector.NAME.getBytes(StandardCharsets.UTF_8); byte[] varInt = writeVarInt(data.length); - BRAND_DATA = new byte[varInt.length + data.length]; - System.arraycopy(varInt, 0, BRAND_DATA, 0, varInt.length); - System.arraycopy(data, 0, BRAND_DATA, varInt.length, data.length); + brandData = new byte[varInt.length + data.length]; + System.arraycopy(varInt, 0, brandData, 0, varInt.length); + System.arraycopy(data, 0, brandData, varInt.length, data.length); } - /** - * Get the prebuilt brand as a byte array - * @return the brand information of the Geyser client - */ - public static byte[] getGeyserBrandData() { - return BRAND_DATA; + + @Override + public void translate(ServerPluginMessagePacket packet, GeyserSession session) { + if (packet.getChannel().equals("minecraft:brand")) { + session.sendDownstreamPacket( + new ClientPluginMessagePacket(packet.getChannel(), brandData) + ); + } } private static byte[] writeVarInt(int value) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java index 6c8faeb5..086291db 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaRespawnTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,9 @@ package org.geysermc.connector.network.translators.java; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket; 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.SetPlayerGameTypePacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.attribute.AttributeType; import org.geysermc.connector.network.session.GeyserSession; @@ -37,12 +35,19 @@ import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.DimensionUtils; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket; +import com.nukkitx.protocol.bedrock.packet.SetPlayerGameTypePacket; + +import java.util.concurrent.ThreadLocalRandom; + @Translator(packet = ServerRespawnPacket.class) public class JavaRespawnTranslator extends PacketTranslator { @Override public void translate(ServerRespawnPacket packet, GeyserSession session) { Entity entity = session.getPlayerEntity(); + if (entity == null) + return; float maxHealth = entity.getAttributes().containsKey(AttributeType.MAX_HEALTH) ? entity.getAttributes().get(AttributeType.MAX_HEALTH).getValue() : 20f; // Max health must be divisible by two in bedrock @@ -55,33 +60,23 @@ public class JavaRespawnTranslator extends PacketTranslator session.sendUpstreamPacket(playerGameTypePacket); session.setGameMode(packet.getGamemode()); - if (session.isRaining()) { - LevelEventPacket stopRainPacket = new LevelEventPacket(); - stopRainPacket.setType(LevelEventType.STOP_RAINING); - stopRainPacket.setData(0); - stopRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopRainPacket); - session.setRaining(false); - } + LevelEventPacket stopRainPacket = new LevelEventPacket(); + stopRainPacket.setType(LevelEventType.STOP_RAIN); + stopRainPacket.setData(ThreadLocalRandom.current().nextInt(50000) + 10000); + stopRainPacket.setPosition(Vector3f.ZERO); + session.sendUpstreamPacket(stopRainPacket); - if (session.isThunder()) { - LevelEventPacket stopThunderPacket = new LevelEventPacket(); - stopThunderPacket.setType(LevelEventType.STOP_THUNDERSTORM); - stopThunderPacket.setData(0); - stopThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(stopThunderPacket); - session.setThunder(false); - } - - String newDimension = DimensionUtils.getNewDimension(packet.getDimension()); - if (!session.getDimension().equals(newDimension) || !packet.getWorldName().equals(session.getWorldName())) { - if (!packet.getWorldName().equals(session.getWorldName()) && session.getDimension().equals(newDimension)) { - // Switching to a new world (based off the world name change); send a fake dimension change - String fakeDim = DimensionUtils.getTemporaryDimension(session.getDimension(), newDimension); + if (entity.getDimension() != DimensionUtils.javaToBedrock(packet.getDimension())) { + DimensionUtils.switchDimension(session, packet.getDimension()); + } else { + if (session.isManyDimPackets()) { //reloading world + int fakeDim = entity.getDimension() == 0 ? -1 : 0; DimensionUtils.switchDimension(session, fakeDim); + DimensionUtils.switchDimension(session, packet.getDimension()); + } else { + // Handled in JavaPlayerPositionRotationTranslator + session.setSpawned(false); } - session.setWorldName(packet.getWorldName()); - DimensionUtils.switchDimension(session, newDimension); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaStatisticsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaStatisticsTranslator.java deleted file mode 100644 index 9bf810e2..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaStatisticsTranslator.java +++ /dev/null @@ -1,46 +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.connector.network.translators.java; - -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerStatisticsPacket; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.utils.StatisticsUtils; - -@Translator(packet = ServerStatisticsPacket.class) -public class JavaStatisticsTranslator extends PacketTranslator { - - @Override - public void translate(ServerStatisticsPacket packet, GeyserSession session) { - session.updateStatistics(packet.getStatistics()); - - if (session.isWaitingForStatistics()) { - session.setWaitingForStatistics(false); - session.sendForm(StatisticsUtils.buildMenuForm(session), StatisticsUtils.STATISTICS_MENU_FORM_ID); - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java index d3b93068..8ecf4e30 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/JavaTitleTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +28,7 @@ package org.geysermc.connector.network.translators.java; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.chat.MessageTranslator; +import org.geysermc.connector.utils.MessageUtils; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerTitlePacket; import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; @@ -39,35 +39,26 @@ public class JavaTitleTranslator extends PacketTranslator { @Override public void translate(ServerTitlePacket packet, GeyserSession session) { SetTitlePacket titlePacket = new SetTitlePacket(); - String locale = session.getLocale(); - - String text; - if (packet.getTitle() == null) { - text = " "; - } else { - text = MessageTranslator.convertMessage(packet.getTitle(), locale); - } switch (packet.getAction()) { case TITLE: - titlePacket.setType(SetTitlePacket.Type.TITLE); - titlePacket.setText(text); + titlePacket.setType(SetTitlePacket.Type.SET_TITLE); + titlePacket.setText(MessageUtils.getBedrockMessage(packet.getTitle())); break; case SUBTITLE: - titlePacket.setType(SetTitlePacket.Type.SUBTITLE); - titlePacket.setText(text); + titlePacket.setType(SetTitlePacket.Type.SET_SUBTITLE); + titlePacket.setText(MessageUtils.getBedrockMessage(packet.getTitle())); break; case CLEAR: case RESET: - titlePacket.setType(SetTitlePacket.Type.CLEAR); + titlePacket.setType(SetTitlePacket.Type.RESET_TITLE); titlePacket.setText(""); break; case ACTION_BAR: - titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - titlePacket.setText(text); + titlePacket.setType(SetTitlePacket.Type.SET_ACTIONBAR_MESSAGE); + titlePacket.setText(MessageUtils.getBedrockMessage(packet.getTitle())); break; case TIMES: - titlePacket.setType(SetTitlePacket.Type.TIMES); titlePacket.setFadeInTime(packet.getFadeIn()); titlePacket.setFadeOutTime(packet.getFadeOut()); titlePacket.setStayTime(packet.getStay()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAnimationTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAnimationTranslator.java index 53c2864c..4f2fe022 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAnimationTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAnimationTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java index b7ca66fe..6e53df27 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityAttachTranslator.java @@ -1,34 +1,35 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.java.entity; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityAttachPacket; -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.EntityData; +import com.nukkitx.protocol.bedrock.data.EntityEventType; +import com.nukkitx.protocol.bedrock.data.EntityFlag; import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; @@ -62,7 +63,7 @@ public class JavaEntityAttachTranslator extends PacketTranslator { @@ -41,7 +43,7 @@ public class JavaEntityEffectTranslator extends PacketTranslator { @@ -43,6 +48,21 @@ public class JavaEntityHeadLookTranslator extends PacketTranslator { @@ -46,20 +45,7 @@ public class JavaEntityMetadataTranslator extends PacketTranslator { @@ -41,7 +43,10 @@ public class JavaEntityPositionRotationTranslator extends PacketTranslator { @Override public void translate(ServerEntityPropertiesPacket packet, GeyserSession session) { - boolean isSessionPlayer = false; Entity entity = session.getEntityCache().getEntityByJavaId(packet.getEntityId()); if (packet.getEntityId() == session.getPlayerEntity().getEntityId()) { entity = session.getPlayerEntity(); - isSessionPlayer = true; } if (entity == null) return; @@ -55,13 +54,6 @@ public class JavaEntityPropertiesTranslator extends PacketTranslator { @@ -41,7 +43,7 @@ public class JavaEntityRemoveEffectTranslator extends PacketTranslator { @@ -42,6 +47,23 @@ public class JavaEntityRotationTranslator extends PacketTranslator 1)); rider = false; } @@ -99,177 +90,66 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator id == passengerId)) { SetEntityLinkPacket linkPacket = new SetEntityLinkPacket(); - linkPacket.setEntityLink(new EntityLinkData(entity.getGeyserId(), passenger.getGeyserId(), EntityLinkData.Type.REMOVE, false)); + linkPacket.setEntityLink(new EntityLink(entity.getGeyserId(), passenger.getGeyserId(), EntityLink.Type.REMOVE, false)); session.sendUpstreamPacket(linkPacket); passengers.remove(passenger.getEntityId()); - passenger.getMetadata().put(EntityData.RIDER_ROTATION_LOCKED, (byte) 0); - passenger.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 0f); - passenger.getMetadata().put(EntityData.RIDER_MIN_ROTATION, 0f); - this.updateOffset(passenger, entity, session, false, false, (packet.getPassengerIds().length > 1)); - } else { - this.updateOffset(passenger, entity, session, (packet.getPassengerIds()[0] == passengerId), true, (packet.getPassengerIds().length > 1)); + this.updateOffset(passenger, entity.getEntityType(), session, false, false, (passengers.size() > 1)); } - - // Force an update to the passenger metadata - passenger.updateBedrockMetadata(session); } - switch (entity.getEntityType()) { - case HORSE: - case SKELETON_HORSE: - case DONKEY: - case MULE: - case RAVAGER: - entity.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 181.0f); - entity.updateBedrockMetadata(session); - break; + if (entity.getEntityType() == EntityType.HORSE) { + entity.getMetadata().put(EntityData.RIDER_SEAT_POSITION, Vector3f.from(0.0f, 2.3200102f, -0.2f)); + entity.getMetadata().put(EntityData.RIDER_MAX_ROTATION, 181.0f); + + entity.updateBedrockMetadata(session); } } - private float getMountedHeightOffset(Entity mount) { - float height = mount.getMetadata().getFloat(EntityData.BOUNDING_BOX_HEIGHT); - float mountedHeightOffset = height * 0.75f; - switch (mount.getEntityType()) { - case CHICKEN: - case SPIDER: - mountedHeightOffset = height * 0.5f; - break; - case DONKEY: - case MULE: - mountedHeightOffset -= 0.25f; - break; - case LLAMA: - mountedHeightOffset = height * 0.67f; + private void updateOffset(Entity passenger, EntityType mountType, GeyserSession session, boolean rider, boolean riding, boolean moreThanOneEntity) { + // Without the Y offset, Bedrock players will find themselves in the floor when mounting + float yOffset = 0; + switch (mountType) { + case BOAT: + yOffset = passenger.getEntityType() == EntityType.PLAYER ? 1.02001f : -0.2f; break; case MINECART: - case MINECART_HOPPER: - case MINECART_TNT: - case MINECART_CHEST: - case MINECART_FURNACE: - case MINECART_SPAWNER: - case MINECART_COMMAND_BLOCK: - mountedHeightOffset = 0; + yOffset = passenger.getEntityType() == EntityType.PLAYER ? 1.02001f : 0f; break; - case BOAT: - mountedHeightOffset = -0.1f; - break; - case HOGLIN: - case ZOGLIN: - boolean isBaby = mount.getMetadata().getFlags().getFlag(EntityFlag.BABY); - mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f); - break; - case PIGLIN: - mountedHeightOffset = height * 0.92f; - break; - case RAVAGER: - mountedHeightOffset = 2.1f; + case DONKEY: + yOffset = 2.1f; break; + case HORSE: case SKELETON_HORSE: - mountedHeightOffset -= 0.1875f; + case ZOMBIE_HORSE: + case MULE: + yOffset = 2.3f; break; - case STRIDER: - mountedHeightOffset = height - 0.19f; + case LLAMA: + case TRADER_LLAMA: + yOffset = 2.5f; + break; + case PIG: + yOffset = 1.85001f; break; - } - return mountedHeightOffset; - } - - private float getHeightOffset(Entity passenger) { - boolean isBaby; - switch (passenger.getEntityType()) { - case SKELETON: - case STRAY: - case WITHER_SKELETON: - return -0.6f; case ARMOR_STAND: - if (((ArmorStandEntity) passenger).isMarker()) { - return 0.0f; - } else { - return 0.1f; - } - case ENDERMITE: - case SILVERFISH: - return 0.1f; - case PIGLIN: - case PIGLIN_BRUTE: - case ZOMBIFIED_PIGLIN: - isBaby = passenger.getMetadata().getFlags().getFlag(EntityFlag.BABY); - return isBaby ? -0.05f : -0.45f; - case ZOMBIE: - isBaby = passenger.getMetadata().getFlags().getFlag(EntityFlag.BABY); - return isBaby ? 0.0f : -0.45f; - case EVOKER: - case ILLUSIONER: - case PILLAGER: - case RAVAGER: - case VINDICATOR: - case WITCH: - return -0.45f; - case PLAYER: - return -0.35f; + yOffset = 1.3f; + break; } - if (passenger instanceof AnimalEntity) { - return 0.14f; + Vector3f offset = Vector3f.from(0f, yOffset, 0f); + // Without the X offset, more than one entity on a boat is stacked on top of each other + if (rider && moreThanOneEntity) { + offset = offset.add(Vector3f.from(0.2, 0, 0)); + } else if (moreThanOneEntity) { + offset = offset.add(Vector3f.from(-0.6, 0, 0)); } - return 0f; - } - - private void updateOffset(Entity passenger, Entity mount, GeyserSession session, boolean rider, boolean riding, boolean moreThanOneEntity) { passenger.getMetadata().getFlags().setFlag(EntityFlag.RIDING, riding); if (riding) { - // Without the Y offset, Bedrock players will find themselves in the floor when mounting - float mountedHeightOffset = getMountedHeightOffset(mount); - float heightOffset = getHeightOffset(passenger); - - float xOffset = 0; - float yOffset = mountedHeightOffset + heightOffset; - float zOffset = 0; - switch (mount.getEntityType()) { - 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; - } - /* - * Bedrock Differences - * Zoglin & Hoglin seem to be taller in Bedrock edition - * Horses are tinier - * Players, Minecarts, and Boats have different origins - */ - if (passenger.getEntityType() == EntityType.PLAYER && mount.getEntityType() != EntityType.PLAYER) { - yOffset += EntityType.PLAYER.getOffset(); - } - switch (mount.getEntityType()) { - case MINECART: - case MINECART_HOPPER: - case MINECART_TNT: - case MINECART_CHEST: - case MINECART_FURNACE: - case MINECART_SPAWNER: - case MINECART_COMMAND_BLOCK: - case BOAT: - yOffset -= mount.getEntityType().getHeight() * 0.5f; - } - Vector3f offset = Vector3f.from(xOffset, yOffset, zOffset); passenger.getMetadata().put(EntityData.RIDER_SEAT_POSITION, offset); } passenger.updateBedrockMetadata(session); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java index 59ea2992..b8675dbf 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityStatusTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,22 +25,14 @@ package org.geysermc.connector.network.translators.java.entity; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityStatusPacket; -import com.nukkitx.protocol.bedrock.data.SoundEvent; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.entity.EntityData; -import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; -import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; -import com.nukkitx.protocol.bedrock.packet.LevelSoundEvent2Packet; -import com.nukkitx.protocol.bedrock.packet.SetEntityDataPacket; -import com.nukkitx.protocol.bedrock.packet.SetEntityMotionPacket; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemRegistry; + +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityStatusPacket; +import com.nukkitx.protocol.bedrock.data.EntityEventType; +import com.nukkitx.protocol.bedrock.packet.EntityEventPacket; @Translator(packet = ServerEntityStatusPacket.class) public class JavaEntityStatusTranslator extends PacketTranslator { @@ -57,145 +49,54 @@ public class JavaEntityStatusTranslator extends PacketTranslator { @Override public void translate(ServerPlayerAbilitiesPacket packet, GeyserSession session) { - PlayerEntity entity = session.getPlayerEntity(); + Entity entity = session.getPlayerEntity(); if (entity == null) return; - session.setCanFly(packet.isCanFly()); - session.setFlying(packet.isFlying()); - session.sendAdventureSettings(); + EntityDataMap metadata = entity.getMetadata(); + metadata.getFlags().setFlag(EntityFlag.CAN_FLY, packet.isCanFly()); + + SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); + entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); + entityDataPacket.getMetadata().putAll(metadata); + session.sendUpstreamPacket(entityDataPacket); + + Set playerFlags = new ObjectOpenHashSet<>(); + playerFlags.add(AdventureSettingsPacket.Flag.AUTO_JUMP); + if (packet.isCanFly()) + playerFlags.add(AdventureSettingsPacket.Flag.MAY_FLY); + + if (packet.isFlying()) + playerFlags.add(AdventureSettingsPacket.Flag.FLYING); + + AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); + adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); + // Required or the packet simply is not sent + adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); + adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId()); + adventureSettingsPacket.getFlags().addAll(playerFlags); + session.sendUpstreamPacket(adventureSettingsPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java index 837adb12..b049d0be 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/player/JavaPlayerActionAckTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,20 +27,19 @@ package org.geysermc.connector.network.translators.java.entity.player; 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.entity.player.PlayerAction; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerActionAckPacket; -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.math.vector.Vector3f; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import org.geysermc.connector.inventory.PlayerInventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; -import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.utils.BlockUtils; +import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.ChunkUtils; @Translator(packet = ServerPlayerActionAckPacket.class) @@ -48,54 +47,54 @@ public class JavaPlayerActionAckTranslator extends PacketTranslator - GeyserConnector.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data")); + SkinUtils.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> { + GeyserConnector.getInstance().getLogger().debug("Loading Local Bedrock Java Skin Data"); + }); } else { playerEntity = session.getEntityCache().getPlayerEntity(entry.getProfile().getId()); } @@ -82,25 +82,36 @@ public class JavaPlayerListEntryTranslator extends PacketTranslator { @Override public void translate(ServerPlayerPositionRotationPacket packet, GeyserSession session) { - if (!session.isLoggedIn()) + PlayerEntity entity = session.getPlayerEntity(); + if (entity == null) return; - PlayerEntity entity = session.getPlayerEntity(); + if (!session.isLoggedIn()) + return; if (!session.isSpawned()) { Vector3f pos = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); @@ -57,11 +60,17 @@ public class JavaPlayerPositionRotationTranslator extends PacketTranslator { +public class JavaPlayerStopSoundTranslator extends PacketTranslator { @Override public void translate(ServerStopSoundPacket packet, GeyserSession session) { - // Runs if all sounds are stopped - if (packet.getSound() == null) { - StopSoundPacket stopPacket = new StopSoundPacket(); - stopPacket.setStoppingAllSound(true); - stopPacket.setSoundName(""); - session.sendUpstreamPacket(stopPacket); - return; - } - String packetSound; - if (packet.getSound() instanceof BuiltinSound) { + if(packet.getSound() instanceof BuiltinSound) { packetSound = ((BuiltinSound) packet.getSound()).getName(); - } else if (packet.getSound() instanceof CustomSound) { + } else if(packet.getSound() instanceof CustomSound) { packetSound = ((CustomSound) packet.getSound()).getName(); } else { session.getConnector().getLogger().debug("Unknown sound packet, we were unable to map this. " + packet.toString()); return; } - SoundRegistry.SoundMapping soundMapping = SoundRegistry.fromJava(packetSound.replace("minecraft:", "")); + SoundRegistry.SoundMapping soundMapping = SoundRegistry.fromJava(packetSound); session.getConnector().getLogger() .debug("[StopSound] Sound mapping " + packetSound + " -> " + soundMapping + (soundMapping == null ? "[not found]" : "") + " - " + packet.toString()); String playsound; - if (soundMapping == null || soundMapping.getPlaysound() == null) { + if(soundMapping == null || soundMapping.getPlaysound() == null) { // no mapping session.getConnector().getLogger() .debug("[StopSound] Defaulting to sound server gave us."); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java index efbdfc5b..920969a7 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 +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.server.entity.spawn.ServerSpawnEntityPacket; import com.nukkitx.math.vector.Vector3f; -import org.geysermc.connector.entity.*; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.FallingBlockEntity; +import org.geysermc.connector.entity.FishingHookEntity; +import org.geysermc.connector.entity.ItemFrameEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.EntityUtils; -import org.geysermc.connector.utils.LanguageUtils; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -53,7 +55,7 @@ public class JavaSpawnEntityTranslator extends PacketTranslator entityConstructor = entityClass.getConstructor(long.class, long.class, org.geysermc.connector.entity.type.EntityType.class, Vector3f.class, Vector3f.class, Vector3f.class); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java index a158751c..79ba3e0f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnExpOrbTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java index 96d93fab..8c246e51 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnLivingEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.EntityUtils; -import org.geysermc.connector.utils.LanguageUtils; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -49,7 +48,7 @@ public class JavaSpawnLivingEntityTranslator extends PacketTranslator { @@ -43,26 +42,20 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator entity.sendPlayer(session)); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockEmoteTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnWeatherEntityTranslator.java similarity index 57% rename from connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockEmoteTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnWeatherEntityTranslator.java index a9e911ac..c50686a0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockEmoteTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnWeatherEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,30 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock.entity.player; +package org.geysermc.connector.network.translators.java.entity.spawn; -import com.nukkitx.protocol.bedrock.packet.EmotePacket; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -@Translator(packet = EmotePacket.class) -public class BedrockEmoteTranslator extends PacketTranslator { +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnWeatherEntityPacket; +import com.nukkitx.math.vector.Vector3f; + +@Translator(packet = ServerSpawnWeatherEntityPacket.class) +public class JavaSpawnWeatherEntityTranslator extends PacketTranslator { @Override - public void translate(EmotePacket packet, GeyserSession session) { - long javaId = session.getPlayerEntity().getEntityId(); - for (GeyserSession otherSession : session.getConnector().getPlayers()) { - if (otherSession != session) { - if (otherSession.isClosed()) continue; - Entity otherEntity = otherSession.getEntityCache().getEntityByJavaId(javaId); - if (otherEntity == null) continue; - packet.setRuntimeEntityId(otherEntity.getGeyserId()); - otherSession.sendUpstreamPacket(packet); - } - } + public void translate(ServerSpawnWeatherEntityPacket packet, GeyserSession session) { + Vector3f position = Vector3f.from(packet.getX(), packet.getY(), packet.getZ()); + + // Currently WeatherEntityType only has a lightning bolt + Entity entity = new Entity( + packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(), + EntityType.LIGHTNING_BOLT, position, Vector3f.ZERO, Vector3f.ZERO + ); + + session.getEntityCache().spawnEntity(entity); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java index dc2112b6..5a722953 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaDisplayScoreboardTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ public class JavaDisplayScoreboardTranslator extends PacketTranslator { - private static final GeyserLogger LOGGER = GeyserConnector.getInstance().getLogger(); @Override public void translate(ServerTeamPacket packet, GeyserSession session) { - if (LOGGER.isDebug()) { - LOGGER.debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers())); - } + GeyserConnector.getInstance().getLogger().debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers())); - int pps = session.getWorldCache().increaseAndGetScoreboardPacketsPerSecond(); - - Scoreboard scoreboard = session.getWorldCache().getScoreboard(); + Scoreboard scoreboard = session.getScoreboardCache().getScoreboard(); Team team = scoreboard.getTeam(packet.getTeamName()); switch (packet.getAction()) { case CREATE: scoreboard.registerNewTeam(packet.getTeamName(), toPlayerSet(packet.getPlayers())) - .setName(MessageTranslator.convertMessage(packet.getDisplayName())) + .setName(MessageUtils.getBedrockMessage(packet.getDisplayName())) .setColor(packet.getColor()) - .setNameTagVisibility(packet.getNameTagVisibility()) - .setPrefix(MessageTranslator.convertMessage(packet.getPrefix(), session.getLocale())) - .setSuffix(MessageTranslator.convertMessage(packet.getSuffix(), session.getLocale())); + .setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix())) + .setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix())); break; case UPDATE: - if (team == null) { - LOGGER.debug(LanguageUtils.getLocaleStringLog( - "geyser.network.translator.team.failed_not_registered", - packet.getAction(), packet.getTeamName() - )); - return; + if (team != null) { + team.setName(MessageUtils.getBedrockMessage(packet.getDisplayName())) + .setColor(packet.getColor()) + .setPrefix(MessageUtils.getBedrockMessage(packet.getPrefix())) + .setSuffix(MessageUtils.getBedrockMessage(packet.getSuffix())) + .setUpdateType(UpdateType.UPDATE); + } else { + GeyserConnector.getInstance().getLogger().error("Error while translating Team Packet " + packet.getAction() + "! Scoreboard Team " + packet.getTeamName() + " is not registered."); } - - team.setName(MessageTranslator.convertMessage(packet.getDisplayName())) - .setColor(packet.getColor()) - .setNameTagVisibility(packet.getNameTagVisibility()) - .setPrefix(MessageTranslator.convertMessage(packet.getPrefix(), session.getLocale())) - .setSuffix(MessageTranslator.convertMessage(packet.getSuffix(), session.getLocale())) - .setUpdateType(UpdateType.UPDATE); break; case ADD_PLAYER: - if (team == null) { - LOGGER.debug(LanguageUtils.getLocaleStringLog( - "geyser.network.translator.team.failed_not_registered", - packet.getAction(), packet.getTeamName() - )); - return; + if(team != null){ + team.addEntities(packet.getPlayers()); + } else { + GeyserConnector.getInstance().getLogger().error("Error while translating Team Packet " + packet.getAction() + "! Scoreboard Team " + packet.getTeamName() + " is not registered."); } - team.addEntities(packet.getPlayers()); break; case REMOVE_PLAYER: - if (team == null) { - LOGGER.debug(LanguageUtils.getLocaleStringLog( - "geyser.network.translator.team.failed_not_registered", - packet.getAction(), packet.getTeamName() - )); - return; + if(team != null){ + team.removeEntities(packet.getPlayers()); + } else { + GeyserConnector.getInstance().getLogger().error("Error while translating Team Packet " + packet.getAction() + "! Scoreboard Team " + packet.getTeamName() + " is not registered."); } - team.removeEntities(packet.getPlayers()); break; case REMOVE: scoreboard.removeTeam(packet.getTeamName()); break; } - - // ScoreboardUpdater will handle it for us if the packets per second - // (for score and team packets) is higher then the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { - scoreboard.onUpdate(); - } + scoreboard.onUpdate(); } private Set toPlayerSet(String[] players) { - return new ObjectOpenHashSet<>(players); + return new ObjectOpenHashSet<>(Arrays.asList(players)); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java index b7054b1e..eac2ed04 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/scoreboard/JavaUpdateScoreTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,58 +25,47 @@ package org.geysermc.connector.network.translators.java.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction; -import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.GeyserLogger; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.cache.WorldCache; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.scoreboard.Objective; import org.geysermc.connector.scoreboard.Scoreboard; -import org.geysermc.connector.scoreboard.ScoreboardUpdater; -import org.geysermc.connector.utils.LanguageUtils; + +import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction; +import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; @Translator(packet = ServerUpdateScorePacket.class) public class JavaUpdateScoreTranslator extends PacketTranslator { - private final GeyserLogger logger; - - public JavaUpdateScoreTranslator() { - logger = GeyserConnector.getInstance().getLogger(); - } @Override public void translate(ServerUpdateScorePacket packet, GeyserSession session) { - WorldCache worldCache = session.getWorldCache(); - Scoreboard scoreboard = worldCache.getScoreboard(); - int pps = worldCache.increaseAndGetScoreboardPacketsPerSecond(); + try { + Scoreboard scoreboard = session.getScoreboardCache().getScoreboard(); - Objective objective = scoreboard.getObjective(packet.getObjective()); - if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) { - logger.info(LanguageUtils.getLocaleStringLog("geyser.network.translator.score.failed_objective", packet.getObjective())); - return; - } + Objective objective = scoreboard.getObjective(packet.getObjective()); + if (objective == null && packet.getAction() != ScoreboardAction.REMOVE) { + GeyserConnector.getInstance().getLogger().info("Tried to update score without the existence of its requested objective '" + packet.getObjective() + '\''); + return; + } - switch (packet.getAction()) { - case ADD_OR_UPDATE: - objective.setScore(packet.getEntry(), packet.getValue()); - break; - case REMOVE: - if (objective != null) { - objective.removeScore(packet.getEntry()); - } else { - for (Objective objective1 : scoreboard.getObjectives().values()) { - objective1.removeScore(packet.getEntry()); + switch (packet.getAction()) { + case ADD_OR_UPDATE: + objective.setScore(packet.getEntry(), packet.getValue()); + break; + case REMOVE: + if (objective != null) { + objective.resetScore(packet.getEntry()); + } else { + for (Objective objective1 : scoreboard.getObjectives().values()) { + objective1.resetScore(packet.getEntry()); + } } - } - break; - } - - // ScoreboardUpdater will handle it for us if the packets per second - // (for score and team packets) is higher then the first threshold - if (pps < ScoreboardUpdater.FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { + break; + } scoreboard.onUpdate(); + } catch (Exception ex) { + ex.printStackTrace(); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java index 770e73cc..93cfa08e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaCloseWindowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java index cc0d153b..e6787753 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaConfirmTransactionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java index 4c50b313..dde45cf8 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaOpenWindowTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,16 @@ package org.geysermc.connector.network.translators.java.window; import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientCloseWindowPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.window.ServerOpenWindowPacket; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; +import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; import org.geysermc.connector.utils.InventoryUtils; -import org.geysermc.connector.utils.LocaleUtils; -import org.geysermc.connector.network.translators.chat.MessageTranslator; @Translator(packet = ServerOpenWindowPacket.class) public class JavaOpenWindowTranslator extends PacketTranslator { @@ -56,9 +58,18 @@ public class JavaOpenWindowTranslator extends PacketTranslator { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java index a50518e8..2cc392f5 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowItemsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java index d325f36d..daebed1b 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/window/JavaWindowPropertyTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockBreakAnimTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockBreakAnimTranslator.java index 559d1a92..27bc34c9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockBreakAnimTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockBreakAnimTranslator.java @@ -1,30 +1,32 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.java.world; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockBreakAnimPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3f; @@ -42,8 +44,8 @@ public class JavaBlockBreakAnimTranslator extends PacketTranslator { @Override public void translate(ServerBlockChangePacket packet, GeyserSession session) { Position pos = packet.getRecord().getPosition(); - boolean updatePlacement = session.getConnector().getPlatformType() != PlatformType.SPIGOT && // Spigot simply listens for the block place event - !(session.getConnector().getConfig().isCacheChunks() && - session.getConnector().getWorldManager().getBlockAt(session, pos) == packet.getRecord().getBlock()); - ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), pos); - if (updatePlacement) { + boolean updatePlacement = !(session.getConnector().getConfig().isCacheChunks() && session.getConnector().getWorldManager().getBlockAt(session, pos.getX(), pos.getY(), pos.getZ()).getId() == packet.getRecord().getBlock().getId()); + ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), packet.getRecord().getPosition()); + if (updatePlacement && session.getConnector().getPlatformType() != PlatformType.BUKKIT) { this.checkPlace(session, packet); } this.checkInteract(session, packet); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockValueTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockValueTranslator.java index 6c14f17c..dd8c336d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockValueTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockValueTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,14 @@ package org.geysermc.connector.network.translators.java.world; -import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.github.steveice10.mc.protocol.data.game.world.block.value.*; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockValuePacket; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import com.nukkitx.protocol.bedrock.packet.BlockEventPacket; + import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -54,12 +54,16 @@ public class JavaBlockValueTranslator extends PacketTranslator 0 ? 1 : 0); session.sendUpstreamPacket(blockEventPacket); - } else if (packet.getValue() instanceof EndGatewayValue) { + } + if (packet.getValue() instanceof EndGatewayValue) { blockEventPacket.setEventType(1); session.sendUpstreamPacket(blockEventPacket); - } else if (packet.getValue() instanceof NoteBlockValue) { + } + if (packet.getValue() instanceof NoteBlockValue) { NoteblockBlockEntityTranslator.translate(session, packet.getPosition()); - } else if (packet.getValue() instanceof PistonValue) { + return; + } + if (packet.getValue() instanceof PistonValue) { PistonValueType type = (PistonValueType) packet.getType(); // Unlike everything else, pistons need a block entity packet to convey motion @@ -70,46 +74,18 @@ public class JavaBlockValueTranslator extends PacketTranslator { - /** - * Determines if we should process non-full chunks - */ - private final boolean cacheChunks; - - public JavaChunkDataTranslator() { - cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks(); - } @Override public void translate(ServerChunkDataPacket packet, GeyserSession session) { @@ -60,75 +55,60 @@ public class JavaChunkDataTranslator extends PacketTranslator { try { - ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(session, mergedColumn, isNonFullChunk); - ChunkSection[] sections = chunkData.getSections(); + ChunkUtils.ChunkData chunkData = ChunkUtils.translateToBedrock(packet.getColumn()); + ByteBuf byteBuf = Unpooled.buffer(32); + ChunkSection[] sections = chunkData.sections; - // Find highest section int sectionCount = sections.length - 1; - while (sectionCount >= 0 && sections[sectionCount] == null) { + while (sectionCount >= 0 && sections[sectionCount].isEmpty()) { sectionCount--; } sectionCount++; - // Estimate chunk size - int size = 0; for (int i = 0; i < sectionCount; i++) { - ChunkSection section = sections[i]; - size += (section != null ? section : ChunkUtils.EMPTY_SECTION).estimateNetworkSize(); + ChunkSection section = chunkData.sections[i]; + section.writeToNetwork(byteBuf); } - size += 256; // Biomes - size += 1; // Border blocks - size += 1; // Extra data length (always 0) - size += chunkData.getBlockEntities().length * 64; // Conservative estimate of 64 bytes per tile entity - // Allocate output buffer - ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(size); - byte[] payload; - try { - for (int i = 0; i < sectionCount; i++) { - ChunkSection section = sections[i]; - (section != null ? section : ChunkUtils.EMPTY_SECTION).writeToNetwork(byteBuf); - } + byte[] bedrockBiome = BiomeTranslator.toBedrockBiome(packet.getColumn().getBiomeData()); - byteBuf.writeBytes(BiomeTranslator.toBedrockBiome(mergedColumn.getBiomeData())); // Biomes - 256 bytes - byteBuf.writeByte(0); // Border blocks - Edu edition only - VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now + byteBuf.writeBytes(bedrockBiome); // Biomes - 256 bytes + byteBuf.writeByte(0); // Border blocks - Edu edition only + VarInts.writeUnsignedInt(byteBuf, 0); // extra data length, 0 for now - // Encode tile entities into buffer - NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(new ByteBufOutputStream(byteBuf)); - for (NbtMap blockEntity : chunkData.getBlockEntities()) { - nbtStream.writeTag(blockEntity); - } - - // Copy data into byte[], because the protocol lib really likes things that are s l o w - byteBuf.readBytes(payload = new byte[byteBuf.readableBytes()]); - } finally { - byteBuf.release(); // Release buffer to allow buffer pooling to be useful + ByteBufOutputStream stream = new ByteBufOutputStream(Unpooled.buffer()); + NBTOutputStream nbtStream = NbtUtils.createNetworkWriter(stream); + for (CompoundTag blockEntity : chunkData.getBlockEntities()) { + nbtStream.write(blockEntity); } + byteBuf.writeBytes(stream.buffer()); + + byte[] payload = new byte[byteBuf.writerIndex()]; + byteBuf.readBytes(payload); + LevelChunkPacket levelChunkPacket = new LevelChunkPacket(); levelChunkPacket.setSubChunksLength(sectionCount); levelChunkPacket.setCachingEnabled(false); - levelChunkPacket.setChunkX(mergedColumn.getX()); - levelChunkPacket.setChunkZ(mergedColumn.getZ()); + levelChunkPacket.setChunkX(packet.getColumn().getX()); + levelChunkPacket.setChunkZ(packet.getColumn().getZ()); levelChunkPacket.setData(payload); session.sendUpstreamPacket(levelChunkPacket); + + // Some block entities need to be loaded in later or else text doesn't show (signs) or they crash the game (end gateway blocks) + for (Object2IntMap.Entry blockEntityEntry : chunkData.getLoadBlockEntitiesLater().object2IntEntrySet()) { + int x = blockEntityEntry.getKey().getInt("x"); + int y = blockEntityEntry.getKey().getInt("y"); + int z = blockEntityEntry.getKey().getInt("z"); + ChunkUtils.updateBlock(session, new BlockState(blockEntityEntry.getIntValue()), new Position(x, y, z)); + } + chunkData.getLoadBlockEntitiesLater().clear(); + session.getChunkCache().addToCache(packet.getColumn()); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityCollectItemTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaCollectItemTranslator.java similarity index 57% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityCollectItemTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaCollectItemTranslator.java index 4711e54e..31379bd2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/JavaEntityCollectItemTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaCollectItemTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,52 +23,33 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.java.entity; +package org.geysermc.connector.network.translators.java.world; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityCollectItemPacket; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import com.nukkitx.protocol.bedrock.packet.TakeItemEntityPacket; import org.geysermc.connector.entity.Entity; -import org.geysermc.connector.entity.ExpOrbEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -/** - * This packet is called whenever a player picks up an item. - * In Java, this is called for item entities, experience orbs and arrows - * Bedrock uses it for arrows and item entities, but not experience orbs. - */ @Translator(packet = ServerEntityCollectItemPacket.class) -public class JavaEntityCollectItemTranslator extends PacketTranslator { +public class JavaCollectItemTranslator extends PacketTranslator { @Override public void translate(ServerEntityCollectItemPacket packet, GeyserSession session) { - // Collected entity is the other entity + // This is the definition of translating - both packets take the same values + TakeItemEntityPacket takeItemEntityPacket = new TakeItemEntityPacket(); + // Collected entity is the item Entity collectedEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectedEntityId()); - if (collectedEntity == null) return; - // Collector is the entity 'picking up' the item + // Collector is the entity picking up the item Entity collectorEntity; if (packet.getCollectorEntityId() == session.getPlayerEntity().getEntityId()) { collectorEntity = session.getPlayerEntity(); } else { collectorEntity = session.getEntityCache().getEntityByJavaId(packet.getCollectorEntityId()); } - if (collectorEntity == null) return; - if (collectedEntity instanceof ExpOrbEntity) { - // Player just picked up an experience orb - LevelEventPacket xpPacket = new LevelEventPacket(); - xpPacket.setType(LevelEventType.SOUND_EXPERIENCE_ORB_PICKUP); - xpPacket.setPosition(collectedEntity.getPosition()); - xpPacket.setData(0); - session.sendUpstreamPacket(xpPacket); - } else { - // Item is being picked up (visual only) - TakeItemEntityPacket takeItemEntityPacket = new TakeItemEntityPacket(); - takeItemEntityPacket.setRuntimeEntityId(collectorEntity.getGeyserId()); - takeItemEntityPacket.setItemRuntimeEntityId(collectedEntity.getGeyserId()); - session.sendUpstreamPacket(takeItemEntityPacket); - } + takeItemEntityPacket.setRuntimeEntityId(collectorEntity.getGeyserId()); + takeItemEntityPacket.setItemRuntimeEntityId(collectedEntity.getGeyserId()); + session.sendUpstreamPacket(takeItemEntityPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java index 70953e8a..79b27f6a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaExplosionTranslator.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.java.world; @@ -32,7 +33,6 @@ 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.SetEntityMotionPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -46,13 +46,13 @@ public class JavaExplosionTranslator extends PacketTranslator= 2.0f ? LevelEventType.PARTICLE_HUGE_EXPLODE : LevelEventType.PARTICLE_EXPLOSION); + levelEventPacket.setType(packet.getRadius() >= 2.0f ? LevelEventType.PARTICLE_HUGE_EXPLODE : LevelEventType.PARTICLE_LARGE_EXPLOSION); levelEventPacket.setData(0); levelEventPacket.setPosition(pos.toFloat()); session.sendUpstreamPacket(levelEventPacket); @@ -65,12 +65,5 @@ public class JavaExplosionTranslator extends PacketTranslator 0f || packet.getPushY() > 0f || packet.getPushZ() > 0f) { - SetEntityMotionPacket motionPacket = new SetEntityMotionPacket(); - motionPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); - motionPacket.setMotion(Vector3f.from(packet.getPushX(), packet.getPushY(), packet.getPushZ())); - session.sendUpstreamPacket(motionPacket); - } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java index 8a67080a..c8be3a56 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMapDataTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 @@ import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.utils.BedrockMapIcon; -import org.geysermc.connector.utils.DimensionUtils; import org.geysermc.connector.utils.MapColor; @Translator(packet = ServerMapDataPacket.class) @@ -43,10 +42,9 @@ public class JavaMapDataTranslator extends PacketTranslator @Override public void translate(ServerMapDataPacket packet, GeyserSession session) { ClientboundMapItemDataPacket mapItemDataPacket = new ClientboundMapItemDataPacket(); - boolean shouldStore = false; mapItemDataPacket.setUniqueMapId(packet.getMapId()); - mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension())); + mapItemDataPacket.setDimensionId(session.getPlayerEntity().getDimension()); mapItemDataPacket.setLocked(packet.isLocked()); mapItemDataPacket.setScale(packet.getScale()); @@ -57,11 +55,6 @@ public class JavaMapDataTranslator extends PacketTranslator mapItemDataPacket.setWidth(data.getColumns()); mapItemDataPacket.setHeight(data.getRows()); - // We have a full map image, this usually only happens on spawn for the initial image - if (mapItemDataPacket.getWidth() == 128 && mapItemDataPacket.getHeight() == 128) { - shouldStore = true; - } - // Every int entry is an ABGR color int[] colors = new int[data.getData().length]; @@ -83,12 +76,6 @@ public class JavaMapDataTranslator extends PacketTranslator id++; } - // Store the map to send when the client requests it, as bedrock expects the data after a MapInfoRequestPacket - if (shouldStore) { - session.getStoredMaps().put(mapItemDataPacket.getUniqueMapId(), mapItemDataPacket); - } - - // Send anyway just in case - session.sendUpstreamPacket(mapItemDataPacket); + session.getUpstream().getSession().sendPacket(mapItemDataPacket); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java index de1eea0b..64733a02 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaMultiBlockChangeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java index e8b244b3..781018b2 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaNotifyClientTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,87 +28,86 @@ package org.geysermc.connector.network.translators.java.world; import com.github.steveice10.mc.protocol.data.game.ClientRequest; import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; import com.github.steveice10.mc.protocol.data.game.world.notify.EnterCreditsValue; -import com.github.steveice10.mc.protocol.data.game.world.notify.RainStrengthValue; -import com.github.steveice10.mc.protocol.data.game.world.notify.RespawnScreenValue; -import com.github.steveice10.mc.protocol.data.game.world.notify.ThunderStrengthValue; import com.github.steveice10.mc.protocol.packet.ingame.client.ClientRequestPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerNotifyClientPacket; import com.nukkitx.math.vector.Vector3f; -import com.nukkitx.protocol.bedrock.data.GameRuleData; -import com.nukkitx.protocol.bedrock.data.LevelEventType; -import com.nukkitx.protocol.bedrock.data.entity.EntityEventType; +import com.nukkitx.protocol.bedrock.data.*; import com.nukkitx.protocol.bedrock.packet.*; -import org.geysermc.connector.entity.player.PlayerEntity; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.inventory.PlayerInventoryTranslator; -import org.geysermc.connector.utils.LocaleUtils; + +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; @Translator(packet = ServerNotifyClientPacket.class) public class JavaNotifyClientTranslator extends PacketTranslator { @Override public void translate(ServerNotifyClientPacket packet, GeyserSession session) { - PlayerEntity entity = session.getPlayerEntity(); + Entity entity = session.getPlayerEntity(); if (entity == null) return; switch (packet.getNotification()) { case START_RAIN: LevelEventPacket startRainPacket = new LevelEventPacket(); - startRainPacket.setType(LevelEventType.START_RAINING); - startRainPacket.setData(Integer.MAX_VALUE); + startRainPacket.setType(LevelEventType.START_RAIN); + startRainPacket.setData(ThreadLocalRandom.current().nextInt(50000) + 10000); startRainPacket.setPosition(Vector3f.ZERO); session.sendUpstreamPacket(startRainPacket); - session.setRaining(true); break; case STOP_RAIN: LevelEventPacket stopRainPacket = new LevelEventPacket(); - stopRainPacket.setType(LevelEventType.STOP_RAINING); - stopRainPacket.setData(0); + stopRainPacket.setType(LevelEventType.STOP_RAIN); + stopRainPacket.setData(ThreadLocalRandom.current().nextInt(50000) + 10000); stopRainPacket.setPosition(Vector3f.ZERO); session.sendUpstreamPacket(stopRainPacket); - session.setRaining(false); - break; - case RAIN_STRENGTH: - // While the above values are used, they CANNOT BE TRUSTED on a vanilla server as they are swapped around - // Spigot and forks implement it correctly - // Rain strength is your best way for determining if there is any rain - RainStrengthValue value = (RainStrengthValue) packet.getValue(); - boolean isCurrentlyRaining = value.getStrength() > 0f; - // Java sends the rain level. Bedrock doesn't care, so we don't care if it's already raining. - if (isCurrentlyRaining != session.isRaining()) { - LevelEventPacket changeRainPacket = new LevelEventPacket(); - changeRainPacket.setType(isCurrentlyRaining ? LevelEventType.START_RAINING : LevelEventType.STOP_RAINING); - changeRainPacket.setData(Integer.MAX_VALUE); // Dunno what this does; used to be implemented with ThreadLocalRandom - changeRainPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeRainPacket); - session.setRaining(isCurrentlyRaining); - } - break; - case THUNDER_STRENGTH: - // See above, same process - ThunderStrengthValue thunderValue = (ThunderStrengthValue) packet.getValue(); - boolean isCurrentlyThundering = thunderValue.getStrength() > 0f; - if (isCurrentlyThundering != session.isThunder()) { - LevelEventPacket changeThunderPacket = new LevelEventPacket(); - changeThunderPacket.setType(isCurrentlyThundering ? LevelEventType.START_THUNDERSTORM : LevelEventType.STOP_THUNDERSTORM); - changeThunderPacket.setData(Integer.MAX_VALUE); - changeThunderPacket.setPosition(Vector3f.ZERO); - session.sendUpstreamPacket(changeThunderPacket); - session.setThunder(isCurrentlyThundering); - } break; case CHANGE_GAMEMODE: + Set playerFlags = new ObjectOpenHashSet<>(); GameMode gameMode = (GameMode) packet.getValue(); + if (gameMode == GameMode.ADVENTURE) + playerFlags.add(AdventureSettingsPacket.Flag.IMMUTABLE_WORLD); + + if (gameMode == GameMode.CREATIVE) + playerFlags.add(AdventureSettingsPacket.Flag.MAY_FLY); + + if (gameMode == GameMode.SPECTATOR) { + playerFlags.add(AdventureSettingsPacket.Flag.MAY_FLY); + playerFlags.add(AdventureSettingsPacket.Flag.NO_CLIP); + playerFlags.add(AdventureSettingsPacket.Flag.FLYING); + gameMode = GameMode.CREATIVE; // spectator doesnt exist on bedrock + } + + playerFlags.add(AdventureSettingsPacket.Flag.AUTO_JUMP); SetPlayerGameTypePacket playerGameTypePacket = new SetPlayerGameTypePacket(); playerGameTypePacket.setGamemode(gameMode.ordinal()); session.sendUpstreamPacket(playerGameTypePacket); session.setGameMode(gameMode); - session.sendAdventureSettings(); + // We need to delay this because otherwise it's overridden by the adventure settings from the abilities packet + session.getConnector().getGeneralThreadPool().schedule(() -> { + AdventureSettingsPacket adventureSettingsPacket = new AdventureSettingsPacket(); + adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); + adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); + adventureSettingsPacket.setUniqueEntityId(entity.getGeyserId()); + adventureSettingsPacket.getFlags().addAll(playerFlags); + session.sendUpstreamPacket(adventureSettingsPacket); + }, 50, TimeUnit.MILLISECONDS); + + EntityDataMap metadata = entity.getMetadata(); + metadata.getFlags().setFlag(EntityFlag.CAN_FLY, gameMode == GameMode.CREATIVE); + + SetEntityDataPacket entityDataPacket = new SetEntityDataPacket(); + entityDataPacket.setRuntimeEntityId(entity.getGeyserId()); + entityDataPacket.getMetadata().putAll(metadata); + session.sendUpstreamPacket(entityDataPacket); // Update the crafting grid to add/remove barriers for creative inventory PlayerInventoryTranslator.updateCraftingGrid(session, session.getInventory()); @@ -133,26 +132,6 @@ public class JavaNotifyClientTranslator extends PacketTranslator("doimmediaterespawn", - packet.getValue() == RespawnScreenValue.IMMEDIATE_RESPAWN)); - session.sendUpstreamPacket(gamerulePacket); - break; - case INVALID_BED: - // Not sent as a proper message? Odd. - session.sendMessage(LocaleUtils.getLocaleString("block.minecraft.spawn.not_valid", - session.getLocale())); - break; - case ARROW_HIT_PLAYER: - PlaySoundPacket arrowSoundPacket = new PlaySoundPacket(); - arrowSoundPacket.setSound("random.orb"); - arrowSoundPacket.setPitch(0.5f); - arrowSoundPacket.setVolume(0.5f); - arrowSoundPacket.setPosition(entity.getPosition()); - session.sendUpstreamPacket(arrowSoundPacket); - break; default: break; } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java index f9be5563..f51e35fe 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayBuiltinSoundTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +34,8 @@ import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; -import org.geysermc.connector.network.translators.sound.SoundRegistry; import org.geysermc.connector.network.translators.world.block.BlockTranslator; +import org.geysermc.connector.network.translators.sound.SoundRegistry; @Translator(packet = ServerPlayBuiltinSoundPacket.class) public class JavaPlayBuiltinSoundTranslator extends PacketTranslator { @@ -70,9 +70,8 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator { @Override public void translate(ServerPlayEffectPacket packet, GeyserSession session) { - // Separate case since each RecordEffectData in Java is an individual track in Bedrock - if (packet.getEffect() == SoundEffect.RECORD) { - RecordEffectData recordEffectData = (RecordEffectData) packet.getData(); - SoundEvent soundEvent = EffectRegistry.RECORDS.getOrDefault(recordEffectData.getRecordId(), SoundEvent.STOP_RECORD); - Vector3f pos = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f); - - LevelSoundEventPacket levelSoundEvent = new LevelSoundEventPacket(); - levelSoundEvent.setIdentifier(""); - levelSoundEvent.setSound(soundEvent); - levelSoundEvent.setPosition(pos); - levelSoundEvent.setRelativeVolumeDisabled(packet.isBroadcast()); - levelSoundEvent.setExtraData(-1); - levelSoundEvent.setBabySound(false); - session.sendUpstreamPacket(levelSoundEvent); - - if (soundEvent != SoundEvent.STOP_RECORD) { - // Send text packet as it seems to be handled in Java Edition client-side. - TextPacket textPacket = new TextPacket(); - textPacket.setType(TextPacket.Type.JUKEBOX_POPUP); - textPacket.setNeedsTranslation(true); - textPacket.setXuid(""); - textPacket.setPlatformChatId(""); - textPacket.setSourceName(null); - textPacket.setMessage("record.nowPlaying"); - List params = new ArrayList<>(); - String recordString = "%item." + soundEvent.name().toLowerCase(Locale.ROOT) + ".desc"; - params.add(LocaleUtils.getLocaleString(recordString, session.getLocale())); - textPacket.setParameters(params); - session.sendUpstreamPacket(textPacket); - } - return; - } - - if (packet.getEffect() instanceof SoundEffect) { - SoundEffect soundEffect = (SoundEffect) packet.getEffect(); - Effect geyserEffect = EffectRegistry.SOUND_EFFECTS.get(soundEffect); - if (geyserEffect != null) { - geyserEffect.handleEffectPacket(session, packet); - return; - } - GeyserConnector.getInstance().getLogger().debug("Unhandled sound effect: " + soundEffect.name()); - } else if (packet.getEffect() instanceof ParticleEffect) { + LevelEventPacket effect = new LevelEventPacket(); + // Some things here are particles, others are not + if (packet.getEffect() instanceof ParticleEffect) { ParticleEffect particleEffect = (ParticleEffect) packet.getEffect(); - Vector3f pos = Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ()).add(0.5f, 0.5f, 0.5f); + Effect geyserEffect = EffectRegistry.EFFECTS.get(particleEffect.name()); + if (geyserEffect != null) { + String name = geyserEffect.getBedrockName(); + effect.setType(LevelEventType.valueOf(name)); + } else { + switch (particleEffect) { + // TODO: BREAK_SPLASH_POTION has additional data + case BONEMEAL_GROW: + effect.setType(LevelEventType.BONEMEAL); + BonemealGrowEffectData growEffectData = (BonemealGrowEffectData) packet.getData(); + effect.setData(growEffectData.getParticleCount()); + break; + //TODO: Block break particles when under fire + case BREAK_BLOCK: + effect.setType(LevelEventType.DESTROY); + BreakBlockEffectData breakBlockEffectData = (BreakBlockEffectData) packet.getData(); + effect.setData(BlockTranslator.getBedrockBlockId(breakBlockEffectData.getBlockState())); + break; + case EXPLOSION: + effect.setType(LevelEventType.PARTICLE_LARGE_EXPLOSION); + break; + case MOB_SPAWN: + effect.setType(LevelEventType.ENTITY_SPAWN); + break; + // Done with a dispenser + case SMOKE: + // Might need to be SHOOT + effect.setType(LevelEventType.PARTICLE_SMOKE); + break; + case COMPOSTER: + effect.setType(LevelEventType.BONEMEAL); - LevelEventPacket effectPacket = new LevelEventPacket(); - effectPacket.setPosition(pos); - effectPacket.setData(0); - switch (particleEffect) { - case COMPOSTER: { - effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); + ComposterEffectData composterEffectData = (ComposterEffectData) packet.getData(); + LevelSoundEventPacket soundEvent = new LevelSoundEventPacket(); + soundEvent.setSound(SoundEvent.valueOf("COMPOSTER_" + composterEffectData.name())); + soundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + soundEvent.setIdentifier(":"); + soundEvent.setExtraData(-1); + soundEvent.setBabySound(false); + soundEvent.setRelativeVolumeDisabled(false); + session.sendUpstreamPacket(soundEvent); + break; + case BLOCK_LAVA_EXTINGUISH: + effect.setType(LevelEventType.SHOOT); + effect.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY() + 1, packet.getPosition().getZ())); + session.sendUpstreamPacket(effect); - ComposterEffectData composterEffectData = (ComposterEffectData) packet.getData(); - LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - switch (composterEffectData) { - case FILL: - soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL); - break; - case FILL_SUCCESS: - soundEventPacket.setSound(SoundEvent.COMPOSTER_FILL_LAYER); - break; - } - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); - soundEventPacket.setExtraData(-1); - soundEventPacket.setBabySound(false); - soundEventPacket.setRelativeVolumeDisabled(false); - session.sendUpstreamPacket(soundEventPacket); - break; - } - 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); - break; - } - 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); - break; - } - 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); - break; - } - case SMOKE: { - effectPacket.setType(LevelEventType.PARTICLE_SHOOT); - - SmokeEffectData smokeEffectData = (SmokeEffectData) packet.getData(); - int data = 0; - switch (smokeEffectData) { - case DOWN: - data = 4; - pos = pos.add(0, -0.9f, 0); - break; - case UP: - data = 4; - pos = pos.add(0, 0.5f, 0); - break; - case NORTH: - data = 1; - pos = pos.add(0, -0.2f, -0.7f); - break; - case SOUTH: - data = 7; - pos = pos.add(0, -0.2f, 0.7f); - break; - case WEST: - data = 3; - pos = pos.add(-0.7f, -0.2f, 0); - break; - case EAST: - data = 5; - pos = pos.add(0.7f, -0.2f, 0); - break; - - } - effectPacket.setPosition(pos); - effectPacket.setData(data); - break; - } - //TODO: Block break particles when under fire - case BREAK_BLOCK: { - effectPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); - - BreakBlockEffectData breakBlockEffectData = (BreakBlockEffectData) packet.getData(); - effectPacket.setData(BlockTranslator.getBedrockBlockId(breakBlockEffectData.getBlockState())); - break; - } - case BREAK_SPLASH_POTION: { - effectPacket.setType(LevelEventType.PARTICLE_POTION_SPLASH); - effectPacket.setPosition(pos.add(0, -0.5f, 0)); - - BreakPotionEffectData splashPotionData = (BreakPotionEffectData) 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); - break; - } - case BREAK_EYE_OF_ENDER: { - effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); - break; - } - 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 - break; - } - case BONEMEAL_GROW: { - effectPacket.setType(LevelEventType.PARTICLE_CROP_GROWTH); - - BonemealGrowEffectData growEffectData = (BonemealGrowEffectData) packet.getData(); - effectPacket.setData(growEffectData.getParticleCount()); - break; - } - case ENDERDRAGON_FIREBALL_EXPLODE: { - effectPacket.setType(LevelEventType.PARTICLE_EYE_OF_ENDER_DEATH); // TODO - - DragonFireballEffectData fireballEffectData = (DragonFireballEffectData) packet.getData(); - if (fireballEffectData == DragonFireballEffectData.HAS_SOUND) { LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); - soundEventPacket.setSound(SoundEvent.EXPLODE); - soundEventPacket.setPosition(pos); - soundEventPacket.setIdentifier(""); + soundEventPacket.setSound(SoundEvent.EXTINGUISH_FIRE); + soundEventPacket.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + soundEventPacket.setIdentifier(":"); soundEventPacket.setExtraData(-1); soundEventPacket.setBabySound(false); soundEventPacket.setRelativeVolumeDisabled(false); session.sendUpstreamPacket(soundEventPacket); - } - break; - } - case EXPLOSION: { - effectPacket.setType(LevelEventType.PARTICLE_GENERIC_SPAWN); - effectPacket.setData(61); - break; - } - case EVAPORATE: { - effectPacket.setType(LevelEventType.PARTICLE_EVAPORATE_WATER); - effectPacket.setPosition(pos.add(-0.5f, 0.5f, -0.5f)); - break; - } - 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); - break; - } - default: { - GeyserConnector.getInstance().getLogger().debug("Unhandled particle effect: " + particleEffect.name()); - return; + return; + default: + GeyserConnector.getInstance().getLogger().debug("No effect handling for particle effect: " + packet.getEffect()); } } - session.sendUpstreamPacket(effectPacket); + effect.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + session.sendUpstreamPacket(effect); + } else if (packet.getEffect() instanceof SoundEffect) { + SoundEffect soundEffect = (SoundEffect) packet.getEffect(); + Effect geyserEffect = EffectRegistry.EFFECTS.get(soundEffect.name()); + if (geyserEffect != null) { + // Some events are LevelEventTypes, some are SoundEvents. + if (geyserEffect.getType().equals("soundLevel")) { + effect.setType(LevelEventType.valueOf(geyserEffect.getBedrockName())); + } else if (geyserEffect.getType().equals("soundEvent")) { + LevelSoundEventPacket soundEvent = new LevelSoundEventPacket(); + // Separate case since each RecordEffectData in Java is an individual track in Bedrock + if (geyserEffect.getJavaName().equals("RECORD")) { + RecordEffectData recordEffectData = (RecordEffectData) packet.getData(); + soundEvent.setSound(EffectRegistry.RECORDS.get(recordEffectData.getRecordId())); + if (EffectRegistry.RECORDS.get(recordEffectData.getRecordId()) != SoundEvent.STOP_RECORD) { + // Send text packet as it seems to be handled in Java Edition client-side. + TextPacket textPacket = new TextPacket(); + textPacket.setType(TextPacket.Type.JUKEBOX_POPUP); + textPacket.setNeedsTranslation(true); + textPacket.setXuid(""); + textPacket.setPlatformChatId(""); + textPacket.setSourceName(null); + textPacket.setMessage("record.nowPlaying"); + List params = new ArrayList<>(); + String recordString = "%item." + EffectRegistry.RECORDS.get(recordEffectData.getRecordId()).name().toLowerCase() + ".desc"; + params.add(LocaleUtils.getLocaleString(recordString, session.getClientData().getLanguageCode())); + textPacket.setParameters(params); + session.sendUpstreamPacket(textPacket); + } + } else { + soundEvent.setSound(SoundEvent.valueOf(geyserEffect.getBedrockName())); + } + soundEvent.setExtraData(geyserEffect.getData()); + soundEvent.setIdentifier(geyserEffect.getIdentifier()); + soundEvent.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + session.sendUpstreamPacket(soundEvent); + } + } else { + GeyserConnector.getInstance().getLogger().debug("No effect handling for sound effect: " + packet.getEffect()); + } } + if (effect.getType() != null) { + effect.setPosition(Vector3f.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); + session.sendUpstreamPacket(effect); + } + } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlaySoundTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java similarity index 59% rename from connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlaySoundTranslator.java rename to connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java index 238e9ba3..c99de3e3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlaySoundTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaPlayerPlaySoundTranslator.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.java.world; @@ -36,14 +37,14 @@ import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.sound.SoundRegistry; @Translator(packet = ServerPlaySoundPacket.class) -public class JavaPlaySoundTranslator extends PacketTranslator { +public class JavaPlayerPlaySoundTranslator extends PacketTranslator { @Override public void translate(ServerPlaySoundPacket packet, GeyserSession session) { String packetSound; - if (packet.getSound() instanceof BuiltinSound) { + if(packet.getSound() instanceof BuiltinSound) { packetSound = ((BuiltinSound) packet.getSound()).getName(); - } else if (packet.getSound() instanceof CustomSound) { + } else if(packet.getSound() instanceof CustomSound) { packetSound = ((CustomSound) packet.getSound()).getName(); } else { session.getConnector().getLogger().debug("Unknown sound packet, we were unable to map this. " + packet.toString()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java index 82e113ce..63512047 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaSpawnParticleTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.java.world; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.mc.protocol.data.game.world.particle.*; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.data.LevelEventType; import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; import com.nukkitx.protocol.bedrock.packet.SpawnParticleEffectPacket; @@ -40,7 +40,6 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerSpawnParticlePacket; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.network.translators.effect.EffectRegistry; -import org.geysermc.connector.utils.DimensionUtils; @Translator(packet = ServerSpawnParticlePacket.class) public class JavaSpawnParticleTranslator extends PacketTranslator { @@ -50,7 +49,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator { @@ -42,7 +41,6 @@ public class JavaSpawnPositionTranslator extends PacketTranslator { - - @Override - public void translate(ServerTradeListPacket packet, GeyserSession session) { - Entity villager = session.getPlayerEntity(); - session.setVillagerTrades(packet.getTrades()); - villager.getMetadata().put(EntityData.TRADE_TIER, packet.getVillagerLevel() - 1); - villager.getMetadata().put(EntityData.MAX_TRADE_TIER, 4); - villager.getMetadata().put(EntityData.TRADE_XP, packet.getExperience()); - villager.updateBedrockMetadata(session); - - UpdateTradePacket updateTradePacket = new UpdateTradePacket(); - updateTradePacket.setTradeTier(packet.getVillagerLevel() - 1); - updateTradePacket.setContainerId((short) packet.getWindowId()); - updateTradePacket.setContainerType(ContainerType.TRADE); - Inventory openInv = session.getInventoryCache().getOpenInventory(); - String displayName; - if (openInv != null && openInv.getId() == packet.getWindowId()) { - displayName = openInv.getTitle(); - } else { - Entity realVillager = session.getEntityCache().getEntityByGeyserId(session.getLastInteractedVillagerEid()); - if (realVillager != null && realVillager.getMetadata().containsKey(EntityData.NAMETAG) && realVillager.getMetadata().getString(EntityData.NAMETAG) != null) { - displayName = realVillager.getMetadata().getString(EntityData.NAMETAG); - } else { - displayName = realVillager != null && - realVillager.getEntityType() == EntityType.WANDERING_TRADER ? "Wandering Trader" : "Villager"; - } - } - updateTradePacket.setDisplayName(displayName); - updateTradePacket.setSize(0); - updateTradePacket.setNewTradingUi(true); - updateTradePacket.setUsingEconomyTrade(true); - updateTradePacket.setPlayerUniqueEntityId(session.getPlayerEntity().getGeyserId()); - updateTradePacket.setTraderUniqueEntityId(session.getPlayerEntity().getGeyserId()); - NbtMapBuilder builder = NbtMap.builder(); - List tags = new ArrayList<>(); - for (VillagerTrade trade : packet.getTrades()) { - NbtMapBuilder recipe = NbtMap.builder(); - recipe.putInt("maxUses", trade.getMaxUses()); - recipe.putInt("traderExp", trade.getXp()); - recipe.putFloat("priceMultiplierA", trade.getPriceMultiplier()); - recipe.put("sell", getItemTag(session, trade.getOutput(), 0)); - recipe.putFloat("priceMultiplierB", 0.0f); - recipe.putInt("buyCountB", trade.getSecondInput() != null ? trade.getSecondInput().getAmount() : 0); - recipe.putInt("buyCountA", trade.getFirstInput().getAmount()); - recipe.putInt("demand", trade.getDemand()); - recipe.putInt("tier", packet.getVillagerLevel() > 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.putInt("uses", trade.getNumUses()); - recipe.putByte("rewardExp", (byte) 1); - tags.add(recipe.build()); - } - - //Hidden trade to fix visual experience bug - if (packet.isRegularVillager() && packet.getVillagerLevel() < 5) { - tags.add(NbtMap.builder() - .putInt("maxUses", 0) - .putInt("traderExp", 0) - .putFloat("priceMultiplierA", 0.0f) - .putFloat("priceMultiplierB", 0.0f) - .putInt("buyCountB", 0) - .putInt("buyCountA", 0) - .putInt("demand", 0) - .putInt("tier", 5) - .putInt("uses", 0) - .putByte("rewardExp", (byte) 0) - .build()); - } - - builder.putList("Recipes", NbtType.COMPOUND, tags); - List expTags = new ArrayList<>(); - expTags.add(NbtMap.builder().putInt("0", 0).build()); - expTags.add(NbtMap.builder().putInt("1", 10).build()); - expTags.add(NbtMap.builder().putInt("2", 70).build()); - expTags.add(NbtMap.builder().putInt("3", 150).build()); - expTags.add(NbtMap.builder().putInt("4", 250).build()); - builder.putList("TierExpRequirements", NbtType.COMPOUND, expTags); - updateTradePacket.setOffers(builder.build()); - session.sendUpstreamPacket(updateTradePacket); - } - - private NbtMap getItemTag(GeyserSession session, ItemStack stack, int specialPrice) { - ItemData itemData = ItemTranslator.translateToBedrock(session, stack); - ItemEntry itemEntry = ItemRegistry.getItem(stack); - NbtMapBuilder builder = NbtMap.builder(); - builder.putByte("Count", (byte) (Math.max(itemData.getCount() + specialPrice, 1))); - builder.putShort("Damage", itemData.getDamage()); - builder.putString("Name", itemEntry.getBedrockIdentifier()); - if (itemData.getTag() != null) { - NbtMap tag = itemData.getTag().toBuilder().build(); - builder.put("tag", tag); - } - return builder.build(); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java index b768a207..d54d8b6a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUnloadChunkTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,29 +25,18 @@ package org.geysermc.connector.network.translators.java.world; -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUnloadChunkPacket; -import com.nukkitx.math.vector.Vector3i; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.world.chunk.ChunkPosition; -import java.util.Iterator; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUnloadChunkPacket; @Translator(packet = ServerUnloadChunkPacket.class) public class JavaUnloadChunkTranslator extends PacketTranslator { @Override public void translate(ServerUnloadChunkPacket packet, GeyserSession session) { - session.getChunkCache().removeChunk(packet.getX(), packet.getZ()); - - //Checks if a skull is in an unloaded chunk then removes it - Iterator iterator = session.getSkullCache().keySet().iterator(); - while (iterator.hasNext()) { - Vector3i position = iterator.next(); - if (Math.floor(position.getX() / 16) == packet.getX() && Math.floor(position.getZ() / 16) == packet.getZ()) { - session.getSkullCache().get(position).despawnEntity(session); - iterator.remove(); - } - } + session.getChunkCache().removeChunk(new ChunkPosition(packet.getX(), packet.getZ())); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTileEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTileEntityTranslator.java index 014d2d73..362d67d0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTileEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTileEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,60 +25,29 @@ package org.geysermc.connector.network.translators.java.world; -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.world.block.UpdatedTileType; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTileEntityPacket; -import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerType; -import com.nukkitx.protocol.bedrock.packet.ContainerOpenPacket; -import org.geysermc.connector.GeyserConnector; + import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; -import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator; import org.geysermc.connector.utils.BlockEntityUtils; import org.geysermc.connector.utils.ChunkUtils; @Translator(packet = ServerUpdateTileEntityPacket.class) public class JavaUpdateTileEntityTranslator extends PacketTranslator { - private final boolean cacheChunks; - - public JavaUpdateTileEntityTranslator() { - cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks(); - } @Override public void translate(ServerUpdateTileEntityPacket packet, GeyserSession session) { String id = BlockEntityUtils.getBedrockBlockEntityId(packet.getType().name()); - if (packet.getNbt().isEmpty()) { // Fixes errors in CubeCraft sending empty NBT - BlockEntityUtils.updateBlockEntity(session, null, packet.getPosition()); - return; - } - BlockEntityTranslator translator = BlockEntityUtils.getBlockEntityTranslator(id); - // The Java block state is used in BlockEntityTranslator.translateTag() to make up for some inconsistencies - // between Java block states and Bedrock block entity data - int blockState = cacheChunks ? - // Cache chunks is enabled; use chunk cache - session.getConnector().getWorldManager().getBlockAt(session, packet.getPosition()) : - // Cache chunks is not enabled; use block entity cache - ChunkUtils.CACHED_BLOCK_ENTITIES.removeInt(packet.getPosition()); - BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), blockState), packet.getPosition()); - // Check for custom skulls. - if (SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS && packet.getNbt().contains("SkullOwner")) { - SkullBlockEntityTranslator.spawnPlayer(session, packet.getNbt(), blockState); - } - - // If block entity is command block, OP permission level is appropriate, player is in creative mode and the NBT is not empty - if (packet.getType() == UpdatedTileType.COMMAND_BLOCK && session.getOpPermissionLevel() >= 2 && - session.getGameMode() == GameMode.CREATIVE && packet.getNbt().size() > 5) { - ContainerOpenPacket openPacket = new ContainerOpenPacket(); - openPacket.setBlockPosition(Vector3i.from(packet.getPosition().getX(), packet.getPosition().getY(), packet.getPosition().getZ())); - openPacket.setId((byte) 1); - openPacket.setType(ContainerType.COMMAND_BLOCK); - openPacket.setUniqueEntityId(-1); - session.sendUpstreamPacket(openPacket); + // If not null then the BlockState is used in BlockEntityTranslator.translateTag() + if (ChunkUtils.CACHED_BLOCK_ENTITIES.get(packet.getPosition()) != null) { + BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), + ChunkUtils.CACHED_BLOCK_ENTITIES.get(packet.getPosition())), packet.getPosition()); + ChunkUtils.CACHED_BLOCK_ENTITIES.remove(packet.getPosition()); + } else { + BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), null), packet.getPosition()); } } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java index 461d8139..188e960d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateTimeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,31 +25,51 @@ package org.geysermc.connector.network.translators.java.world; -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; -import com.nukkitx.protocol.bedrock.packet.SetTimePacket; +import com.nukkitx.protocol.bedrock.data.GameRuleData; +import com.nukkitx.protocol.bedrock.packet.GameRulesChangedPacket; +import it.unimi.dsi.fastutil.longs.Long2LongMap; +import it.unimi.dsi.fastutil.longs.Long2LongOpenHashMap; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateTimePacket; +import com.nukkitx.protocol.bedrock.packet.SetTimePacket; + @Translator(packet = ServerUpdateTimePacket.class) public class JavaUpdateTimeTranslator extends PacketTranslator { + // If negative, the last time is stored so we know it's not some plugin behavior doing weird things. + // Per-player for multi-world support + private static final Long2LongMap LAST_RECORDED_TIMES = new Long2LongOpenHashMap(); + @Override public void translate(ServerUpdateTimePacket packet, GeyserSession session) { + // Bedrock sends a GameRulesChangedPacket if there is no daylight cycle // Java just sends a negative long if there is no daylight cycle + long lastTime = LAST_RECORDED_TIMES.getOrDefault(session.getPlayerEntity().getEntityId(), 0); long time = packet.getTime(); - // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day - SetTimePacket setTimePacket = new SetTimePacket(); - setTimePacket.setTime((int) Math.abs(time) % 24000); - session.sendUpstreamPacket(setTimePacket); - if (!session.isDaylightCycle() && time >= 0) { - // Client thinks there is no daylight cycle but there is - session.setDaylightCycle(true); - } else if (session.isDaylightCycle() && time < 0) { - // Client thinks there is daylight cycle but there isn't - session.setDaylightCycle(false); + if (lastTime != time) { + // https://minecraft.gamepedia.com/Day-night_cycle#24-hour_Minecraft_day + SetTimePacket setTimePacket = new SetTimePacket(); + setTimePacket.setTime((int) Math.abs(time) % 24000); + session.sendUpstreamPacket(setTimePacket); + // TODO: Performance efficient to always do this? + LAST_RECORDED_TIMES.put(session.getPlayerEntity().getEntityId(), time); + } + if (lastTime < 0 && time >= 0) { + setDoDaylightCycleGamerule(session, true); + } else if (lastTime != time && time < 0) { + setDoDaylightCycleGamerule(session, false); } } + + private void setDoDaylightCycleGamerule(GeyserSession session, boolean doCycle) { + GameRulesChangedPacket gameRulesChangedPacket = new GameRulesChangedPacket(); + gameRulesChangedPacket.getGameRules().add(new GameRuleData<>("dodaylightcycle", doCycle)); + session.sendUpstreamPacket(gameRulesChangedPacket); + } + } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java index 23dc2dbc..823ce199 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewDistanceTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java index cb15022d..63ade153 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaUpdateViewPositionTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java index 4ae0d7c6..1bcd9919 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaVehicleMoveTranslator.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.java.world; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaWorldBorderTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaWorldBorderTranslator.java new file mode 100644 index 00000000..a58650eb --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaWorldBorderTranslator.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.java.world; + +import com.github.steveice10.mc.protocol.data.game.world.WorldBorderAction; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerWorldBorderPacket; +import com.nukkitx.math.vector.Vector2f; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.network.translators.Translator; +import org.geysermc.connector.network.translators.world.WorldBorder; + +@Translator(packet = ServerWorldBorderPacket.class) +public class JavaWorldBorderTranslator extends PacketTranslator { + + @Override + public void translate(ServerWorldBorderPacket packet, GeyserSession session) { + WorldBorder worldBorder = session.getWorldBorder(); + + if(packet.getAction() != WorldBorderAction.INITIALIZE && worldBorder == null) { + if (session.getWorldBorder().getWorldBorderTask() != null) { + session.getWorldBorder().getWorldBorderTask().cancel(false); + } + return; + } + + switch(packet.getAction()) { + case INITIALIZE: + worldBorder = new WorldBorder(Vector2f.from(packet.getNewCenterX(), packet.getNewCenterZ()), packet.getOldSize(), packet.getNewSize(), + packet.getLerpTime(), packet.getWarningTime(), packet.getWarningTime()); + + session.setWorldBorder(worldBorder); + break; + case SET_SIZE: + worldBorder.setOldRadius(packet.getNewSize()); + worldBorder.setNewRadius(packet.getNewSize()); + break; + case LERP_SIZE: + worldBorder.setOldRadius(packet.getOldSize()); + worldBorder.setNewRadius(packet.getNewSize()); + worldBorder.setSpeed(packet.getLerpTime()); + break; + case SET_CENTER: + worldBorder.setCenter(Vector2f.from(packet.getNewCenterX(), packet.getNewCenterZ())); + break; + case SET_WARNING_TIME: + worldBorder.setWarningTime(packet.getWarningTime()); + return; + case SET_WARNING_BLOCKS: + worldBorder.setWarningBlocks(packet.getWarningBlocks()); + return; + } + + worldBorder.update(session); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java index 5ef00449..5a03b218 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/EntitySoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/EntitySoundInteractionHandler.java index 484936e5..138791b1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/EntitySoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/EntitySoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandler.java index 4af1b820..52a76aa3 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java index 6cfb9767..260efb41 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java @@ -1,32 +1,31 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.utils.FileUtils; import org.reflections.Reflections; import java.util.HashMap; @@ -40,7 +39,7 @@ public class SoundHandlerRegistry { static final Map> INTERACTION_HANDLERS = new HashMap<>(); static { - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.sound") : new Reflections("org.geysermc.connector.network.translators.sound"); + Reflections ref = new Reflections("org.geysermc.connector.network.translators.sound"); for (Class clazz : ref.getTypesAnnotatedWith(SoundHandler.class)) { try { SoundInteractionHandler interactionHandler = (SoundInteractionHandler) clazz.newInstance(); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundInteractionHandler.java index 8f25b8e8..e68061ef 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java index 8ebca00e..01b03476 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java index bad9b41d..367f9beb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; @@ -38,7 +39,6 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl @Override public void handleInteraction(GeyserSession session, Vector3f position, String identifier) { - if (session.getBucketScheduledFuture() == null) return; // No bucket was really interacted with String handItemIdentifier = ItemRegistry.getItem(session.getInventory().getItemInHand()).getJavaIdentifier(); LevelSoundEventPacket soundEventPacket = new LevelSoundEventPacket(); soundEventPacket.setPosition(position); @@ -69,6 +69,5 @@ public class BucketSoundInteractionHandler implements BlockSoundInteractionHandl soundEventPacket.setSound(soundEvent); session.sendUpstreamPacket(soundEventPacket); } - session.setBucketScheduledFuture(null); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/ComparatorSoundInteractHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/ComparatorSoundInteractHandler.java index ba436374..4b74a678 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/ComparatorSoundInteractHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/ComparatorSoundInteractHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; @@ -40,7 +41,7 @@ public class ComparatorSoundInteractHandler implements BlockSoundInteractionHand boolean powered = identifier.contains("mode=compare"); LevelEventPacket levelEventPacket = new LevelEventPacket(); levelEventPacket.setPosition(position); - levelEventPacket.setType(LevelEventType.SOUND_CLICK); //TODO: New ID? + levelEventPacket.setType(LevelEventType.REDSTONE_TRIGGER); levelEventPacket.setData(powered ? 500 : 550); session.sendUpstreamPacket(levelEventPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/DoorSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/DoorSoundInteractionHandler.java index 8c6c62f0..39a07c3a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/DoorSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/DoorSoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; @@ -37,9 +38,8 @@ public class DoorSoundInteractionHandler implements BlockSoundInteractionHandler @Override public void handleInteraction(GeyserSession session, Vector3f position, String identifier) { - if (identifier.contains("iron")) return; LevelEventPacket levelEventPacket = new LevelEventPacket(); - levelEventPacket.setType(LevelEventType.SOUND_DOOR_OPEN); + levelEventPacket.setType(LevelEventType.SOUND_DOOR); levelEventPacket.setPosition(position); levelEventPacket.setData(0); session.sendUpstreamPacket(levelEventPacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/FlintAndSteelInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/FlintAndSteelInteractionHandler.java index 794b8708..290aa7bd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/FlintAndSteelInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/FlintAndSteelInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/GrassPathInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/GrassPathInteractionHandler.java index 328dbfbf..e5445e9d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/GrassPathInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/GrassPathInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/HoeInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/HoeInteractionHandler.java index 30fe94b5..17d346ae 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/HoeInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/HoeInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/LeverSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/LeverSoundInteractionHandler.java index 83fe79f2..fb39d4ac 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/LeverSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/LeverSoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.block; @@ -40,7 +41,7 @@ public class LeverSoundInteractionHandler implements BlockSoundInteractionHandle boolean powered = identifier.contains("powered=true"); LevelEventPacket levelEventPacket = new LevelEventPacket(); levelEventPacket.setPosition(position); - levelEventPacket.setType(LevelEventType.SOUND_CLICK); + levelEventPacket.setType(LevelEventType.REDSTONE_TRIGGER); levelEventPacket.setData(powered ? 600 : 500); session.sendUpstreamPacket(levelEventPacket); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java index e2dcf29a..d33d68af 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.sound.entity; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/CachedChunkManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/CachedChunkManager.java new file mode 100644 index 00000000..740e2df9 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/CachedChunkManager.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.world; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import org.geysermc.connector.network.session.GeyserSession; + +public class CachedChunkManager extends WorldManager { + + @Override + public BlockState getBlockAt(GeyserSession session, int x, int y, int z) { + return session.getChunkCache().getBlockAt(new Position(x, y, z)); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java deleted file mode 100644 index 5507b778..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java +++ /dev/null @@ -1,131 +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.connector.network.translators.world; - -import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; -import com.github.steveice10.mc.protocol.data.game.chunk.Column; -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.client.ClientChatPacket; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.cache.ChunkCache; -import org.geysermc.connector.utils.GameRule; - -public class GeyserWorldManager extends WorldManager { - - private static final Object2ObjectMap gameruleCache = new Object2ObjectOpenHashMap<>(); - - @Override - public int getBlockAt(GeyserSession session, int x, int y, int z) { - ChunkCache chunkCache = session.getChunkCache(); - if (chunkCache != null) { // Chunk cache can be null if the session is closed asynchronously - return chunkCache.getBlockAt(x, y, z); - } - return 0; - } - - @Override - public void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk chunk) { - ChunkCache chunkCache = session.getChunkCache(); - Column cachedColumn; - Chunk cachedChunk; - if (chunkCache == null || (cachedColumn = chunkCache.getChunk(x, z)) == null || (cachedChunk = cachedColumn.getChunks()[y]) == null) { - return; - } - - // Copy state IDs from cached chunk to output chunk - for (int blockY = 0; blockY < 16; blockY++) { // Cache-friendly iteration order - for (int blockZ = 0; blockZ < 16; blockZ++) { - for (int blockX = 0; blockX < 16; blockX++) { - chunk.set(blockX, blockY, blockZ, cachedChunk.get(blockX, blockY, blockZ)); - } - } - } - } - - @Override - public boolean hasMoreBlockDataThanChunkCache() { - // This implementation can only fetch data from the session chunk cache - return false; - } - - @Override - public int[] getBiomeDataAt(GeyserSession session, int x, int z) { - if (session.getConnector().getConfig().isCacheChunks()) { - ChunkCache chunkCache = session.getChunkCache(); - if (chunkCache != null) { // Chunk cache can be null if the session is closed asynchronously - Column column = chunkCache.getChunk(x, z); - if (column != null) { // Column can be null if the server sent a partial chunk update before the first ground-up-continuous one - return column.getBiomeData(); - } - } - } - return new int[1024]; - } - - @Override - public void setGameRule(GeyserSession session, String name, Object value) { - session.sendDownstreamPacket(new ClientChatPacket("/gamerule " + name + " " + value)); - gameruleCache.put(name, String.valueOf(value)); - } - - @Override - public Boolean getGameRuleBool(GeyserSession session, GameRule gameRule) { - String value = gameruleCache.get(gameRule.getJavaID()); - if (value != null) { - return Boolean.parseBoolean(value); - } - - return gameRule.getDefaultValue() != null ? (Boolean) gameRule.getDefaultValue() : false; - } - - @Override - public int getGameRuleInt(GeyserSession session, GameRule gameRule) { - String value = gameruleCache.get(gameRule.getJavaID()); - if (value != null) { - return Integer.parseInt(value); - } - - return gameRule.getDefaultValue() != null ? (int) gameRule.getDefaultValue() : 0; - } - - @Override - public void setPlayerGameMode(GeyserSession session, GameMode gameMode) { - session.sendDownstreamPacket(new ClientChatPacket("/gamemode " + gameMode.name().toLowerCase())); - } - - @Override - public void setDifficulty(GeyserSession session, Difficulty difficulty) { - session.sendDownstreamPacket(new ClientChatPacket("/difficulty " + difficulty.name().toLowerCase())); - } - - @Override - public boolean hasPermission(GeyserSession session, String permission) { - return false; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldBorder.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldBorder.java new file mode 100644 index 00000000..a06dd0fd --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldBorder.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.world; + +import com.nukkitx.math.vector.Vector2f; +import com.nukkitx.math.vector.Vector3f; +import lombok.Getter; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import org.geysermc.common.ChatColor; +import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +@Getter +@Setter +@RequiredArgsConstructor +public class WorldBorder { + private @NonNull Vector2f center; + private @NonNull double oldRadius; + private @NonNull double newRadius; + private @NonNull long speed; + private @NonNull int warningTime; + private @NonNull int warningBlocks; + + // Runs the onTick method + private ScheduledFuture worldBorderTask; + + private double minX; + private double minZ; + private double maxX; + private double maxZ; + + public void onTick(GeyserSession session) { + PlayerEntity player = session.getPlayerEntity(); + if(isNearEdge(player)) { + session.sendActionBar(ChatColor.BOLD + "" + ChatColor.RED + "You are near the world border (" + (int) getDistanceToEdge(player) + " blocks)"); + } + } + + /** + * Updates the min and max positions of the world border. + * This should be called every time there is a modification to either the center coordinates or the radius. + */ + public void update(GeyserSession session) { + this.minX = Math.max(center.getX() - newRadius / 2.0D, -newRadius); + this.minZ = Math.max(center.getY() - newRadius / 2.0D, -newRadius); + this.maxX = Math.min(center.getX() + newRadius / 2.0D, newRadius); + this.maxZ = Math.min(center.getY() + newRadius / 2.0D, newRadius); + if (worldBorderTask != null) { + worldBorderTask.cancel(false); + } + + // If world border is at that number then it's 'disabled', no need to run tasks for it + // https://minecraft.gamepedia.com/World_border#Commands + if (!(newRadius >= 59999967)) { + worldBorderTask = session.getConnector().getGeneralThreadPool().scheduleAtFixedRate(() -> + onTick(session), 1, 50, TimeUnit.MILLISECONDS + ); + } + } + + /** + * Checks if an entity is within the warning distance to the edge of the world border. + * https://wiki.vg/Protocol#World_Border + */ + public boolean isNearEdge(Entity entity) { + double distance = Math.max(Math.min(speed * 1000 * warningTime, Math.abs(newRadius - oldRadius)), warningBlocks); + + float entityDistance = (float) getDistanceToEdge(entity); + + return (double) entityDistance < distance; + } + + /** + * Checks if an entity is inside the world border. + * + * This method needs to be improved as it doesn't account for when the world border + * is currently changing size, it only accounts for the target size. + * + * Something similar to the method above should work. + */ + public boolean isInsideBorder(Entity entity) { + return entity.getPosition().getX() > minX && entity.getPosition().getX() < maxX && entity.getPosition().getZ() > minZ && entity.getPosition().getZ() < maxZ; + } + + /** + * Calculates how close the entity is to the edge of the world border. + */ + public double getDistanceToEdge(Entity entity) { + Vector3f pos = entity.getPosition(); + + double minPosZ = pos.getZ() - minZ; + double maxPosZ = maxZ - pos.getZ(); + double minPosX = pos.getX() - minX; + double maxPosX = maxX - pos.getX(); + + return Math.min(Math.min(Math.min(minPosX, maxPosX), minPosZ), maxPosZ); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java index d8b484f2..d92d8454 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/WorldManager.java @@ -1,37 +1,36 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world; -import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; 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.github.steveice10.mc.protocol.data.game.world.block.BlockState; + import com.nukkitx.math.vector.Vector3i; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.GameRule; /** * Class that manages or retrieves various information @@ -43,29 +42,29 @@ import org.geysermc.connector.utils.GameRule; public abstract class WorldManager { /** - * Gets the Java block state at the specified location + * Gets the {@link BlockState} 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) { + public BlockState getBlockAt(GeyserSession session, Position position) { return this.getBlockAt(session, position.getX(), position.getY(), position.getZ()); } /** - * Gets the Java block state at the specified location + * Gets the {@link BlockState} at the specified location * * @param session the session * @param vector the position * @return the block state at the specified location */ - public int getBlockAt(GeyserSession session, Vector3i vector) { + public BlockState getBlockAt(GeyserSession session, Vector3i vector) { return this.getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); } /** - * Gets the Java block state at the specified location + * Gets the {@link BlockState} at the specified location * * @param session the session * @param x the x coordinate to get the block at @@ -73,88 +72,5 @@ public abstract class WorldManager { * @param z the z coordinate to get the block at * @return the block state at the specified location */ - public abstract int getBlockAt(GeyserSession session, int x, int y, int z); - - /** - * Gets all block states in the specified chunk section. - * - * @param session the session - * @param x the chunk's X coordinate - * @param y the chunk's Y coordinate - * @param z the chunk's Z coordinate - * @param section the chunk section to store the block data in - */ - public abstract void getBlocksInSection(GeyserSession session, int x, int y, int z, Chunk section); - - /** - * Checks whether or not this world manager has access to more block data than the chunk cache. - *

- * Some world managers (e.g. Spigot) can provide access to block data outside of the chunk cache, and even with chunk caching disabled. This - * method provides a means to check if this manager has this capability. - * - * @return whether or not this world manager has access to more block data than the chunk cache - */ - public abstract boolean hasMoreBlockDataThanChunkCache(); - - /** - * Gets the Java biome data for the specified chunk. - * - * @param session the session of the player - * @param x the chunk's X coordinate - * @param z the chunk's Z coordinate - * @return the biome data for the specified region with a length of 1024. - */ - public abstract int[] getBiomeDataAt(GeyserSession session, int x, int z); - - /** - * Updates a gamerule value on the Java server - * - * @param session The session of the user that requested the change - * @param name The gamerule to change - * @param value The new value for the gamerule - */ - public abstract void setGameRule(GeyserSession session, String name, Object value); - - /** - * Gets a gamerule value as a boolean - * - * @param session The session of the user that requested the value - * @param gameRule The gamerule to fetch the value of - * @return The boolean representation of the value - */ - public abstract Boolean getGameRuleBool(GeyserSession session, GameRule gameRule); - - /** - * Get a gamerule value as an integer - * - * @param session The session of the user that requested the value - * @param gameRule The gamerule to fetch the value of - * @return The integer representation of the value - */ - public abstract int getGameRuleInt(GeyserSession session, GameRule gameRule); - - /** - * Change the game mode of the given session - * - * @param session The session of the player to change the game mode of - * @param gameMode The game mode to change the player to - */ - public abstract void setPlayerGameMode(GeyserSession session, GameMode gameMode); - - /** - * Change the difficulty of the Java server - * - * @param session The session of the user that requested the change - * @param difficulty The difficulty to change to - */ - public abstract void setDifficulty(GeyserSession session, Difficulty difficulty); - - /** - * Checks if the given session's player has a permission - * - * @param session The session of the player to check the permission of - * @param permission The permission node to check - * @return True if the player has the requested permission, false if not - */ - public abstract boolean hasPermission(GeyserSession session, String permission); + public abstract BlockState getBlockAt(GeyserSession session, int x, int y, int z); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java index 4ffb96d0..070a0592 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockStateValues.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,16 @@ package org.geysermc.connector.network.translators.world.block; import com.fasterxml.jackson.databind.JsonNode; -import com.nukkitx.nbt.NbtMap; -import it.unimi.dsi.fastutil.ints.*; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.nukkitx.nbt.tag.CompoundTag; +import it.unimi.dsi.fastutil.ints.Int2BooleanMap; +import it.unimi.dsi.fastutil.ints.Int2BooleanOpenHashMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ByteMap; +import it.unimi.dsi.fastutil.objects.Object2ByteOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import java.util.HashMap; import java.util.Map; @@ -36,27 +44,25 @@ import java.util.Map; * Used for block entities if the Java block state contains Bedrock block information. */ public class BlockStateValues { - private static final Int2IntMap BANNER_COLORS = new Int2IntOpenHashMap(); - private static final Int2ByteMap BED_COLORS = new Int2ByteOpenHashMap(); - private static final Int2ByteMap COMMAND_BLOCK_VALUES = new Int2ByteOpenHashMap(); + + private static final Object2IntMap BANNER_COLORS = new Object2IntOpenHashMap<>(); + private static final Object2ByteMap BED_COLORS = new Object2ByteOpenHashMap<>(); private static final Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); - private static final Map FLOWER_POT_BLOCKS = new HashMap<>(); - private static final Int2IntMap NOTEBLOCK_PITCHES = new Int2IntOpenHashMap(); + private static final Map FLOWER_POT_BLOCKS = new HashMap<>(); + private static final Object2IntMap NOTEBLOCK_PITCHES = new Object2IntOpenHashMap<>(); private static final Int2BooleanMap IS_STICKY_PISTON = new Int2BooleanOpenHashMap(); private static final Int2BooleanMap PISTON_VALUES = new Int2BooleanOpenHashMap(); - private static final Int2ByteMap SKULL_VARIANTS = new Int2ByteOpenHashMap(); - private static final Int2ByteMap SKULL_ROTATIONS = new Int2ByteOpenHashMap(); - private static final Int2IntMap SKULL_WALL_DIRECTIONS = new Int2IntOpenHashMap(); - private static final Int2ByteMap SHULKERBOX_DIRECTIONS = new Int2ByteOpenHashMap(); + private static final Object2ByteMap SKULL_VARIANTS = new Object2ByteOpenHashMap<>(); + private static final Object2ByteMap SKULL_ROTATIONS = new Object2ByteOpenHashMap<>(); + private static final Object2ByteMap SHULKERBOX_DIRECTIONS = new Object2ByteOpenHashMap<>(); /** * Determines if the block state contains Bedrock block information - * - * @param entry The String to JsonNode map used in BlockTranslator + * @param entry The String to JsonNode map used in BlockTranslator * @param javaBlockState the Java Block State of the block */ - public static void storeBlockStateValues(Map.Entry entry, int javaBlockState) { + public static void storeBlockStateValues(Map.Entry entry, BlockState javaBlockState) { JsonNode bannerColor = entry.getValue().get("banner_color"); if (bannerColor != null) { BANNER_COLORS.put(javaBlockState, (byte) bannerColor.intValue()); @@ -69,22 +75,17 @@ public class BlockStateValues { return; } - if (entry.getKey().contains("command_block")) { - COMMAND_BLOCK_VALUES.put(javaBlockState, entry.getKey().contains("conditional=true") ? (byte) 1 : (byte) 0); - return; - } - if (entry.getValue().get("double_chest_position") != null) { boolean isX = (entry.getValue().get("x") != null); boolean isDirectionPositive = ((entry.getValue().get("x") != null && entry.getValue().get("x").asBoolean()) || (entry.getValue().get("z") != null && entry.getValue().get("z").asBoolean())); boolean isLeft = (entry.getValue().get("double_chest_position").asText().contains("left")); - DOUBLE_CHEST_VALUES.put(javaBlockState, new DoubleChestValue(isX, isDirectionPositive, isLeft)); + DOUBLE_CHEST_VALUES.put(javaBlockState.getId(), new DoubleChestValue(isX, isDirectionPositive, isLeft)); return; } - if (entry.getKey().contains("potted_") || entry.getKey().contains("flower_pot")) { - FLOWER_POT_VALUES.put(javaBlockState, entry.getKey().replace("potted_", "")); + if (entry.getKey().contains("potted_")) { + FLOWER_POT_VALUES.put(javaBlockState.getId(), entry.getKey().replace("potted_", "")); return; } @@ -96,13 +97,13 @@ public class BlockStateValues { if (entry.getKey().contains("piston")) { // True if extended, false if not - PISTON_VALUES.put(javaBlockState, entry.getKey().contains("extended=true")); - IS_STICKY_PISTON.put(javaBlockState, entry.getKey().contains("sticky")); + PISTON_VALUES.put(javaBlockState.getId(), entry.getKey().contains("extended=true")); + IS_STICKY_PISTON.put(javaBlockState.getId(), entry.getKey().contains("sticky")); return; } JsonNode skullVariation = entry.getValue().get("variation"); - if (skullVariation != null) { + if(skullVariation != null) { SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue()); } @@ -111,26 +112,6 @@ public class BlockStateValues { SKULL_ROTATIONS.put(javaBlockState, (byte) skullRotation.intValue()); } - if (entry.getKey().contains("wall_skull") || entry.getKey().contains("wall_head")) { - String direction = entry.getKey().substring(entry.getKey().lastIndexOf("facing=") + 7); - int rotation = 0; - switch (direction.substring(0, direction.length() - 1)) { - case "north": - rotation = 180; - break; - case "south": - rotation = 0; - break; - case "west": - rotation = 90; - break; - case "east": - rotation = 270; - break; - } - SKULL_WALL_DIRECTIONS.put(javaBlockState, rotation); - } - JsonNode shulkerDirection = entry.getValue().get("shulker_direction"); if (shulkerDirection != null) { BlockStateValues.SHULKERBOX_DIRECTIONS.put(javaBlockState, (byte) shulkerDirection.intValue()); @@ -144,8 +125,11 @@ public class BlockStateValues { * @param state BlockState of the block * @return Banner color integer or -1 if no color */ - public static int getBannerColor(int state) { - return BANNER_COLORS.getOrDefault(state, -1); + public static int getBannerColor(BlockState state) { + if (BANNER_COLORS.containsKey(state)) { + return BANNER_COLORS.getInt(state); + } + return -1; } /** @@ -155,24 +139,16 @@ public class BlockStateValues { * @param state BlockState of the block * @return Bed color byte or -1 if no color */ - public static byte getBedColor(int state) { - return BED_COLORS.getOrDefault(state, (byte) -1); - } - - /** - * The block state in Java and Bedrock both contain the conditional bit, however command block block entity tags - * in Bedrock need the conditional information. - * - * @return the list of all command blocks and if they are conditional (1 or 0) - */ - public static Int2ByteMap getCommandBlockValues() { - return COMMAND_BLOCK_VALUES; + public static byte getBedColor(BlockState state) { + if (BED_COLORS.containsKey(state)) { + return BED_COLORS.getByte(state); + } + return -1; } /** * All double chest values are part of the block state in Java and part of the block entity tag in Bedrock. * This gives the DoubleChestValue that can be calculated into the final tag. - * * @return The map of all DoubleChestValues. */ public static Int2ObjectMap getDoubleChestValues() { @@ -181,7 +157,6 @@ public class BlockStateValues { /** * Get the Int2ObjectMap of flower pot block states to containing plant - * * @return Int2ObjectMap of flower pot values */ public static Int2ObjectMap getFlowerPotValues() { @@ -190,35 +165,35 @@ public class BlockStateValues { /** * Get the map of contained flower pot plants to Bedrock CompoundTag - * * @return Map of flower pot blocks. */ - public static Map getFlowerPotBlocks() { + public static Map getFlowerPotBlocks() { return FLOWER_POT_BLOCKS; } /** * The note that noteblocks output when hit is part of the block state in Java but sent as a BlockEventPacket in Bedrock. * This gives an integer pitch that Bedrock can use. - * * @param state BlockState of the block * @return note block note integer or -1 if not present */ - public static int getNoteblockPitch(int state) { - return NOTEBLOCK_PITCHES.getOrDefault(state, -1); + public static int getNoteblockPitch(BlockState state) { + if (NOTEBLOCK_PITCHES.containsKey(state)) { + return NOTEBLOCK_PITCHES.getInt(state); + } + return -1; } /** * Get the Int2BooleanMap showing if a piston block state is extended or not. - * * @return the Int2BooleanMap of piston extensions. */ public static Int2BooleanMap getPistonValues() { return PISTON_VALUES; } - public static boolean isStickyPiston(int blockState) { - return IS_STICKY_PISTON.get(blockState); + public static boolean isStickyPiston(BlockState blockState) { + return IS_STICKY_PISTON.get(blockState.getId()); } /** @@ -228,8 +203,11 @@ public class BlockStateValues { * @param state BlockState of the block * @return Skull variant byte or -1 if no variant */ - public static byte getSkullVariant(int state) { - return SKULL_VARIANTS.getOrDefault(state, (byte) -1); + public static byte getSkullVariant(BlockState state) { + if (SKULL_VARIANTS.containsKey(state)) { + return SKULL_VARIANTS.getByte(state); + } + return -1; } /** @@ -239,19 +217,13 @@ public class BlockStateValues { * @param state BlockState of the block * @return Skull rotation value or -1 if no value */ - public static byte getSkullRotation(int state) { - return SKULL_ROTATIONS.getOrDefault(state, (byte) -1); + public static byte getSkullRotation(BlockState state) { + if (SKULL_ROTATIONS.containsKey(state)) { + return SKULL_ROTATIONS.getByte(state); + } + return -1; } - /** - * Skull rotations are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. - * This gives a integer rotation that Bedrock can use. - * - * @return Skull wall rotation value with the blockstate - */ - public static Int2IntMap getSkullWallDirections() { - return SKULL_WALL_DIRECTIONS; - } /** * Shulker box directions are part of the namespaced ID in Java Edition, but part of the block entity tag in Bedrock. @@ -260,7 +232,10 @@ public class BlockStateValues { * @param state BlockState of the block * @return Shulker direction value or -1 if no value */ - public static byte getShulkerBoxDirection(int state) { - return SHULKERBOX_DIRECTIONS.getOrDefault(state, (byte) -1); + public static byte getShulkerBoxDirection(BlockState state) { + if (SHULKERBOX_DIRECTIONS.containsKey(state)) { + return SHULKERBOX_DIRECTIONS.getByte(state); + } + return -1; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java index b047999e..d6f446f0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/BlockTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,70 +26,46 @@ package org.geysermc.connector.network.translators.world.block; import com.fasterxml.jackson.databind.JsonNode; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import com.nukkitx.nbt.*; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.NbtUtils; +import com.nukkitx.nbt.stream.NBTInputStream; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.nbt.tag.ListTag; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.network.translators.world.block.entity.BlockEntity; import org.geysermc.connector.utils.FileUtils; import org.reflections.Reflections; -import java.io.DataInputStream; import java.io.InputStream; -import java.util.Iterator; -import java.util.Map; +import java.util.*; public class BlockTranslator { - /** - * The Java block runtime ID of air - */ - public static final int JAVA_AIR_ID = 0; - /** - * The Bedrock block runtime ID of air - */ - public static final int BEDROCK_AIR_ID; + public static final ListTag BLOCKS; + public static final BlockState AIR = new BlockState(0); public static final int BEDROCK_WATER_ID; private static final Int2IntMap JAVA_TO_BEDROCK_BLOCK_MAP = new Int2IntOpenHashMap(); - private static final Int2IntMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2IntOpenHashMap(); - /** - * Stores a list of differences in block identifiers. - * Items will not be added to this list if the key and value is the same. - */ - private static final Object2ObjectMap JAVA_TO_BEDROCK_IDENTIFIERS = new Object2ObjectOpenHashMap<>(); - private static final BiMap JAVA_ID_BLOCK_MAP = HashBiMap.create(); + private static final Int2ObjectMap BEDROCK_TO_JAVA_BLOCK_MAP = new Int2ObjectOpenHashMap<>(); + private static final BiMap JAVA_ID_BLOCK_MAP = HashBiMap.create(); private static final IntSet WATERLOGGED = new IntOpenHashSet(); - private static final Object2IntMap ITEM_FRAMES = new Object2IntOpenHashMap<>(); + private static final Object2IntMap ITEM_FRAMES = new Object2IntOpenHashMap<>(); // Bedrock carpet ID, used in LlamaEntity.java for decoration public static final int CARPET = 171; + private static final Map JAVA_ID_TO_BLOCK_ENTITY_MAP = new HashMap<>(); + public static final Int2DoubleMap JAVA_RUNTIME_ID_TO_HARDNESS = new Int2DoubleOpenHashMap(); public static final Int2BooleanMap JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND = new Int2BooleanOpenHashMap(); public static final Int2ObjectMap JAVA_RUNTIME_ID_TO_TOOL_TYPE = new Int2ObjectOpenHashMap<>(); - // The index of the collision data in collision.json - public static final Int2IntMap JAVA_RUNTIME_ID_TO_COLLISION_INDEX = new Int2IntOpenHashMap(); - - private static final Int2ObjectMap JAVA_RUNTIME_ID_TO_PICK_ITEM = new Int2ObjectOpenHashMap<>(); - - /** - * Java numeric ID to java unique identifier, used for block names in the statistics screen - */ - public static final Int2ObjectMap JAVA_ID_TO_JAVA_IDENTIFIER_MAP = new Int2ObjectOpenHashMap<>(); - - /** - * Runtime command block ID, used for fixing command block minecart appearances - */ - public static final int BEDROCK_RUNTIME_COMMAND_BLOCK_ID; - - /** - * A list of all Java runtime wool IDs, for use with block breaking math and shears - */ + // For block breaking animation math public static final IntSet JAVA_RUNTIME_WOOL_IDS = new IntOpenHashSet(); public static final int JAVA_RUNTIME_COBWEB_ID; @@ -98,31 +74,25 @@ public class BlockTranslator { public static final int JAVA_RUNTIME_SPAWNER_ID; - private static final int BLOCK_STATE_VERSION = 17825808; + private static final int BLOCK_STATE_VERSION = 17760256; static { /* Load block palette */ - InputStream stream = FileUtils.getResource("bedrock/blockpalette.nbt"); + InputStream stream = FileUtils.getResource("bedrock/runtime_block_states.dat"); - NbtList blocksTag; - try (NBTInputStream nbtInputStream = new NBTInputStream(new DataInputStream(stream))) { - NbtMap blockPalette = (NbtMap) nbtInputStream.readTag(); - blocksTag = (NbtList) blockPalette.getList("blocks", NbtType.COMPOUND); + ListTag blocksTag; + try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { + blocksTag = (ListTag) nbtInputStream.readTag(); } catch (Exception e) { throw new AssertionError("Unable to get blocks from runtime block states", e); } - // 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()); + Map blockStateMap = new HashMap<>(); - for (int i = 0; i < blocksTag.size(); i++) { - NbtMap tag = blocksTag.get(i); - NbtMap blockTag = tag.getCompound("block"); - if (blockStateOrderedMap.containsKey(blockTag)) { + for (CompoundTag tag : blocksTag.getValue()) { + if (blockStateMap.putIfAbsent(tag.getCompound("block"), tag) != null) { throw new AssertionError("Duplicate block states in Bedrock palette"); } - blockStateOrderedMap.put(blockTag, i); } stream = FileUtils.getResource("mappings/blocks.json"); @@ -132,29 +102,27 @@ public class BlockTranslator { } catch (Exception e) { throw new AssertionError("Unable to load Java block mappings", e); } + Object2IntMap addedStatesMap = new Object2IntOpenHashMap<>(); + addedStatesMap.defaultReturnValue(-1); + List paletteList = new ArrayList<>(); - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.world.block.entity") - : new Reflections("org.geysermc.connector.network.translators.world.block.entity"); + Reflections ref = new Reflections("org.geysermc.connector.network.translators.world.block.entity"); + ref.getTypesAnnotatedWith(BlockEntity.class); int waterRuntimeId = -1; int javaRuntimeId = -1; - int airRuntimeId = -1; + int bedrockRuntimeId = 0; int cobwebRuntimeId = -1; - int commandBlockRuntimeId = -1; int furnaceRuntimeId = -1; int furnaceLitRuntimeId = -1; int spawnerRuntimeId = -1; - int uniqueJavaId = -1; Iterator> blocksIterator = blocks.fields(); while (blocksIterator.hasNext()) { javaRuntimeId++; Map.Entry entry = blocksIterator.next(); String javaId = entry.getKey(); - NbtMap blockTag = buildBedrockState(entry.getValue()); - int bedrockRuntimeId = blockStateOrderedMap.getOrDefault(blockTag, -1); - if (bedrockRuntimeId == -1) { - throw new RuntimeException("Unable to find " + javaId + " Bedrock runtime ID!"); - } + BlockState javaBlockState = new BlockState(javaRuntimeId); + CompoundTag blockTag = buildBedrockState(entry.getValue()); // TODO fix this, (no block should have a null hardness) JsonNode hardnessNode = entry.getValue().get("block_hardness"); @@ -162,47 +130,40 @@ public class BlockTranslator { JAVA_RUNTIME_ID_TO_HARDNESS.put(javaRuntimeId, hardnessNode.doubleValue()); } - try { - JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, entry.getValue().get("can_break_with_hand").booleanValue()); - } catch (Exception e) { - JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, false); - } + JAVA_RUNTIME_ID_TO_CAN_HARVEST_WITH_HAND.put(javaRuntimeId, entry.getValue().get("can_break_with_hand").booleanValue()); JsonNode toolTypeNode = entry.getValue().get("tool_type"); if (toolTypeNode != null) { JAVA_RUNTIME_ID_TO_TOOL_TYPE.put(javaRuntimeId, toolTypeNode.textValue()); } - JsonNode collisionIndexNode = entry.getValue().get("collision_index"); - if (hardnessNode != null) { - JAVA_RUNTIME_ID_TO_COLLISION_INDEX.put(javaRuntimeId, collisionIndexNode.intValue()); + if (javaId.contains("wool")) { + JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId); } - JsonNode pickItemNode = entry.getValue().get("pick_item"); - if (pickItemNode != null) { - JAVA_RUNTIME_ID_TO_PICK_ITEM.put(javaRuntimeId, pickItemNode.textValue()); + if (javaId.contains("cobweb")) { + cobwebRuntimeId = javaRuntimeId; } - JAVA_ID_BLOCK_MAP.put(javaId, javaRuntimeId); + JAVA_ID_BLOCK_MAP.put(javaId, javaBlockState); - BlockStateValues.storeBlockStateValues(entry, javaRuntimeId); - - String cleanJavaIdentifier = entry.getKey().split("\\[")[0]; - - if (!JAVA_ID_TO_JAVA_IDENTIFIER_MAP.containsValue(cleanJavaIdentifier)) { - uniqueJavaId++; - JAVA_ID_TO_JAVA_IDENTIFIER_MAP.put(uniqueJavaId, cleanJavaIdentifier); + // Used for adding all "special" Java block states to block state map + String identifier; + String bedrock_identifer = entry.getValue().get("bedrock_identifier").asText(); + for (Class clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) { + identifier = clazz.getAnnotation(BlockEntity.class).regex(); + // Endswith, or else the block bedrock gets picked up for bed + if (bedrock_identifer.endsWith(identifier) && !identifier.equals("")) { + JAVA_ID_TO_BLOCK_ENTITY_MAP.put(javaBlockState, clazz.getAnnotation(BlockEntity.class).name()); + break; + } } - String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); - - if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { - JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier); - } + BlockStateValues.storeBlockStateValues(entry, javaBlockState); // Get the tag needed for non-empty flower pots if (entry.getValue().get("pottable") != null) { - BlockStateValues.getFlowerPotBlocks().put(cleanJavaIdentifier, buildBedrockState(entry.getValue())); + BlockStateValues.getFlowerPotBlocks().put(entry.getKey().split("\\[")[0], buildBedrockState(entry.getValue())); } if ("minecraft:water[level=0]".equals(javaId)) { @@ -212,36 +173,40 @@ public class BlockTranslator { || javaId.contains("minecraft:bubble_column") || javaId.contains("minecraft:kelp") || javaId.contains("seagrass"); if (waterlogged) { - BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaRuntimeId); + BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId | 1 << 31, javaBlockState); WATERLOGGED.add(javaRuntimeId); } else { - BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaRuntimeId); + BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaBlockState); } + CompoundTag runtimeTag = blockStateMap.remove(blockTag); + if (runtimeTag != null) { + addedStatesMap.put(blockTag, bedrockRuntimeId); + paletteList.add(runtimeTag); + } else { + int duplicateRuntimeId = addedStatesMap.getOrDefault(blockTag, -1); + if (duplicateRuntimeId == -1) { + GeyserConnector.getInstance().getLogger().debug("Mapping " + javaId + " was not found for bedrock edition!"); + } else { + JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, duplicateRuntimeId); + } + continue; + } JAVA_TO_BEDROCK_BLOCK_MAP.put(javaRuntimeId, bedrockRuntimeId); - if (bedrockIdentifier.equals("minecraft:air")) { - airRuntimeId = bedrockRuntimeId; - - } else if (javaId.contains("wool")) { - JAVA_RUNTIME_WOOL_IDS.add(javaRuntimeId); - - } else if (javaId.contains("cobweb")) { - cobwebRuntimeId = javaRuntimeId; - - } else if (javaId.equals("minecraft:command_block[conditional=false,facing=north]")) { - commandBlockRuntimeId = bedrockRuntimeId; - - } else if (javaId.startsWith("minecraft:furnace[facing=north")) { + if (javaId.startsWith("minecraft:furnace[facing=north")) { if (javaId.contains("lit=true")) { furnaceLitRuntimeId = javaRuntimeId; } else { furnaceRuntimeId = javaRuntimeId; } + } - } else if (javaId.startsWith("minecraft:spawner")) { + if (javaId.startsWith("minecraft:spawner")) { spawnerRuntimeId = javaRuntimeId; } + + bedrockRuntimeId++; } if (cobwebRuntimeId == -1) { @@ -249,11 +214,6 @@ public class BlockTranslator { } JAVA_RUNTIME_COBWEB_ID = cobwebRuntimeId; - if (commandBlockRuntimeId == -1) { - throw new AssertionError("Unable to find command block in palette"); - } - BEDROCK_RUNTIME_COMMAND_BLOCK_ID = commandBlockRuntimeId; - if (furnaceRuntimeId == -1) { throw new AssertionError("Unable to find furnace in palette"); } @@ -274,17 +234,19 @@ public class BlockTranslator { } BEDROCK_WATER_ID = waterRuntimeId; - if (airRuntimeId == -1) { - throw new AssertionError("Unable to find air in palette"); - } - BEDROCK_AIR_ID = airRuntimeId; + paletteList.addAll(blockStateMap.values()); // Add any missing mappings that could crash the client // Loop around again to find all item frame runtime IDs - for (Object2IntMap.Entry entry : blockStateOrderedMap.object2IntEntrySet()) { - if (entry.getKey().getString("name").equals("minecraft:frame")) { - ITEM_FRAMES.put(entry.getKey(), entry.getIntValue()); + int frameRuntimeId = 0; + for (CompoundTag tag : paletteList) { + CompoundTag blockTag = tag.getCompound("block"); + if (blockTag.getString("name").equals("minecraft:frame")) { + ITEM_FRAMES.put(tag, frameRuntimeId); } + frameRuntimeId++; } + + BLOCKS = new ListTag<>("", CompoundTag.class, paletteList); } private BlockTranslator() { @@ -294,12 +256,12 @@ public class BlockTranslator { // no-op } - private static NbtMap buildBedrockState(JsonNode node) { - NbtMapBuilder tagBuilder = NbtMap.builder(); - tagBuilder.putString("name", node.get("bedrock_identifier").textValue()) - .putInt("version", BlockTranslator.BLOCK_STATE_VERSION); + private static CompoundTag buildBedrockState(JsonNode node) { + CompoundTagBuilder tagBuilder = CompoundTag.builder(); + tagBuilder.stringTag("name", node.get("bedrock_identifier").textValue()) + .intTag("version", BlockTranslator.BLOCK_STATE_VERSION); - NbtMapBuilder statesBuilder = NbtMap.builder(); + CompoundTagBuilder statesBuilder = CompoundTag.builder(); // check for states if (node.has("bedrock_states")) { @@ -310,37 +272,32 @@ public class BlockTranslator { JsonNode stateValue = stateEntry.getValue(); switch (stateValue.getNodeType()) { case BOOLEAN: - statesBuilder.putBoolean(stateEntry.getKey(), stateValue.booleanValue()); + statesBuilder.booleanTag(stateEntry.getKey(), stateValue.booleanValue()); continue; case STRING: - statesBuilder.putString(stateEntry.getKey(), stateValue.textValue()); + statesBuilder.stringTag(stateEntry.getKey(), stateValue.textValue()); continue; case NUMBER: - statesBuilder.putInt(stateEntry.getKey(), stateValue.intValue()); + statesBuilder.intTag(stateEntry.getKey(), stateValue.intValue()); } } } - tagBuilder.put("states", statesBuilder.build()); - return tagBuilder.build(); + return tagBuilder.tag(statesBuilder.build("states")).build("block"); } - public static int getBedrockBlockId(int state) { - return JAVA_TO_BEDROCK_BLOCK_MAP.get(state); + public static int getBedrockBlockId(BlockState state) { + return JAVA_TO_BEDROCK_BLOCK_MAP.get(state.getId()); } - public static int getJavaBlockState(int bedrockId) { + public static int getBedrockBlockId(int javaId) { + return JAVA_TO_BEDROCK_BLOCK_MAP.get(javaId); + } + + public static BlockState getJavaBlockState(int bedrockId) { return BEDROCK_TO_JAVA_BLOCK_MAP.get(bedrockId); } - /** - * @param javaIdentifier the Java identifier of the block to search for - * @return the Bedrock identifier if different, or else the Java identifier - */ - public static String getBedrockBlockIdentifier(String javaIdentifier) { - return JAVA_TO_BEDROCK_IDENTIFIERS.getOrDefault(javaIdentifier, javaIdentifier); - } - - public static int getItemFrame(NbtMap tag) { + public static int getItemFrame(CompoundTag tag) { return ITEM_FRAMES.getOrDefault(tag, -1); } @@ -352,38 +309,23 @@ public class BlockTranslator { return BLOCK_STATE_VERSION; } - /** - * @param javaId the Java string identifier to search for - * @return the Java block state integer, or {@link #JAVA_AIR_ID} if there is no valid entry. - */ - public static int getJavaBlockState(String javaId) { - return JAVA_ID_BLOCK_MAP.getOrDefault(javaId, JAVA_AIR_ID); + public static BlockState getJavaBlockState(String javaId) { + return JAVA_ID_BLOCK_MAP.get(javaId); } - public static boolean isWaterlogged(int state) { - return WATERLOGGED.contains(state); + public static String getBlockEntityString(BlockState javaId) { + return JAVA_ID_TO_BLOCK_ENTITY_MAP.get(javaId); } - public static BiMap getJavaIdBlockMap() { + public static boolean isWaterlogged(BlockState state) { + return WATERLOGGED.contains(state.getId()); + } + + public static BiMap getJavaIdBlockMap() { return JAVA_ID_BLOCK_MAP; } - public static int getJavaWaterloggedState(int bedrockId) { + public static BlockState getJavaWaterloggedState(int bedrockId) { return BEDROCK_TO_JAVA_BLOCK_MAP.get(1 << 31 | bedrockId); } - - /** - * Get the item a Java client would receive when pressing - * the Pick Block key on a specific Java block state. - * - * @param javaId The Java runtime id of the block - * @return The Java identifier of the item - */ - public static String getPickItem(int javaId) { - String itemIdentifier = JAVA_RUNTIME_ID_TO_PICK_ITEM.get(javaId); - if (itemIdentifier == null) { - return JAVA_ID_BLOCK_MAP.inverse().get(javaId).split("\\[")[0]; - } - return itemIdentifier; - } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/DoubleChestValue.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/DoubleChestValue.java index 52715984..5bd21724 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/DoubleChestValue.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/DoubleChestValue.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java index 07760c46..3e2c0a95 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,39 +25,59 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.IntTag; +import com.nukkitx.nbt.tag.StringTag; +import com.nukkitx.nbt.tag.Tag; import org.geysermc.connector.network.translators.item.translators.BannerTranslator; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import java.util.ArrayList; +import java.util.List; + @BlockEntity(name = "Banner", regex = "banner") public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + @Override - public boolean isBlock(int blockState) { + public boolean isBlock(BlockState blockState) { return BlockStateValues.getBannerColor(blockState) != -1; } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + int bannerColor = BlockStateValues.getBannerColor(blockState); if (bannerColor != -1) { - builder.put("Base", 15 - bannerColor); + tags.add(new IntTag("Base", 15 - bannerColor)); } if (tag.contains("Patterns")) { ListTag patterns = tag.get("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 - builder.putInt("Type", 1); - } else { - builder.put("Patterns", BannerTranslator.convertBannerPattern(patterns)); - } + tags.add(BannerTranslator.convertBannerPattern(patterns)); } if (tag.contains("CustomName")) { - builder.put("CustomName", tag.get("CustomName").getValue()); + tags.add(new StringTag("CustomName", (String) tag.get("CustomName").getValue())); } + + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + CompoundTag tag = getConstantJavaTag(javaId, x, y, z); + tag.put(new ListTag("Patterns")); + return tag; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.listTag("Patterns", com.nukkitx.nbt.tag.CompoundTag.class, new ArrayList<>()); + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java index 7d9dee98..5f0b1cc0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,24 +25,43 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.ByteTag; +import com.nukkitx.nbt.tag.Tag; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import java.util.ArrayList; +import java.util.List; + @BlockEntity(name = "Bed", regex = "bed") public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + @Override - public boolean isBlock(int blockState) { + public boolean isBlock(BlockState blockState) { return BlockStateValues.getBedColor(blockState) != -1; } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); byte bedcolor = BlockStateValues.getBedColor(blockState); // Just in case... - if (bedcolor == -1) { - bedcolor = 0; - } - builder.put("color", bedcolor); + if (bedcolor == -1) bedcolor = 0; + tags.add(new ByteTag("color", bedcolor)); + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.byteTag("color", (byte) 0); + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedrockOnlyBlockEntity.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedrockOnlyBlockEntity.java index e05fcc67..5b325eba 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedrockOnlyBlockEntity.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BedrockOnlyBlockEntity.java @@ -1,45 +1,48 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.tag.CompoundTag; import org.geysermc.connector.network.session.GeyserSession; /** * Implemented only if a block is a block entity in Bedrock and not Java Edition. */ public interface BedrockOnlyBlockEntity { + /** * Update the block on Bedrock Edition. * @param session GeyserSession. * @param blockState The Java block state. * @param position The Bedrock block position. */ - void updateBlock(GeyserSession session, int blockState, Vector3i position); + void updateBlock(GeyserSession session, BlockState blockState, Vector3i position); /** * Get the tag of the Bedrock-only block entity @@ -47,8 +50,8 @@ public interface BedrockOnlyBlockEntity { * @param blockState Java BlockState of block. * @return Bedrock tag, or null if not a Bedrock-only Block Entity */ - static NbtMap getTag(Vector3i position, int blockState) { - if (FlowerPotBlockEntityTranslator.isFlowerBlock(blockState)) { + static CompoundTag getTag(Vector3i position, BlockState blockState) { + if (new FlowerPotBlockEntityTranslator().isBlock(blockState)) { return FlowerPotBlockEntityTranslator.getTag(blockState, position); } else if (PistonBlockEntityTranslator.isBlock(blockState)) { return PistonBlockEntityTranslator.getTag(blockState, position); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java index acd0c87f..11bfe0ea 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java index 7f2e16ef..3d663926 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,46 +25,26 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.Tag; + import it.unimi.dsi.fastutil.objects.ObjectArrayList; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.BlockEntityUtils; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.LanguageUtils; import org.reflections.Reflections; import java.util.HashMap; +import java.util.List; import java.util.Map; -/** - * The class that all block entities (on both Java and Bedrock) should translate with - */ public abstract class BlockEntityTranslator { - public static final Map BLOCK_ENTITY_TRANSLATORS = new HashMap<>(); - /** - * 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 chunks on as we don't need to double-cache data - */ - public static final ObjectArrayList REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>(); - /** - * 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() { - { - // Bedrock/Java differences - put("minecraft:enchanting_table", "EnchantTable"); - put("minecraft:jigsaw", "JigsawBlock"); - put("minecraft:piston_head", "PistonArm"); - put("minecraft: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 - } - }; + public static final Map BLOCK_ENTITY_TRANSLATORS = new HashMap<>(); + public static ObjectArrayList REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>(); protected BlockEntityTranslator() { } @@ -74,44 +54,41 @@ public abstract class BlockEntityTranslator { } static { - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections("org.geysermc.connector.network.translators.world.block.entity") : new Reflections("org.geysermc.connector.network.translators.world.block.entity"); + Reflections ref = new Reflections("org.geysermc.connector.network.translators.world.block.entity"); for (Class clazz : ref.getTypesAnnotatedWith(BlockEntity.class)) { GeyserConnector.getInstance().getLogger().debug("Found annotated block entity: " + clazz.getCanonicalName()); try { BLOCK_ENTITY_TRANSLATORS.put(clazz.getAnnotation(BlockEntity.class).name(), (BlockEntityTranslator) clazz.newInstance()); } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_entity.failed", clazz.getCanonicalName())); + GeyserConnector.getInstance().getLogger().error("Could not instantiate annotated block entity " + clazz.getCanonicalName() + "."); } } - boolean cacheChunks = GeyserConnector.getInstance().getConfig().isCacheChunks(); for (Class clazz : ref.getSubTypesOf(RequiresBlockState.class)) { GeyserConnector.getInstance().getLogger().debug("Found block entity that requires block state: " + clazz.getCanonicalName()); try { - RequiresBlockState requiresBlockState = (RequiresBlockState) clazz.newInstance(); - if (cacheChunks && !(requiresBlockState instanceof BedrockOnlyBlockEntity)) { - // Not needed to put this one in the map; cache chunks takes care of that for us - GeyserConnector.getInstance().getLogger().debug("Not adding because cache chunks is enabled."); - continue; - } - REQUIRES_BLOCK_STATE_LIST.add(requiresBlockState); + REQUIRES_BLOCK_STATE_LIST.add((RequiresBlockState) clazz.newInstance()); } catch (InstantiationException | IllegalAccessException e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_state.failed", clazz.getCanonicalName())); + GeyserConnector.getInstance().getLogger().error("Could not instantiate required block state " + clazz.getCanonicalName() + "."); } } } - public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState); + public abstract List> translateTag(CompoundTag tag, BlockState blockState); - public NbtMap getBlockEntityTag(String id, CompoundTag tag, int blockState) { - int x = ((IntTag) tag.getValue().get("x")).getValue(); - int y = ((IntTag) tag.getValue().get("y")).getValue(); - int z = ((IntTag) tag.getValue().get("z")).getValue(); + public abstract CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z); - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder(); - translateTag(tagBuilder, tag, blockState); - return tagBuilder.build(); + public abstract com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z); + + public com.nukkitx.nbt.tag.CompoundTag getBlockEntityTag(String id, CompoundTag tag, BlockState blockState) { + int x = Integer.parseInt(String.valueOf(tag.getValue().get("x").getValue())); + int y = Integer.parseInt(String.valueOf(tag.getValue().get("y").getValue())); + int z = Integer.parseInt(String.valueOf(tag.getValue().get("z").getValue())); + + CompoundTagBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder(); + translateTag(tag, blockState).forEach(tagBuilder::tag); + return tagBuilder.buildRootTag(); } protected CompoundTag getConstantJavaTag(String javaId, int x, int y, int z) { @@ -123,17 +100,17 @@ public abstract class BlockEntityTranslator { return tag; } - protected NbtMap getConstantBedrockTag(String bedrockId, int x, int y, int z) { - return NbtMap.builder() - .putInt("x", x) - .putInt("y", y) - .putInt("z", z) - .putString("id", bedrockId) - .build(); + protected com.nukkitx.nbt.tag.CompoundTag getConstantBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder() + .intTag("x", x) + .intTag("y", y) + .intTag("z", z) + .stringTag("id", bedrockId); + return tagBuilder.buildRootTag(); } @SuppressWarnings("unchecked") - protected T getOrDefault(Tag tag, T defaultValue) { + protected T getOrDefault(com.github.steveice10.opennbt.tag.builtin.Tag tag, T defaultValue) { return (tag != null && tag.getValue() != null) ? (T) tag.getValue() : defaultValue; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java index 7ae4f315..cd31636c 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CampfireBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,57 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.ListTag; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.Tag; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + @BlockEntity(name = "Campfire", regex = "campfire") public class CampfireBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); ListTag items = tag.get("Items"); int i = 1; for (com.github.steveice10.opennbt.tag.builtin.Tag itemTag : items.getValue()) { - builder.put("Item" + i, getItem((CompoundTag) itemTag)); + tags.add(getItem((CompoundTag) itemTag).toBuilder().build("Item" + i)); i++; } + return tags; } - protected NbtMap getItem(CompoundTag tag) { + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + CompoundTag tag = getConstantJavaTag(javaId, x, y, z); + tag.put(new ListTag("Items")); + return tag; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item1", new HashMap<>())); + tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item2", new HashMap<>())); + tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item3", new HashMap<>())); + tagBuilder.tag(new com.nukkitx.nbt.tag.CompoundTag("Item4", new HashMap<>())); + return tagBuilder.buildRootTag(); + } + + protected com.nukkitx.nbt.tag.CompoundTag getItem(CompoundTag tag) { ItemEntry entry = ItemRegistry.getItemEntry((String) tag.get("id").getValue()); - NbtMapBuilder tagBuilder = NbtMap.builder() - .putString("Name", entry.getBedrockIdentifier()) - .putByte("Count", (byte) tag.get("Count").getValue()) - .putShort("Damage", (short) entry.getBedrockData()); - tagBuilder.put("tag", NbtMap.builder().build()); - return tagBuilder.build(); + CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder() + .shortTag("id", (short) entry.getBedrockId()) + .byteTag("Count", (byte) tag.get("Count").getValue()) + .shortTag("Damage", (short) entry.getBedrockData()) + .tag(CompoundTagBuilder.builder().build("tag")); + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java deleted file mode 100644 index fe988854..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/CommandBlockBlockEntityTranslator.java +++ /dev/null @@ -1,62 +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.connector.network.translators.world.block.entity; - -import com.github.steveice10.opennbt.tag.builtin.*; -import com.nukkitx.nbt.NbtMapBuilder; -import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import org.geysermc.connector.network.translators.chat.MessageTranslator; - -@BlockEntity(name = "CommandBlock", regex = "command_block") -public class CommandBlockBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { - @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - if (tag.size() < 5) { - return; // These values aren't here - } - // Java infers from the block state, but Bedrock needs it in the tag - builder.put("conditionalMode", BlockStateValues.getCommandBlockValues().getOrDefault(blockState, (byte) 0)); - // Java and Bedrock values - builder.put("conditionMet", ((ByteTag) tag.get("conditionMet")).getValue()); - builder.put("auto", ((ByteTag) tag.get("auto")).getValue()); - builder.put("CustomName", MessageTranslator.convertMessage(((StringTag) tag.get("CustomName")).getValue())); - builder.put("powered", ((ByteTag) tag.get("powered")).getValue()); - builder.put("Command", ((StringTag) tag.get("Command")).getValue()); - builder.put("SuccessCount", ((IntTag) tag.get("SuccessCount")).getValue()); - builder.put("TrackOutput", ((ByteTag) tag.get("TrackOutput")).getValue()); - builder.put("UpdateLastExecution", ((ByteTag) tag.get("UpdateLastExecution")).getValue()); - if (tag.get("LastExecution") != null) { - builder.put("LastExecution", ((LongTag) tag.get("LastExecution")).getValue()); - } else { - builder.put("LastExecution", (long) 0); - } - } - - @Override - public boolean isBlock(int blockState) { - return BlockStateValues.getCommandBlockValues().containsKey(blockState); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java index 991fb266..f5599832 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/DoubleChestBlockEntityTranslator.java @@ -1,85 +1,108 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.ByteTag; +import com.nukkitx.nbt.tag.IntTag; +import com.nukkitx.nbt.tag.Tag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockStateValues; import org.geysermc.connector.network.translators.world.block.DoubleChestValue; import org.geysermc.connector.utils.BlockEntityUtils; +import java.util.ArrayList; +import java.util.List; + /** * Chests have more block entity properties in Bedrock, which is solved by implementing the BedrockOnlyBlockEntity */ @BlockEntity(name = "Chest", regex = "chest") public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState { + @Override - public boolean isBlock(int blockState) { - return BlockStateValues.getDoubleChestValues().containsKey(blockState); + public boolean isBlock(BlockState blockState) { + return BlockStateValues.getDoubleChestValues().containsKey(blockState.getId()); } @Override - public void updateBlock(GeyserSession session, int blockState, Vector3i position) { + public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { CompoundTag javaTag = getConstantJavaTag("chest", position.getX(), position.getY(), position.getZ()); - NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId("chest"), position.getX(), position.getY(), position.getZ()).toBuilder(); - translateTag(tagBuilder, javaTag, blockState); - BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), position); + CompoundTagBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId("chest"), position.getX(), position.getY(), position.getZ()).toBuilder(); + translateTag(javaTag, blockState).forEach(tagBuilder::tag); + BlockEntityUtils.updateBlockEntity(session, tagBuilder.buildRootTag(), position); } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().getOrDefault(blockState, null); - if (chestValues != null) { - int x = (int) tag.getValue().get("x").getValue(); - int z = (int) tag.getValue().get("z").getValue(); - // Calculate the position of the other chest based on the Java block state - if (chestValues.isFacingEast) { - if (chestValues.isDirectionPositive) { - // East - z = z + (chestValues.isLeft ? 1 : -1); + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + if (blockState != null && BlockStateValues.getDoubleChestValues().containsKey(blockState.getId())) { + DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState.getId()); + if (chestValues != null) { + int x = (int) tag.getValue().get("x").getValue(); + int z = (int) tag.getValue().get("z").getValue(); + // Calculate the position of the other chest based on the Java block state + if (chestValues.isFacingEast) { + if (chestValues.isDirectionPositive) { + // East + z = z + (chestValues.isLeft ? 1 : -1); + } else { + // West + z = z + (chestValues.isLeft ? -1 : 1); + } } else { - // West - z = z + (chestValues.isLeft ? -1 : 1); + if (chestValues.isDirectionPositive) { + // South + x = x + (chestValues.isLeft ? -1 : 1); + } else { + // North + x = x + (chestValues.isLeft ? 1 : -1); + } } - } else { - if (chestValues.isDirectionPositive) { - // South - x = x + (chestValues.isLeft ? -1 : 1); - } else { - // North - x = x + (chestValues.isLeft ? 1 : -1); + tags.add(new IntTag("pairx", x)); + tags.add(new IntTag("pairz", z)); + if (!chestValues.isLeft) { + tags.add(new ByteTag("pairlead", (byte) 1)); } } - builder.put("pairx", x); - builder.put("pairz", z); - if (!chestValues.isLeft) { - builder.put("pairlead", (byte) 1); - } } + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return null; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java index 12afd530..d1068277 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EmptyBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 +25,28 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.tag.Tag; + +import java.util.ArrayList; +import java.util.List; @BlockEntity(name = "Empty", regex = "") public class EmptyBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public List> translateTag(CompoundTag tag, BlockState blockState) { + return new ArrayList<>(); + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return getConstantJavaTag(javaId, x, y, z); + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java index 2dbd7585..4cd2eaa9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/EndGatewayBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,38 +25,61 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; -import com.nukkitx.nbt.NbtList; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; +import com.github.steveice10.opennbt.tag.builtin.LongTag; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.IntTag; +import com.nukkitx.nbt.tag.Tag; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; @BlockEntity(name = "EndGateway", regex = "end_gateway") public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - builder.put("Age", (int) ((long) tag.get("Age").getValue())); + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + tags.add(new IntTag("Age", (int) (long) tag.get("Age").getValue())); // Java sometimes does not provide this tag, but Bedrock crashes if it doesn't exist // Linked coordinates - IntList tagsList = new IntArrayList(); + List tagsList = new ArrayList<>(); // Yes, the axis letters are capitalized - tagsList.add(getExitPortalCoordinate(tag, "X")); - tagsList.add(getExitPortalCoordinate(tag, "Y")); - tagsList.add(getExitPortalCoordinate(tag, "Z")); - builder.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList)); + tagsList.add(new IntTag("", getExitPortalCoordinate(tag, "X"))); + tagsList.add(new IntTag("", getExitPortalCoordinate(tag, "Y"))); + tagsList.add(new IntTag("", getExitPortalCoordinate(tag, "Z"))); + com.nukkitx.nbt.tag.ListTag exitPortal = + new com.nukkitx.nbt.tag.ListTag<>("ExitPortal", IntTag.class, tagsList); + tags.add(exitPortal); + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + CompoundTag tag = getConstantJavaTag(javaId, x, y, z); + tag.put(new LongTag("Age")); + return tag; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + List tagsList = new ArrayList<>(); + tagsList.add(new IntTag("", 0)); + tagsList.add(new IntTag("", 0)); + tagsList.add(new IntTag("", 0)); + tagBuilder.listTag("ExitPortal", IntTag.class, tagsList); + return tagBuilder.buildRootTag(); } private int getExitPortalCoordinate(CompoundTag tag, String axis) { // Return 0 if it doesn't exist, otherwise give proper value if (tag.get("ExitPortal") != null) { - LinkedHashMap compoundTag = (LinkedHashMap) tag.get("ExitPortal").getValue(); - IntTag intTag = (IntTag) compoundTag.get(axis); + LinkedHashMap compoundTag = (LinkedHashMap) tag.get("ExitPortal").getValue(); + com.github.steveice10.opennbt.tag.builtin.IntTag intTag = (com.github.steveice10.opennbt.tag.builtin.IntTag) compoundTag.get(axis); return intTag.getValue(); - } - return 0; + } return 0; } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java index 9eebe37d..c4748c82 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/FlowerPotBlockEntityTranslator.java @@ -1,33 +1,35 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.CompoundTag; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockStateValues; @@ -35,57 +37,48 @@ import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.BlockEntityUtils; public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, RequiresBlockState { - /** - * @param blockState the Java block state of a potential flower pot block - * @return true if the block is a flower pot - */ - public static boolean isFlowerBlock(int blockState) { - return BlockStateValues.getFlowerPotValues().containsKey(blockState); - } - /** - * Get the Nukkit CompoundTag of the flower pot. - * - * @param blockState Java block state of flower pot. - * @param position Bedrock position of flower pot. - * @return Bedrock tag of flower pot. - */ - public static NbtMap getTag(int blockState, Vector3i position) { - NbtMapBuilder tagBuilder = NbtMap.builder() - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .putByte("isMovable", (byte) 1) - .putString("id", "FlowerPot"); - // Get the Java name of the plant inside. e.g. minecraft:oak_sapling - String name = BlockStateValues.getFlowerPotValues().get(blockState); - if (name != null) { - // Get the Bedrock CompoundTag of the block. - // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. - NbtMap plant = BlockStateValues.getFlowerPotBlocks().get(name); - if (plant != null) { - tagBuilder.put("PlantBlock", plant.toBuilder().build()); - } - } - return tagBuilder.build(); + @Override + public boolean isBlock(BlockState blockState) { + return (BlockStateValues.getFlowerPotValues().containsKey(blockState.getId())); } @Override - public boolean isBlock(int blockState) { - return isFlowerBlock(blockState); - } - - @Override - public void updateBlock(GeyserSession session, int blockState, Vector3i position) { + public void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); updateBlockPacket.setDataLayer(0); updateBlockPacket.setRuntimeId(BlockTranslator.getBedrockBlockId(blockState)); updateBlockPacket.setBlockPosition(position); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.PRIORITY); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NONE); + updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); session.sendUpstreamPacket(updateBlockPacket); - BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position); + } + + /** + * Get the Nukkit CompoundTag of the flower pot. + * @param blockState Java BlockState of flower pot. + * @param position Bedrock position of flower pot. + * @return Bedrock tag of flower pot. + */ + public static CompoundTag getTag(BlockState blockState, Vector3i position) { + CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .byteTag("isMovable", (byte) 1) + .stringTag("id", "FlowerPot"); + // Get the Java name of the plant inside. e.g. minecraft:oak_sapling + String name = BlockStateValues.getFlowerPotValues().get(blockState.getId()); + if (name != null) { + // Get the Bedrock CompoundTag of the block. + // This is where we need to store the *Java* name because Bedrock has six minecraft:sapling blocks with different block states. + CompoundTag plant = BlockStateValues.getFlowerPotBlocks().get(name); + if (plant != null) { + tagBuilder.tag(plant.toBuilder().build("PlantBlock")); + } + } + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java deleted file mode 100644 index 10582c7b..00000000 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/JigsawBlockBlockEntityTranslator.java +++ /dev/null @@ -1,42 +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.connector.network.translators.world.block.entity; - -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.StringTag; -import com.nukkitx.nbt.NbtMapBuilder; - -@BlockEntity(name = "JigsawBlock", regex = "jigsaw") -public class JigsawBlockBlockEntityTranslator extends BlockEntityTranslator { - @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()); - builder.put("final_state", ((StringTag) tag.get("final_state")).getValue()); - builder.put("target", ((StringTag) tag.get("target")).getValue()); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/NoteblockBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/NoteblockBlockEntityTranslator.java index 3254565d..168015f6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/NoteblockBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/NoteblockBlockEntityTranslator.java @@ -1,31 +1,33 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.packet.BlockEventPacket; import org.geysermc.connector.network.session.GeyserSession; @@ -36,20 +38,21 @@ import org.geysermc.connector.utils.ChunkUtils; * Does not implement BlockEntityTranslator because it's only a block entity in Bedrock */ public class NoteblockBlockEntityTranslator implements RequiresBlockState { + @Override - public boolean isBlock(int blockState) { + public boolean isBlock(BlockState blockState) { return BlockStateValues.getNoteblockPitch(blockState) != -1; } public static void translate(GeyserSession session, Position position) { - int blockState = session.getConnector().getConfig().isCacheChunks() ? - session.getConnector().getWorldManager().getBlockAt(session, position) : - ChunkUtils.CACHED_BLOCK_ENTITIES.removeInt(position); + BlockState blockState = ChunkUtils.CACHED_BLOCK_ENTITIES.get(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); + + ChunkUtils.CACHED_BLOCK_ENTITIES.remove(position); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/PistonBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/PistonBlockEntityTranslator.java index f6211703..2dffce24 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/PistonBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/PistonBlockEntityTranslator.java @@ -1,70 +1,72 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.CompoundTag; import org.geysermc.connector.network.translators.world.block.BlockStateValues; /** * Pistons are a special case where they are only a block entity on Bedrock. */ public class PistonBlockEntityTranslator { + /** * Used in ChunkUtils to determine if the block is a piston. - * * @param blockState Java BlockState of block. * @return if block is a piston or not. */ - public static boolean isBlock(int blockState) { - return BlockStateValues.getPistonValues().containsKey(blockState); + public static boolean isBlock(BlockState blockState) { + return BlockStateValues.getPistonValues().containsKey(blockState.getId()); } /** * Calculates the Nukkit CompoundTag to send to the client on chunk - * - * @param blockState Java block state of block. - * @param position Bedrock position of piston. + * @param blockState Java BlockState of block. + * @param position Bedrock position of piston. * @return Bedrock tag of piston. */ - public static NbtMap getTag(int blockState, Vector3i position) { - NbtMapBuilder tagBuilder = NbtMap.builder() - .putInt("x", position.getX()) - .putInt("y", position.getY()) - .putInt("z", position.getZ()) - .putByte("isMovable", (byte) 1) - .putString("id", "PistonArm"); - - boolean extended = BlockStateValues.getPistonValues().get(blockState); - // 1f if extended, otherwise 0f - tagBuilder.putFloat("Progress", (extended) ? 1.0f : 0.0f); - // 1 if sticky, 0 if not - tagBuilder.putByte("Sticky", (byte) ((BlockStateValues.isStickyPiston(blockState)) ? 1 : 0)); - - return tagBuilder.build(); + public static CompoundTag getTag(BlockState blockState, Vector3i position) { + CompoundTagBuilder tagBuilder = CompoundTagBuilder.builder() + .intTag("x", position.getX()) + .intTag("y", position.getY()) + .intTag("z", position.getZ()) + .byteTag("isMovable", (byte) 1) + .stringTag("id", "PistonArm"); + if (BlockStateValues.getPistonValues().containsKey(blockState.getId())) { + boolean extended = BlockStateValues.getPistonValues().get(blockState.getId()); + // 1f if extended, otherwise 0f + tagBuilder.floatTag("Progress", (extended) ? 1.0f : 0.0f); + // 1 if sticky, 0 if not + tagBuilder.byteTag("Sticky", (byte)((BlockStateValues.isStickyPiston(blockState)) ? 1 : 0)); + } + return tagBuilder.buildRootTag(); } + } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/RequiresBlockState.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/RequiresBlockState.java index 146e024f..4df7292a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/RequiresBlockState.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/RequiresBlockState.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; + /** * Implemented in block entities if their Java block state is required for additional values in Bedrock */ @@ -35,6 +37,6 @@ public interface RequiresBlockState { * @param blockState BlockState to be compared * @return true if part of the class */ - boolean isBlock(int blockState); + boolean isBlock(BlockState blockState); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java index 70fde3e4..373b963e 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/ShulkerBoxBlockEntityTranslator.java @@ -1,43 +1,65 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.ByteTag; +import com.nukkitx.nbt.tag.Tag; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import java.util.ArrayList; +import java.util.List; + @BlockEntity(name = "ShulkerBox", regex = "shulker_box") public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + byte direction = BlockStateValues.getShulkerBoxDirection(blockState); // Just in case... - if (direction == -1) { - direction = 1; - } - builder.put("facing", direction); + if (direction == -1) direction = 1; + tags.add(new ByteTag("facing", direction)); + + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.byteTag("facing", (byte)1); + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java index 2a3950b3..6c170462 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SignBlockEntityTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,109 +25,58 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.github.steveice10.mc.protocol.data.message.Message; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; -import org.geysermc.connector.network.translators.chat.MessageTranslator; -import org.geysermc.connector.utils.SignUtils; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.StringTag; +import com.nukkitx.nbt.tag.Tag; +import io.netty.util.internal.StringUtil; +import org.geysermc.connector.utils.MessageUtils; + +import java.util.ArrayList; +import java.util.List; @BlockEntity(name = "Sign", regex = "sign") public class SignBlockEntityTranslator extends BlockEntityTranslator { - /** - * Maps a color stored in a sign's Color tag to a Bedrock Edition formatting code. - *
- * The color names correspond to dye names, because of this we can't use {@link MessageTranslator#getColor(String)}. - * - * @param javaColor The dye color stored in the sign's Color tag. - * @return A Bedrock Edition formatting code for valid dye colors, otherwise an empty string. - */ - private String getBedrockSignColor(String javaColor) { - String base = "\u00a7"; - switch (javaColor) { - case "white": - base += 'f'; - break; - case "orange": - base += '6'; - break; - case "magenta": - case "purple": - base += '5'; - break; - case "light_blue": - base += 'b'; - break; - case "yellow": - base += 'e'; - break; - case "lime": - base += 'a'; - break; - case "pink": - base += 'd'; - break; - case "gray": - base += '8'; - break; - case "light_gray": - base += '7'; - break; - case "cyan": - base += '3'; - break; - case "blue": - base += '9'; - break; - case "brown": // Brown does not have a bedrock counterpart. - case "red": // In Java Edition light red (&c) can only be applied using commands. Red dye gives &4. - base += '4'; - break; - case "green": - base += '2'; - break; - case "black": - base += '0'; - break; - default: - return ""; - } - return base; - } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + StringBuilder signText = new StringBuilder(); - for (int i = 0; i < 4; i++) { - int currentLine = i + 1; + for(int i = 0; i < 4; i++) { + int currentLine = i+1; String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), ""); - signLine = MessageTranslator.convertMessageLenient(signLine); + signLine = MessageUtils.getBedrockMessage(Message.fromString(signLine)); - // Trim any trailing formatting codes - if (signLine.length() > 2 && signLine.toCharArray()[signLine.length() - 2] == '\u00a7') { - signLine = signLine.substring(0, signLine.length() - 2); + //Java allows up to 16+ characters on certain symbols. + if(signLine.length() >= 15 && (signLine.contains("-") || signLine.contains("="))) { + signLine = signLine.substring(0, 14); } - // Check the character width on the sign to ensure there is no overflow that is usually hidden - // to Java Edition clients but will appear to Bedrock clients - int signWidth = 0; - StringBuilder finalSignLine = new StringBuilder(); - for (char c : signLine.toCharArray()) { - signWidth += SignUtils.getCharacterWidth(c); - if (signWidth <= SignUtils.BEDROCK_CHARACTER_WIDTH_MAX) { - finalSignLine.append(c); - } else { - break; - } - } - - // Java Edition 1.14 added the ability to change the text color of the whole sign using dye - if (tag.contains("Color")) { - signText.append(getBedrockSignColor(tag.get("Color").getValue().toString())); - } - - signText.append(finalSignLine.toString()); + signText.append(signLine); signText.append("\n"); } - builder.put("Text", signText.toString()); + tags.add(new StringTag("Text", MessageUtils.getBedrockMessage(Message.fromString(signText.toString())))); + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + CompoundTag tag = getConstantJavaTag(javaId, x, y, z); + tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text1", "{\"text\":\"\"}")); + tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text2", "{\"text\":\"\"}")); + tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text3", "{\"text\":\"\"}")); + tag.put(new com.github.steveice10.opennbt.tag.builtin.StringTag("Text4", "{\"text\":\"\"}")); + return tag; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.stringTag("Text", ""); + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java index c41d4515..9393f7bb 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SkullBlockEntityTranslator.java @@ -1,163 +1,71 @@ -/* - * 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.connector.network.translators.world.block.entity; - -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; -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.connector.entity.player.SkullPlayerEntity; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.world.block.BlockStateValues; -import org.geysermc.connector.skin.SkinProvider; -import org.geysermc.connector.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(name = "Skull", regex = "skull") -public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { - public static boolean ALLOW_CUSTOM_SKULLS; - - @Override - public boolean isBlock(int blockState) { - return BlockStateValues.getSkullVariant(blockState) != -1; - } - - @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - byte skullVariant = BlockStateValues.getSkullVariant(blockState); - float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f; - // Just in case... - if (skullVariant == -1) { - skullVariant = 0; - } - builder.put("Rotation", rotation); - builder.put("SkullType", skullVariant); - } - - public static CompletableFuture getProfile(CompoundTag tag) { - if (tag.contains("SkullOwner")) { - CompoundTag owner = tag.get("SkullOwner"); - CompoundTag properties = owner.get("Properties"); - if (properties == null) { - return SkinProvider.requestTexturesFromUsername(owner); - } - - 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(null); - } - - public static void spawnPlayer(GeyserSession session, CompoundTag tag, int blockState) { - int posX = (int) tag.get("x").getValue(); - int posY = (int) tag.get("y").getValue(); - int posZ = (int) tag.get("z").getValue(); - 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: - // North - z += 0.24f; - break; - case 0: - // South - z -= 0.24f; - break; - case 90: - // West - x += 0.24f; - break; - case 270: - // East - x -= 0.24f; - break; - } - } else { - rotation = (180f + (floorRotation * 22.5f)) % 360; - } - - Vector3i blockPosition = Vector3i.from(posX, posY, posZ); - Vector3f entityPosition = Vector3f.from(x, y, z); - Vector3f entityRotation = Vector3f.from(rotation, 0, rotation); - long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); - - getProfile(tag).whenComplete((gameProfile, throwable) -> { - if (gameProfile == null) { - session.getConnector().getLogger().debug("Custom skull with invalid SkullOwner tag: " + blockPosition.toString() + " " + tag.toString()); - return; - } - - SkullPlayerEntity existingSkull = session.getSkullCache().get(blockPosition); - if (existingSkull != null) { - // Ensure that two skulls can't spawn on the same point - existingSkull.despawnEntity(session, blockPosition); - } - - SkullPlayerEntity player = new SkullPlayerEntity(gameProfile, geyserId, entityPosition, entityRotation); - player.setBlockState(blockState); - - // Cache entity - session.getSkullCache().put(blockPosition, player); - - // Only send to session if we are initialized, otherwise it will happen then. - if (session.getUpstream().isInitialized()) { - player.spawnEntity(session); - - SkullSkinManager.requestAndHandleSkin(player, session, (skin -> session.getConnector().getGeneralThreadPool().schedule(() -> { - // Delay to minimize split-second "player" pop-in - player.getMetadata().getFlags().setFlag(EntityFlag.INVISIBLE, false); - player.updateBedrockMetadata(session); - }, 250, TimeUnit.MILLISECONDS))); - } - }); - } -} +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.world.block.entity; + +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.ByteTag; +import com.nukkitx.nbt.tag.CompoundTag; +import com.nukkitx.nbt.tag.FloatTag; +import com.nukkitx.nbt.tag.Tag; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; + +import java.util.ArrayList; +import java.util.List; + +@BlockEntity(name = "Skull", regex = "skull") +public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + + @Override + public boolean isBlock(BlockState blockState) { + return BlockStateValues.getSkullVariant(blockState) != -1; + } + + @Override + public List> translateTag(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); + byte skullVariant = BlockStateValues.getSkullVariant(blockState); + float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f; + // Just in case... + if (skullVariant == -1) skullVariant = 0; + tags.add(new FloatTag("Rotation", rotation)); + tags.add(new ByteTag("SkullType", skullVariant)); + return tags; + } + + @Override + public com.github.steveice10.opennbt.tag.builtin.CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.floatTag("Rotation", 0); + tagBuilder.byteTag("SkullType", (byte) 0); + return tagBuilder.buildRootTag(); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java index 5a6f974b..100dbddd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/SpawnerBlockEntityTranslator.java @@ -1,83 +1,105 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.Tag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.*; import org.geysermc.connector.entity.type.EntityType; +import java.util.ArrayList; +import java.util.List; + @BlockEntity(name = "MobSpawner", regex = "mob_spawner") public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - Tag current; + public List> translateTag(CompoundTag tag, BlockState blockState) { + List> tags = new ArrayList<>(); - if ((current = tag.get("MaxNearbyEntities")) != null) { - builder.put("MaxNearbyEntities", current.getValue()); + if (tag.get("MaxNearbyEntities") != null) { + tags.add(new ShortTag("MaxNearbyEntities", (short) tag.get("MaxNearbyEntities").getValue())); } - if ((current = tag.get("RequiredPlayerRange")) != null) { - builder.put("RequiredPlayerRange", current.getValue()); + if (tag.get("RequiredPlayerRange") != null) { + tags.add(new ShortTag("RequiredPlayerRange", (short) tag.get("RequiredPlayerRange").getValue())); } - if ((current = tag.get("SpawnCount")) != null) { - builder.put("SpawnCount", current.getValue()); + if (tag.get("SpawnCount") != null) { + tags.add(new ShortTag("SpawnCount", (short) tag.get("SpawnCount").getValue())); } - if ((current = tag.get("MaxSpawnDelay")) != null) { - builder.put("MaxSpawnDelay", current.getValue()); + if (tag.get("MaxSpawnDelay") != null) { + tags.add(new ShortTag("MaxSpawnDelay", (short) tag.get("MaxSpawnDelay").getValue())); } - if ((current = tag.get("Delay")) != null) { - builder.put("Delay", current.getValue()); + if (tag.get("Delay") != null) { + tags.add(new ShortTag("Delay", (short) tag.get("Delay").getValue())); } - if ((current = tag.get("SpawnRange")) != null) { - builder.put("SpawnRange", current.getValue()); + if (tag.get("SpawnRange") != null) { + tags.add(new ShortTag("SpawnRange", (short) tag.get("SpawnRange").getValue())); } - if ((current = tag.get("MinSpawnDelay")) != null) { - builder.put("MinSpawnDelay", current.getValue()); + if (tag.get("MinSpawnDelay") != null) { + tags.add(new ShortTag("MinSpawnDelay", (short) tag.get("MinSpawnDelay").getValue())); } - CompoundTag spawnData = tag.get("SpawnData"); - if (spawnData != null) { + if (tag.get("SpawnData") != null) { + CompoundTag spawnData = tag.get("SpawnData"); String entityID = (String) spawnData.get("id").getValue(); - builder.put("EntityIdentifier", entityID); + tags.add(new StringTag("EntityIdentifier", entityID)); EntityType type = EntityType.getFromIdentifier(entityID); if (type != null) { - builder.put("DisplayEntityWidth", type.getWidth()); - builder.put("DisplayEntityHeight", type.getHeight()); - builder.put("DisplayEntityScale", 1.0f); + tags.add(new FloatTag("DisplayEntityWidth", type.getWidth())); + tags.add(new FloatTag("DisplayEntityHeight", type.getHeight())); + tags.add(new FloatTag("DisplayEntityScale", 1.0f)); } } - builder.put("id", "MobSpawner"); - builder.put("isMovable", (byte) 1); + tags.add(new StringTag("id", "MobSpawner")); + tags.add(new ByteTag("isMovable", (byte) 1)); + + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public com.nukkitx.nbt.tag.CompoundTag getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + CompoundTagBuilder tagBuilder = getConstantBedrockTag(bedrockId, x, y, z).toBuilder(); + tagBuilder.byteTag("isMovable", (byte) 1) + .stringTag("id", "MobSpawner"); + + return tagBuilder.buildRootTag(); } } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/BlockStorage.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/BlockStorage.java index 7a508624..5995ecf9 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/BlockStorage.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/BlockStorage.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk; @@ -29,17 +30,14 @@ import com.nukkitx.network.VarInts; import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; -import lombok.Getter; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray; import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion; import java.util.function.IntConsumer; -@Getter public class BlockStorage { - public static final int SIZE = 4096; + private static final int SIZE = 4096; private final IntList palette; private BitArray bitArray; @@ -49,12 +47,12 @@ public class BlockStorage { } public BlockStorage(BitArrayVersion version) { - this.bitArray = version.createArray(SIZE); + this.bitArray = version.createPalette(SIZE); this.palette = new IntArrayList(16); - this.palette.add(BlockTranslator.BEDROCK_AIR_ID); // Air is at the start of every palette and controls what the default block is in second-layer non-air block spaces. + this.palette.add(0); // Air is at the start of every palette. } - public BlockStorage(BitArray bitArray, IntList palette) { + private BlockStorage(BitArray bitArray, IntArrayList palette) { this.palette = palette; this.bitArray = bitArray; } @@ -67,16 +65,16 @@ public class BlockStorage { return BitArrayVersion.get(header >> 1, true); } - public int getFullBlock(int index) { + public synchronized int getFullBlock(int index) { return this.palette.getInt(this.bitArray.get(index)); } - public void setFullBlock(int index, int runtimeId) { + public synchronized void setFullBlock(int index, int runtimeId) { int idx = this.idFor(runtimeId); this.bitArray.set(index, idx); } - public void writeToNetwork(ByteBuf buffer) { + public synchronized void writeToNetwork(ByteBuf buffer) { buffer.writeByte(getPaletteHeader(bitArray.getVersion(), true)); for (int word : bitArray.getWords()) { @@ -87,18 +85,8 @@ public class BlockStorage { palette.forEach((IntConsumer) id -> VarInts.writeInt(buffer, id)); } - public int estimateNetworkSize() { - int size = 1; // Palette header - size += this.bitArray.getWords().length * 4; - - // We assume that none of the VarInts will be larger than 3 bytes - size += 3; // Palette size - size += this.palette.size() * 3; - return size; - } - private void onResize(BitArrayVersion version) { - BitArray newBitArray = version.createArray(SIZE); + BitArray newBitArray = version.createPalette(SIZE); for (int i = 0; i < SIZE; i++) { newBitArray.set(i, this.bitArray.get(i)); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkPosition.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkPosition.java new file mode 100644 index 00000000..a51755d0 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkPosition.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.network.translators.world.chunk; + +import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@EqualsAndHashCode +public class ChunkPosition { + + private int x; + private int z; + + public Position getBlock(int x, int y, int z) { + return new Position((this.x << 4) + x, y, (this.z << 4) + z); + } + + public Position getChunkBlock(int x, int y, int z) { + int chunkX = x & 15; + int chunkY = y & 15; + int chunkZ = z & 15; + return new Position(chunkX, chunkY, chunkZ); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkSection.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkSection.java index 2709e3e2..4ede0c25 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkSection.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkSection.java @@ -1,45 +1,69 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk; import com.nukkitx.network.util.Preconditions; import io.netty.buffer.ByteBuf; +import lombok.Synchronized; public class ChunkSection { private static final int CHUNK_SECTION_VERSION = 8; + public static final int SIZE = 4096; private final BlockStorage[] storage; + private final NibbleArray blockLight; + private final NibbleArray skyLight; public ChunkSection() { - this(new BlockStorage[]{new BlockStorage(), new BlockStorage()}); + this(new BlockStorage[]{new BlockStorage(), new BlockStorage()}, new NibbleArray(SIZE), + new NibbleArray(SIZE)); } - public ChunkSection(BlockStorage[] storage) { + public ChunkSection(BlockStorage[] blockStorage) { + this(blockStorage, new NibbleArray(SIZE), new NibbleArray(SIZE)); + } + + public ChunkSection(BlockStorage[] storage, byte[] blockLight, byte[] skyLight) { + Preconditions.checkNotNull(storage, "storage"); + Preconditions.checkArgument(storage.length > 1, "Block storage length must be at least 2"); + for (BlockStorage blockStorage : storage) { + Preconditions.checkNotNull(blockStorage, "storage"); + } + this.storage = storage; + this.blockLight = new NibbleArray(blockLight); + this.skyLight = new NibbleArray(skyLight); + } + + private ChunkSection(BlockStorage[] storage, NibbleArray blockLight, NibbleArray skyLight) { + this.storage = storage; + this.blockLight = blockLight; + this.skyLight = skyLight; } public int getFullBlock(int x, int y, int z, int layer) { @@ -54,6 +78,30 @@ public class ChunkSection { this.storage[layer].setFullBlock(blockPosition(x, y, z), fullBlock); } + @Synchronized("skyLight") + public byte getSkyLight(int x, int y, int z) { + checkBounds(x, y, z); + return this.skyLight.get(blockPosition(x, y, z)); + } + + @Synchronized("skyLight") + public void setSkyLight(int x, int y, int z, byte val) { + checkBounds(x, y, z); + this.skyLight.set(blockPosition(x, y, z), val); + } + + @Synchronized("blockLight") + public byte getBlockLight(int x, int y, int z) { + checkBounds(x, y, z); + return this.blockLight.get(blockPosition(x, y, z)); + } + + @Synchronized("blockLight") + public void setBlockLight(int x, int y, int z, byte val) { + checkBounds(x, y, z); + this.blockLight.set(blockPosition(x, y, z), val); + } + public void writeToNetwork(ByteBuf buffer) { buffer.writeByte(CHUNK_SECTION_VERSION); buffer.writeByte(this.storage.length); @@ -62,12 +110,12 @@ public class ChunkSection { } } - public int estimateNetworkSize() { - int size = 2; // Version + storage count - for (BlockStorage blockStorage : this.storage) { - size += blockStorage.estimateNetworkSize(); - } - return size; + public NibbleArray getSkyLightArray() { + return skyLight; + } + + public NibbleArray getBlockLightArray() { + return blockLight; } public BlockStorage[] getBlockStorageArray() { @@ -88,7 +136,7 @@ public class ChunkSection { for (int i = 0; i < storage.length; i++) { storage[i] = this.storage[i].copy(); } - return new ChunkSection(storage); + return new ChunkSection(storage, skyLight.copy(), blockLight.copy()); } public static int blockPosition(int x, int y, int z) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/NibbleArray.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/NibbleArray.java index f028af80..08303e18 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/NibbleArray.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/NibbleArray.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArray.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArray.java index 5c278eb9..728fe237 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArray.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArray.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk.bitarray; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArrayVersion.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArrayVersion.java index f45e9f6b..be91f13d 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArrayVersion.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArrayVersion.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk.bitarray; @@ -37,8 +38,6 @@ public enum BitArrayVersion { V2(2, 16, V3), V1(1, 32, V2); - private static final BitArrayVersion[] VALUES = values(); - final byte bits; final byte entriesPerWord; final int maxEntryValue; @@ -60,14 +59,8 @@ public enum BitArrayVersion { throw new IllegalArgumentException("Invalid palette version: " + version); } - public static BitArrayVersion forBitsCeil(int bits) { - for (int i = VALUES.length - 1; i >= 0; i--) { - BitArrayVersion version = VALUES[i]; - if (version.bits >= bits) { - return version; - } - } - return null; + public BitArray createPalette(int size) { + return this.createPalette(size, new int[MathUtils.ceil((float) size / entriesPerWord)]); } public byte getId() { @@ -86,11 +79,7 @@ public enum BitArrayVersion { return next; } - public BitArray createArray(int size) { - return this.createArray(size, new int[MathUtils.ceil((float) size / entriesPerWord)]); - } - - public BitArray createArray(int size, int[] words) { + public BitArray createPalette(int size, int[] words) { if (this == V3 || this == V5 || this == V6) { // Padded palettes aren't able to use bitwise operations due to their padding. return new PaddedBitArray(this, size, words); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/PaddedBitArray.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/PaddedBitArray.java index b770d0dc..36a97a30 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/PaddedBitArray.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/PaddedBitArray.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk.bitarray; diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/Pow2BitArray.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/Pow2BitArray.java index 1a784b7f..c9bd2764 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/Pow2BitArray.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/Pow2BitArray.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.network.translators.world.chunk.bitarray; diff --git a/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java index a8af51bf..ea0d67c2 100644 --- a/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java +++ b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java @@ -1,45 +1,42 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.ping; -import com.fasterxml.jackson.core.JsonParseException; -import com.fasterxml.jackson.databind.JsonMappingException; import com.github.steveice10.mc.protocol.MinecraftConstants; -import com.nukkitx.nbt.util.VarInts; -import org.geysermc.connector.common.ping.GeyserPingInfo; +import com.github.steveice10.mc.protocol.MinecraftProtocol; +import com.github.steveice10.mc.protocol.data.SubProtocol; +import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoHandler; +import com.github.steveice10.packetlib.Client; +import com.github.steveice10.packetlib.tcp.TcpSessionFactory; +import org.geysermc.common.ping.GeyserPingInfo; +import org.geysermc.connector.GeyserConfiguration; import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.GeyserLogger; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketTimeoutException; import java.util.concurrent.TimeUnit; public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runnable { @@ -48,10 +45,13 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn public GeyserLegacyPingPassthrough(GeyserConnector connector) { this.connector = connector; + this.pingInfo = new GeyserPingInfo(null, 0, 0); } private GeyserPingInfo pingInfo; + private Client client; + /** * Start legacy ping passthrough thread * @param connector GeyserConnector @@ -70,60 +70,22 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn } @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + public GeyserPingInfo getPingInformation() { return pingInfo; } @Override public void run() { try { - Socket socket = new Socket(); - String address = connector.getConfig().getRemote().getAddress(); - int port = connector.getConfig().getRemote().getPort(); - socket.connect(new InetSocketAddress(address, port), 5000); + this.client = new Client(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort(), new MinecraftProtocol(SubProtocol.STATUS), new TcpSessionFactory()); + this.client.getSession().setFlag(MinecraftConstants.SERVER_INFO_HANDLER_KEY, (ServerInfoHandler) (session, info) -> { + this.pingInfo = new GeyserPingInfo(info.getDescription().getFullText(), info.getPlayerInfo().getOnlinePlayers(), info.getPlayerInfo().getMaxPlayers()); + this.client.getSession().disconnect(null); + }); - ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); - DataOutputStream handshake = new DataOutputStream(byteArrayStream); - handshake.write(0x0); - VarInts.writeUnsignedInt(handshake, MinecraftConstants.PROTOCOL_VERSION); - VarInts.writeUnsignedInt(handshake, address.length()); - handshake.writeBytes(address); - handshake.writeShort(port); - VarInts.writeUnsignedInt(handshake, 1); - - DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream()); - VarInts.writeUnsignedInt(dataOutputStream, byteArrayStream.size()); - dataOutputStream.write(byteArrayStream.toByteArray()); - dataOutputStream.writeByte(0x01); - dataOutputStream.writeByte(0x00); - - DataInputStream dataInputStream = new DataInputStream(socket.getInputStream()); - VarInts.readUnsignedInt(dataInputStream); - VarInts.readUnsignedInt(dataInputStream); - int length = VarInts.readUnsignedInt(dataInputStream); - byte[] buffer = new byte[length]; - dataInputStream.readFully(buffer); - dataOutputStream.writeByte(0x09); - dataOutputStream.writeByte(0x01); - dataOutputStream.writeLong(System.currentTimeMillis()); - - VarInts.readUnsignedInt(dataInputStream); - String json = new String(buffer); - - this.pingInfo = GeyserConnector.JSON_MAPPER.readValue(json, GeyserPingInfo.class); - - byteArrayStream.close(); - handshake.close(); - dataOutputStream.close(); - dataInputStream.close(); - socket.close(); - } catch (SocketTimeoutException | ConnectException ex) { - this.pingInfo = null; - this.connector.getLogger().debug("Connection timeout for ping passthrough."); - } catch (JsonParseException | JsonMappingException ex) { - this.connector.getLogger().error("Failed to parse json when pinging server!", ex); - } catch (IOException e) { - e.printStackTrace(); + client.getSession().connect(); + } catch (Exception ex) { + ex.printStackTrace(); } } } diff --git a/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java b/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java index 2ca0ea9c..7bc842df 100644 --- a/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java +++ b/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java @@ -1,55 +1,42 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.ping; -import org.geysermc.connector.common.ping.GeyserPingInfo; - -import java.net.Inet4Address; -import java.net.InetSocketAddress; +import org.geysermc.common.ping.GeyserPingInfo; /** * Interface that retrieves ping passthrough information from the Java server */ public interface IGeyserPingPassthrough { - /** - * Get the MOTD of the server displayed on the multiplayer screen. It uses a fake remote, as the remote isn't important in this context. - * - * @return string of the MOTD - */ - default GeyserPingInfo getPingInformation() { - return this.getPingInformation(new InetSocketAddress(Inet4Address.getLoopbackAddress(), 69)); - } - /** * Get the MOTD of the server displayed on the multiplayer screen - * - * @param inetSocketAddress the ip address of the client pinging the server * @return string of the MOTD */ - GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress); + GeyserPingInfo getPingInformation(); } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Objective.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Objective.java index f4b89535..c3e6c863 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Objective.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Objective.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,25 +29,23 @@ import com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardPosition import lombok.Getter; import lombok.Setter; +import java.util.HashMap; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; @Getter -public final class Objective { - private final Scoreboard scoreboard; - private final long id; - private boolean active = true; +public class Objective { + private Scoreboard scoreboard; + private long id; + private boolean temp; @Setter private UpdateType updateType = UpdateType.ADD; - private String objectiveName; - private ScoreboardPosition displaySlot; - private String displaySlotName; + private String displaySlot; private String displayName = "unknown"; private int type = 0; // 0 = integer, 1 = heart - private Map scores = new ConcurrentHashMap<>(); + private Map scores = new HashMap<>(); private Objective(Scoreboard scoreboard) { this.id = scoreboard.getNextId().getAndIncrement(); @@ -56,107 +54,96 @@ public final class Objective { /** * /!\ This method is made for temporary objectives until the real objective is received - * - * @param scoreboard the scoreboard + * @param scoreboard the scoreboard * @param objectiveName the name of the objective */ public Objective(Scoreboard scoreboard, String objectiveName) { this(scoreboard); this.objectiveName = objectiveName; - this.active = false; + this.temp = true; } public Objective(Scoreboard scoreboard, String objectiveName, ScoreboardPosition displaySlot, String displayName, int type) { + this(scoreboard, objectiveName, displaySlot.name().toLowerCase(), displayName, type); + } + + public Objective(Scoreboard scoreboard, String objectiveName, String displaySlot, String displayName, int type) { this(scoreboard); this.objectiveName = objectiveName; - this.displaySlot = correctDisplaySlot(displaySlot); - this.displaySlotName = translateDisplaySlot(displaySlot); + this.displaySlot = displaySlot; this.displayName = displayName; this.type = type; } - private static String translateDisplaySlot(ScoreboardPosition displaySlot) { - switch (displaySlot) { - case BELOW_NAME: - return "belowname"; - case PLAYER_LIST: - return "list"; - default: - return "sidebar"; - } - } - - private static ScoreboardPosition correctDisplaySlot(ScoreboardPosition displaySlot) { - switch (displaySlot) { - case BELOW_NAME: - return ScoreboardPosition.BELOW_NAME; - case PLAYER_LIST: - return ScoreboardPosition.PLAYER_LIST; - default: - return ScoreboardPosition.SIDEBAR; - } - } - public void registerScore(String id, int score) { if (!scores.containsKey(id)) { - long scoreId = scoreboard.getNextId().getAndIncrement(); - Score scoreObject = new Score(scoreId, id) + Score score1 = new Score(this, id) .setScore(score) - .setTeam(scoreboard.getTeamFor(id)) - .setUpdateType(UpdateType.ADD); - scores.put(id, scoreObject); + .setTeam(scoreboard.getTeamFor(id)); + scores.put(id, score1); } } public void setScore(String id, int score) { - Score stored = scores.get(id); - if (stored != null) { - stored.setScore(score) - .setUpdateType(UpdateType.UPDATE); - return; + if (scores.containsKey(id)) { + scores.get(id).setScore(score).setUpdateType(UpdateType.ADD); + } else { + registerScore(id, score); + } + } + + public void setScoreText(String oldText, String newText) { + if (!scores.containsKey(oldText) || oldText.equals(newText)) return; + Score oldScore = scores.get(oldText); + + Score newScore = new Score(this, newText) + .setScore(oldScore.getScore()) + .setTeam(scoreboard.getTeamFor(newText)); + + scores.put(newText, newScore); + oldScore.setUpdateType(UpdateType.REMOVE); + } + + public int getScore(String id) { + if (scores.containsKey(id)) { + return scores.get(id).getScore(); + } + return 0; + } + + public Score getScore(int line) { + for (Score score : scores.values()) { + if (score.getScore() == line) return score; + } + return null; + } + + public void resetScore(String id) { + if (scores.containsKey(id)) { + scores.get(id).setUpdateType(UpdateType.REMOVE); } - registerScore(id, score); } public void removeScore(String id) { - Score stored = scores.get(id); - if (stored != null) { - stored.setUpdateType(UpdateType.REMOVE); - } - } - - /** - * Used internally to remove a score from the score map - */ - public void removeScore0(String id) { scores.remove(id); } public Objective setDisplayName(String displayName) { this.displayName = displayName; - if (updateType == UpdateType.NOTHING) { - updateType = UpdateType.UPDATE; - } + if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE; return this; } public Objective setType(int type) { this.type = type; - if (updateType == UpdateType.NOTHING) { - updateType = UpdateType.UPDATE; - } + if (updateType == UpdateType.NOTHING) updateType = UpdateType.UPDATE; return this; } - public void setActive(ScoreboardPosition displaySlot) { - if (!active) { - active = true; - this.displaySlot = correctDisplaySlot(displaySlot); - displaySlotName = translateDisplaySlot(displaySlot); + public void removeTemp(ScoreboardPosition displaySlot) { + if (temp) { + temp = false; + this.displaySlot = displaySlot.name().toLowerCase(); } } - - public void removed() { - scores = null; - } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java index 79c90b09..d5a65e8c 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Score.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,115 +25,40 @@ package org.geysermc.connector.scoreboard; -import com.nukkitx.protocol.bedrock.data.ScoreInfo; import lombok.Getter; +import lombok.Setter; import lombok.experimental.Accessors; -@Getter +@Getter @Setter @Accessors(chain = true) -public final class Score { - private final long id; - private final String name; - private ScoreInfo cachedInfo; +public class Score { + private Objective objective; + private long id; - /** - * Changes that have been made since the last cached data. - */ - private Score.ScoreData currentData; - /** - * The data that is currently displayed to the Bedrock client. - */ - private Score.ScoreData cachedData; + private UpdateType updateType = UpdateType.ADD; + private String name; + private Team team; + private int score; + private int oldScore = Integer.MIN_VALUE; - public Score(long id, String name) { - this.id = id; + public Score(Objective objective, String name) { + this.id = objective.getScoreboard().getNextId().getAndIncrement(); + this.objective = objective; this.name = name; - this.currentData = new ScoreData(); } public String getDisplayName() { - Team team = cachedData.team; - if (team != null) { - return team.getDisplayName(name); + if (team != null && team.getUpdateType() != UpdateType.REMOVE) { + return team.getPrefix() + name + team.getSuffix(); } return name; } public Score setScore(int score) { - currentData.score = score; + if (oldScore == Integer.MIN_VALUE) { + this.oldScore = score; + } + this.score = score; return this; } - - public Team getTeam() { - return currentData.team; - } - - public Score setTeam(Team team) { - if (currentData.team != null && team != null) { - if (!currentData.team.equals(team)) { - currentData.team = team; - currentData.updateType = UpdateType.UPDATE; - } - return this; - } - // simplified from (this.team != null && team == null) || (this.team == null && team != null) - if (currentData.team != null || team != null) { - currentData.team = team; - currentData.updateType = UpdateType.UPDATE; - } - return this; - } - - public UpdateType getUpdateType() { - return currentData.updateType; - } - - public Score setUpdateType(UpdateType updateType) { - if (updateType != UpdateType.NOTHING) { - currentData.updateTime = System.currentTimeMillis(); - } - currentData.updateType = updateType; - return this; - } - - public boolean shouldUpdate() { - return cachedData == null || currentData.updateTime > cachedData.updateTime || - (currentData.team != null && currentData.team.shouldUpdate()); - } - - public void update(String objectiveName) { - if (cachedData == null) { - cachedData = new ScoreData(); - cachedData.updateType = UpdateType.ADD; - if (currentData.updateType == UpdateType.REMOVE) { - cachedData.updateType = UpdateType.REMOVE; - } - } else { - cachedData.updateType = currentData.updateType; - } - - cachedData.updateTime = currentData.updateTime; - cachedData.team = currentData.team; - cachedData.score = currentData.score; - - String name = this.name; - if (cachedData.team != null) { - cachedData.team.prepareUpdate(); - name = cachedData.team.getDisplayName(name); - } - cachedInfo = new ScoreInfo(id, objectiveName, cachedData.score, name); - } - - @Getter - public static final class ScoreData { - protected UpdateType updateType; - protected long updateTime; - - private Team team; - private int score; - - protected ScoreData() { - updateType = UpdateType.ADD; - } - } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java index f3d43570..59d9b25f 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Scoreboard.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,82 +30,68 @@ import com.nukkitx.protocol.bedrock.data.ScoreInfo; import com.nukkitx.protocol.bedrock.packet.RemoveObjectivePacket; import com.nukkitx.protocol.bedrock.packet.SetDisplayObjectivePacket; import com.nukkitx.protocol.bedrock.packet.SetScorePacket; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import lombok.Getter; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.GeyserLogger; + import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; import java.util.*; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import static org.geysermc.connector.scoreboard.UpdateType.*; @Getter -public final class Scoreboard { - private final GeyserSession session; - private final GeyserLogger logger; - private final AtomicLong nextId = new AtomicLong(0); +public class Scoreboard { + private GeyserSession session; + private AtomicLong nextId = new AtomicLong(0); - private final Map objectives = new ConcurrentHashMap<>(); - private final Map teams = new HashMap<>(); - - private int lastAddScoreCount = 0; - private int lastRemoveScoreCount = 0; + private Map objectives = new HashMap<>(); + private Map teams = new HashMap<>(); public Scoreboard(GeyserSession session) { this.session = session; - this.logger = GeyserConnector.getInstance().getLogger(); } - public Objective registerNewObjective(String objectiveId, boolean active) { - Objective objective = objectives.get(objectiveId); - if (active || objective != null) { - return objective; - } - objective = new Objective(this, objectiveId); + public Objective registerNewObjective(String objectiveId, boolean temp) { + if (!temp || objectives.containsKey(objectiveId)) return objectives.get(objectiveId); + Objective objective = new Objective(this, objectiveId); objectives.put(objectiveId, objective); return objective; } - public Objective displayObjective(String objectiveId, ScoreboardPosition displaySlot) { - Objective objective = objectives.get(objectiveId); - if (objective != null) { - if (!objective.isActive()) { - objective.setActive(displaySlot); - removeOldObjectives(objective); - return objective; + public Objective registerNewObjective(String objectiveId, ScoreboardPosition displaySlot) { + Objective objective = null; + if (objectives.containsKey(objectiveId)) { + objective = objectives.get(objectiveId); + if (objective.isTemp()) objective.removeTemp(displaySlot); + else { + despawnObjective(objective); + objective = null; } - despawnObjective(objective); } - - objective = new Objective(this, objectiveId, displaySlot, "unknown", 0); - objectives.put(objectiveId, objective); - removeOldObjectives(objective); + if (objective == null) { + objective = new Objective(this, objectiveId, displaySlot, "unknown", 0); + objectives.put(objectiveId, objective); + } return objective; } - private void removeOldObjectives(Objective newObjective) { - for (Objective next : objectives.values()) { - if (next.getId() == newObjective.getId()) { - continue; - } - if (next.getDisplaySlot() == newObjective.getDisplaySlot()) { - next.setUpdateType(REMOVE); - } - } - } - public Team registerNewTeam(String teamName, Set players) { - Team team = teams.get(teamName); - if (team != null) { - logger.info(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName)); - return team; + if (teams.containsKey(teamName)) { + session.getConnector().getLogger().info("Ignoring team " + teamName + ". It overrides without removing old team."); + return getTeam(teamName); } - team = new Team(this, teamName).addEntities(players); + Team team = new Team(this, teamName).setEntities(players); teams.put(teamName, team); + + for (Objective objective : objectives.values()) { + for (Score score : objective.getScores().values()) { + if (players.contains(score.getName())) { + score.setTeam(team); + } + } + } return team; } @@ -119,136 +105,105 @@ public final class Scoreboard { public void unregisterObjective(String objectiveName) { Objective objective = getObjective(objectiveName); - if (objective != null) { - objective.setUpdateType(REMOVE); - } + if (objective != null) objective.setUpdateType(REMOVE); } public void removeTeam(String teamName) { Team remove = teams.remove(teamName); - if (remove != null) { - remove.setUpdateType(REMOVE); - } + if (remove != null) remove.setUpdateType(REMOVE); } public void onUpdate() { - List addScores = new ArrayList<>(getLastAddScoreCount()); - List removeScores = new ArrayList<>(getLastRemoveScoreCount()); - List removedObjectives = new ArrayList<>(); + Set changedObjectives = new ObjectOpenHashSet<>(); + List addScores = new ArrayList<>(); + List removeScores = new ArrayList<>(); - for (Objective objective : objectives.values()) { - if (!objective.isActive()) { - logger.debug("Ignoring non-active Scoreboard Objective '" + objective.getObjectiveName() + '\''); + for (String objectiveId : new ArrayList<>(objectives.keySet())) { + Objective objective = objectives.get(objectiveId); + if (objective.isTemp()) { + session.getConnector().getLogger().debug("Ignoring temp Scoreboard Objective '"+ objectiveId +'\''); continue; } - // hearts can't hold teams, so we treat them differently - if (objective.getType() == 1) { - for (Score score : objective.getScores().values()) { - boolean update = score.shouldUpdate(); + if (objective.getUpdateType() != NOTHING) changedObjectives.add(objective); - if (update) { - score.update(objective.getObjectiveName()); - } + boolean globalUpdate = objective.getUpdateType() == UPDATE; + boolean globalAdd = objective.getUpdateType() == ADD || globalUpdate; + boolean globalRemove = objective.getUpdateType() == REMOVE || globalUpdate; - if (score.getUpdateType() != REMOVE && update) { - addScores.add(score.getCachedInfo()); - } - if (score.getUpdateType() != ADD && update) { - removeScores.add(score.getCachedInfo()); - } - } - continue; - } + boolean hasUpdate = globalUpdate; - boolean objectiveUpdate = objective.getUpdateType() == UPDATE; - boolean objectiveAdd = objective.getUpdateType() == ADD; - boolean objectiveRemove = objective.getUpdateType() == REMOVE; - - for (Score score : objective.getScores().values()) { + List handledScores = new ArrayList<>(); + for (String identifier : new ObjectOpenHashSet<>(objective.getScores().keySet())) { + Score score = objective.getScores().get(identifier); Team team = score.getTeam(); - boolean add = objectiveAdd || objectiveUpdate; - boolean remove = false; - if (team != null) { - if (team.getUpdateType() == REMOVE || !team.hasEntity(score.getName())) { - score.setTeam(null); - add = true; - remove = true; + boolean inTeam = team != null && team.getEntities().contains(score.getName()); + + boolean teamAdd = team != null && (team.getUpdateType() == ADD || team.getUpdateType() == UPDATE); + boolean teamRemove = team != null && (team.getUpdateType() == REMOVE || team.getUpdateType() == UPDATE); + + if (team != null && (team.getUpdateType() == REMOVE || !inTeam)) score.setTeam(null); + + boolean add = (hasUpdate || globalAdd || teamAdd || teamRemove || score.getUpdateType() == ADD || score.getUpdateType() == UPDATE) && (score.getUpdateType() != REMOVE); + boolean remove = hasUpdate || globalRemove || teamAdd || teamRemove || score.getUpdateType() == REMOVE || score.getUpdateType() == UPDATE; + + boolean updated = false; + if (!hasUpdate) { + updated = hasUpdate = add; + } + + if (updated) { + for (Score score1 : handledScores) { + ScoreInfo scoreInfo = new ScoreInfo(score1.getId(), score1.getObjective().getObjectiveName(), score1.getScore(), score1.getDisplayName()); + addScores.add(scoreInfo); + removeScores.add(scoreInfo); } } - add |= score.shouldUpdate(); - remove |= score.shouldUpdate(); - - if (score.getUpdateType() == REMOVE || objectiveRemove) { - add = false; - } - - if (score.getUpdateType() == ADD || objectiveRemove) { - remove = false; - } - - if (objectiveRemove && score.getCachedData() != null) { - // This score has been sent to the client and needs to be removed since the objective is being removed - remove = true; - } else if (score.shouldUpdate()) { - score.update(objective.getObjectiveName()); - } - if (add) { - addScores.add(score.getCachedInfo()); + addScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getScore(), score.getDisplayName())); } - if (remove) { - removeScores.add(score.getCachedInfo()); + removeScores.add(new ScoreInfo(score.getId(), score.getObjective().getObjectiveName(), score.getOldScore(), score.getDisplayName())); } + score.setOldScore(score.getScore()); - // score is pending to be removed, so we can remove it from the objective if (score.getUpdateType() == REMOVE) { - objective.removeScore0(score.getName()); + objective.removeScore(score.getName()); } + if (add || remove) { + changedObjectives.add(objective); + } else { // stays the same like before + handledScores.add(score); + } score.setUpdateType(NOTHING); } + } - if (objectiveRemove) { - removedObjectives.add(objective); - } - - if (objectiveUpdate) { + for (Objective objective : changedObjectives) { + boolean update = objective.getUpdateType() == NOTHING || objective.getUpdateType() == UPDATE; + if (objective.getUpdateType() == REMOVE || update) { RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket(); removeObjectivePacket.setObjectiveId(objective.getObjectiveName()); session.sendUpstreamPacket(removeObjectivePacket); + if (objective.getUpdateType() == REMOVE) { + objectives.remove(objective.getObjectiveName()); // now we can deregister + } } - - if ((objectiveAdd || objectiveUpdate) && !objectiveRemove) { + if (objective.getUpdateType() == ADD || update) { SetDisplayObjectivePacket displayObjectivePacket = new SetDisplayObjectivePacket(); displayObjectivePacket.setObjectiveId(objective.getObjectiveName()); displayObjectivePacket.setDisplayName(objective.getDisplayName()); displayObjectivePacket.setCriteria("dummy"); - displayObjectivePacket.setDisplaySlot(objective.getDisplaySlotName()); + displayObjectivePacket.setDisplaySlot(objective.getDisplaySlot()); displayObjectivePacket.setSortOrder(1); // ?? session.sendUpstreamPacket(displayObjectivePacket); } - objective.setUpdateType(NOTHING); } - Iterator teamIterator = teams.values().iterator(); - while (teamIterator.hasNext()) { - Team current = teamIterator.next(); - - switch (current.getUpdateType()) { - case ADD: - case UPDATE: - current.markUpdated(); - break; - case REMOVE: - teamIterator.remove(); - } - } - if (!removeScores.isEmpty()) { SetScorePacket setScorePacket = new SetScorePacket(); setScorePacket.setAction(SetScorePacket.Action.REMOVE); @@ -262,28 +217,34 @@ public final class Scoreboard { setScorePacket.setInfos(addScores); session.sendUpstreamPacket(setScorePacket); } - - // prevents crashes in some cases - for (Objective objective : removedObjectives) { - despawnObjective(objective); - } - - lastAddScoreCount = addScores.size(); - lastRemoveScoreCount = removeScores.size(); } public void despawnObjective(Objective objective) { - objectives.remove(objective.getObjectiveName()); - objective.removed(); - RemoveObjectivePacket removeObjectivePacket = new RemoveObjectivePacket(); removeObjectivePacket.setObjectiveId(objective.getObjectiveName()); session.sendUpstreamPacket(removeObjectivePacket); + objectives.remove(objective.getDisplayName()); + + List toRemove = new ArrayList<>(); + for (String identifier : objective.getScores().keySet()) { + Score score = objective.getScores().get(identifier); + toRemove.add(new ScoreInfo( + score.getId(), score.getObjective().getObjectiveName(), + 0, "" + )); + } + + if (!toRemove.isEmpty()) { + SetScorePacket setScorePacket = new SetScorePacket(); + setScorePacket.setAction(SetScorePacket.Action.REMOVE); + setScorePacket.setInfos(toRemove); + session.sendUpstreamPacket(setScorePacket); + } } public Team getTeamFor(String entity) { for (Team team : teams.values()) { - if (team.hasEntity(entity)) { + if (team.getEntities().contains(entity)) { return team; } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/ScoreboardUpdater.java b/connector/src/main/java/org/geysermc/connector/scoreboard/ScoreboardUpdater.java deleted file mode 100644 index e5a80250..00000000 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/ScoreboardUpdater.java +++ /dev/null @@ -1,124 +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.connector.scoreboard; - -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.configuration.GeyserConfiguration; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.cache.WorldCache; -import org.geysermc.connector.utils.LanguageUtils; - -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - -public class ScoreboardUpdater extends Thread { - public static final int FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD; - public static final int SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD = 250; - - private static final int FIRST_MILLIS_BETWEEN_UPDATES = 250; // 4 updates per second - private static final int SECOND_MILLIS_BETWEEN_UPDATES = 1000 * 3; // 1 update per 3 seconds - - private static final boolean DEBUG_ENABLED; - - private final WorldCache worldCache; - private final GeyserSession session; - - private int millisBetweenUpdates = FIRST_MILLIS_BETWEEN_UPDATES; - private long lastUpdate = System.currentTimeMillis(); - private long lastLog = -1; - - private long lastPacketsPerSecondUpdate = System.currentTimeMillis(); - private final AtomicInteger packetsPerSecond = new AtomicInteger(0); - private final AtomicInteger pendingPacketsPerSecond = new AtomicInteger(0); - - public ScoreboardUpdater(WorldCache worldCache) { - super("Scoreboard Updater"); - this.worldCache = worldCache; - session = worldCache.getSession(); - } - - @Override - public void run() { - if (!session.isClosed()) { - long currentTime = System.currentTimeMillis(); - - // reset score-packets per second every second - if (currentTime - lastPacketsPerSecondUpdate > 1000) { - lastPacketsPerSecondUpdate = currentTime; - packetsPerSecond.set(pendingPacketsPerSecond.get()); - pendingPacketsPerSecond.set(0); - } - - if (currentTime - lastUpdate > millisBetweenUpdates) { - lastUpdate = currentTime; - - int pps = packetsPerSecond.get(); - if (pps >= FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD) { - boolean reachedSecondThreshold = pps >= SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD; - if (reachedSecondThreshold) { - millisBetweenUpdates = SECOND_MILLIS_BETWEEN_UPDATES; - } else { - millisBetweenUpdates = FIRST_MILLIS_BETWEEN_UPDATES; - } - - worldCache.getScoreboard().onUpdate(); - - if (DEBUG_ENABLED && (currentTime - lastLog > 60000)) { // one minute - int threshold = reachedSecondThreshold ? - SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD : - FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD; - - GeyserConnector.getInstance().getLogger().info( - LanguageUtils.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached.log", session.getName(), threshold, pps) + - LanguageUtils.getLocaleStringLog("geyser.scoreboard.updater.threshold_reached", (millisBetweenUpdates / 1000.0)) - ); - - lastLog = currentTime; - } - } - } - - session.getConnector().getGeneralThreadPool().schedule(this, 50, TimeUnit.MILLISECONDS); - } - } - - public int getPacketsPerSecond() { - return packetsPerSecond.get(); - } - - /** - * Increase the Scoreboard Packets Per Second and return the updated value - */ - public int incrementAndGetPacketsPerSecond() { - return pendingPacketsPerSecond.incrementAndGet(); - } - - static { - GeyserConfiguration config = GeyserConnector.getInstance().getConfig(); - FIRST_SCORE_PACKETS_PER_SECOND_THRESHOLD = Math.min(config.getScoreboardPacketThreshold(), SECOND_SCORE_PACKETS_PER_SECOND_THRESHOLD); - DEBUG_ENABLED = config.isDebugMode(); - } -} diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java b/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java index 9fe9f8cf..c2fcc02c 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/Team.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.scoreboard; -import com.github.steveice10.mc.protocol.data.game.scoreboard.NameTagVisibility; import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; -import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; @@ -38,182 +36,46 @@ import java.util.List; import java.util.Set; @Getter +@Setter @Accessors(chain = true) -public final class Team { +public class Team { private final Scoreboard scoreboard; private final String id; - @Getter(AccessLevel.NONE) - private final Set entities; - @Setter private NameTagVisibility nameTagVisibility; - @Setter private TeamColor color; - - private TeamData currentData; - private TeamData cachedData; - - private boolean updating; + private UpdateType updateType = UpdateType.ADD; + private String name; + private String prefix; + private TeamColor color; + private String suffix; + private Set entities = new ObjectOpenHashSet<>(); public Team(Scoreboard scoreboard, String id) { this.scoreboard = scoreboard; this.id = id; - currentData = new TeamData(); - entities = new ObjectOpenHashSet<>(); } - private void checkAddedEntities(List added) { - if (added.size() == 0) { - return; + public void addEntities(String... names) { + List added = new ArrayList<>(); + for (String name : names) { + if (!entities.contains(name)) { + entities.add(name); + added.add(name); + } } - // we don't have to change the updateType, - // because the scores itself need updating, not the team + setUpdateType(UpdateType.UPDATE); for (Objective objective : scoreboard.getObjectives().values()) { - for (String addedEntity : added) { - Score score = objective.getScores().get(addedEntity); - if (score != null) { + for (Score score : objective.getScores().values()) { + if (added.contains(score.getName())) { score.setTeam(this); } } } } - public Team addEntities(String... names) { - List added = new ArrayList<>(); - for (String name : names) { - if (entities.add(name)) { - added.add(name); - } - } - checkAddedEntities(added); - return this; - } - - public Team addEntities(Set names) { - List added = new ArrayList<>(); - for (String name : names) { - if (entities.add(name)) { - added.add(name); - } - } - checkAddedEntities(added); - return this; - } - public void removeEntities(String... names) { for (String name : names) { entities.remove(name); } - } - - public boolean hasEntity(String name) { - return entities.contains(name); - } - - public Team setName(String name) { - currentData.name = name; - return this; - } - - public Team setPrefix(String prefix) { - // replace "null" to an empty string, - // we do this here to improve the performance of Score#getDisplayName - if (prefix.length() == 4 && "null".equals(prefix)) { - currentData.prefix = ""; - return this; - } - currentData.prefix = prefix; - return this; - } - - public Team setSuffix(String suffix) { - // replace "null" to an empty string, - // we do this here to improve the performance of Score#getDisplayName - if (suffix.length() == 4 && "null".equals(suffix)) { - currentData.suffix = ""; - return this; - } - currentData.suffix = suffix; - return this; - } - - public String getDisplayName(String score) { - return cachedData != null ? - cachedData.getDisplayName(score) : - currentData.getDisplayName(score); - } - - public void markUpdated() { - updating = false; - } - - public boolean shouldUpdate() { - return updating || cachedData == null || currentData.updateTime > cachedData.updateTime; - } - - public void prepareUpdate() { - if (updating) { - return; - } - updating = true; - - if (cachedData == null) { - cachedData = new TeamData(); - cachedData.updateType = currentData.updateType != UpdateType.REMOVE ? UpdateType.ADD : UpdateType.REMOVE; - } else { - cachedData.updateType = currentData.updateType; - } - - cachedData.updateTime = currentData.updateTime; - cachedData.name = currentData.name; - cachedData.prefix = currentData.prefix; - cachedData.suffix = currentData.suffix; - } - - public UpdateType getUpdateType() { - return cachedData != null ? cachedData.updateType : currentData.updateType; - } - - public Team setUpdateType(UpdateType updateType) { - if (updateType != UpdateType.NOTHING) { - currentData.updateTime = System.currentTimeMillis(); - } - currentData.updateType = updateType; - return this; - } - - public boolean isVisibleFor(String entity) { - switch (nameTagVisibility) { - case HIDE_FOR_OTHER_TEAMS: - return hasEntity(entity); - case HIDE_FOR_OWN_TEAM: - return !hasEntity(entity); - case ALWAYS: - return true; - case NEVER: - return false; - } - return true; - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Getter - public static final class TeamData { - protected UpdateType updateType; - protected long updateTime; - - protected String name; - protected String prefix; - protected String suffix; - - protected TeamData() { - updateType = UpdateType.ADD; - } - - public String getDisplayName(String score) { - return prefix + score + suffix; - } + setUpdateType(UpdateType.UPDATE); } } diff --git a/connector/src/main/java/org/geysermc/connector/scoreboard/UpdateType.java b/connector/src/main/java/org/geysermc/connector/scoreboard/UpdateType.java index 5e645cd1..c7481df0 100644 --- a/connector/src/main/java/org/geysermc/connector/scoreboard/UpdateType.java +++ b/connector/src/main/java/org/geysermc/connector/scoreboard/UpdateType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java b/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java deleted file mode 100644 index b39e7f35..00000000 --- a/connector/src/main/java/org/geysermc/connector/skin/SkinManager.java +++ /dev/null @@ -1,280 +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.connector.skin; - -import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.auth.data.GameProfile; -import com.nukkitx.protocol.bedrock.data.skin.ImageData; -import com.nukkitx.protocol.bedrock.data.skin.SerializedSkin; -import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; -import lombok.AllArgsConstructor; -import lombok.Getter; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.AuthType; -import org.geysermc.connector.entity.player.PlayerEntity; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.session.auth.BedrockClientData; -import org.geysermc.connector.utils.LanguageUtils; - -import java.nio.charset.StandardCharsets; -import java.util.Base64; -import java.util.Collections; -import java.util.UUID; -import java.util.function.Consumer; - -public class SkinManager { - - public static PlayerListPacket.Entry buildCachedEntry(GeyserSession session, PlayerEntity playerEntity) { - GameProfileData data = GameProfileData.from(playerEntity.getProfile()); - SkinProvider.Cape cape = SkinProvider.getCachedCape(data.getCapeUrl()); - SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); - - SkinProvider.Skin skin = SkinProvider.getCachedSkin(data.getSkinUrl()); - if (skin == null) { - skin = SkinProvider.EMPTY_SKIN; - } - - return buildEntryManually( - session, - playerEntity.getProfile().getId(), - playerEntity.getProfile().getName(), - playerEntity.getGeyserId(), - skin.getTextureUrl(), - skin.getSkinData(), - cape.getCapeId(), - cape.getCapeData(), - geometry - ); - } - - public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, UUID uuid, String username, long geyserId, - String skinId, byte[] skinData, - String capeId, byte[] capeData, - SkinProvider.SkinGeometry geometry) { - SerializedSkin serializedSkin = SerializedSkin.of( - skinId, geometry.getGeometryName(), ImageData.of(skinData), Collections.emptyList(), - ImageData.of(capeData), geometry.getGeometryData(), "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, skinId - ); - - // This attempts to find the xuid of the player so profile images show up for xbox accounts - String xuid = ""; - GeyserSession player = GeyserConnector.getInstance().getPlayerByUuid(uuid); - - if (player != null) { - xuid = player.getAuthData().getXboxUUID(); - } - - PlayerListPacket.Entry entry; - - // If we are building a PlayerListEntry for our own session we use our AuthData UUID instead of the Java UUID - // as bedrock expects to get back its own provided uuid - if (session.getPlayerEntity().getUuid().equals(uuid)) { - entry = new PlayerListPacket.Entry(session.getAuthData().getUUID()); - } else { - entry = new PlayerListPacket.Entry(uuid); - } - - entry.setName(username); - entry.setEntityId(geyserId); - entry.setSkin(serializedSkin); - entry.setXuid(xuid); - entry.setPlatformChatId(""); - entry.setTeacher(false); - entry.setTrustedSkin(true); - return entry; - } - - public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session, - Consumer skinAndCapeConsumer) { - GameProfileData data = GameProfileData.from(entity.getProfile()); - - SkinProvider.requestSkinAndCape(entity.getUuid(), data.getSkinUrl(), data.getCapeUrl()) - .whenCompleteAsync((skinAndCape, throwable) -> { - try { - SkinProvider.Skin skin = skinAndCape.getSkin(); - SkinProvider.Cape cape = skinAndCape.getCape(); - SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); - - if (cape.isFailed()) { - cape = SkinProvider.getOrDefault(SkinProvider.requestBedrockCape(entity.getUuid()), - SkinProvider.EMPTY_CAPE, 3); - } - - if (cape.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_CAPES) { - cape = SkinProvider.getOrDefault(SkinProvider.requestUnofficialCape( - cape, entity.getUuid(), - entity.getUsername(), false - ), SkinProvider.EMPTY_CAPE, SkinProvider.CapeProvider.VALUES.length * 3); - } - - geometry = SkinProvider.getOrDefault(SkinProvider.requestBedrockGeometry( - geometry, entity.getUuid() - ), geometry, 3); - - // Not a bedrock player check for ears - if (geometry.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_EARS) { - boolean isEars; - - // Its deadmau5, gotta support his skin :) - if (entity.getUuid().toString().equals("1e18d5ff-643d-45c8-b509-43b8461d8614")) { - isEars = true; - } else { - // Get the ears texture for the player - skin = SkinProvider.getOrDefault(SkinProvider.requestUnofficialEars( - skin, entity.getUuid(), entity.getUsername(), false - ), skin, 3); - - isEars = skin.isEars(); - } - - // Does the skin have an ears texture - if (isEars) { - // Get the new geometry - geometry = SkinProvider.SkinGeometry.getEars(data.isAlex()); - - // Store the skin and geometry for the ears - SkinProvider.storeEarSkin(entity.getUuid(), skin); - SkinProvider.storeEarGeometry(entity.getUuid(), data.isAlex()); - } - } - - if (session.getUpstream().isInitialized()) { - PlayerListPacket.Entry updatedEntry = buildEntryManually( - session, - entity.getUuid(), - entity.getUsername(), - entity.getGeyserId(), - skin.getTextureUrl(), - skin.getSkinData(), - cape.getCapeId(), - cape.getCapeData(), - geometry - ); - - - PlayerListPacket playerAddPacket = new PlayerListPacket(); - playerAddPacket.setAction(PlayerListPacket.Action.ADD); - playerAddPacket.getEntries().add(updatedEntry); - session.sendUpstreamPacket(playerAddPacket); - - if (!entity.isPlayerList()) { - PlayerListPacket playerRemovePacket = new PlayerListPacket(); - playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE); - playerRemovePacket.getEntries().add(updatedEntry); - session.sendUpstreamPacket(playerRemovePacket); - - } - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e); - } - - if (skinAndCapeConsumer != null) { - skinAndCapeConsumer.accept(skinAndCape); - } - }); - } - - public static void handleBedrockSkin(PlayerEntity playerEntity, BedrockClientData clientData) { - GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.skin.bedrock.register", playerEntity.getUsername(), playerEntity.getUuid())); - - try { - byte[] skinBytes = Base64.getDecoder().decode(clientData.getSkinData().getBytes(StandardCharsets.UTF_8)); - byte[] capeBytes = clientData.getCapeData(); - - byte[] geometryNameBytes = Base64.getDecoder().decode(clientData.getGeometryName().getBytes(StandardCharsets.UTF_8)); - byte[] geometryBytes = Base64.getDecoder().decode(clientData.getGeometryData().getBytes(StandardCharsets.UTF_8)); - - if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) { - SkinProvider.storeBedrockSkin(playerEntity.getUuid(), clientData.getSkinId(), skinBytes); - SkinProvider.storeBedrockGeometry(playerEntity.getUuid(), geometryNameBytes, geometryBytes); - } else { - GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.skin.bedrock.fail", playerEntity.getUsername())); - GeyserConnector.getInstance().getLogger().debug("The size of '" + playerEntity.getUsername() + "' skin is: " + clientData.getSkinImageWidth() + "x" + clientData.getSkinImageHeight()); - } - - if (!clientData.getCapeId().equals("")) { - SkinProvider.storeBedrockCape(playerEntity.getUuid(), capeBytes); - } - } catch (Exception e) { - throw new AssertionError("Failed to cache skin for bedrock user (" + playerEntity.getUsername() + "): ", e); - } - } - - @AllArgsConstructor - @Getter - public static class GameProfileData { - private final String skinUrl; - private final String capeUrl; - private final boolean alex; - - /** - * Generate the GameProfileData from the given GameProfile - * - * @param profile GameProfile to build the GameProfileData from - * @return The built GameProfileData - */ - public static GameProfileData from(GameProfile profile) { - // Fallback to the offline mode of working it out - boolean isAlex = (Math.abs(profile.getId().hashCode() % 2) == 1); - - try { - GameProfile.Property skinProperty = profile.getProperty("textures"); - - // TODO: Remove try/catch here - JsonNode skinObject = GeyserConnector.JSON_MAPPER.readTree(new String(Base64.getDecoder().decode(skinProperty.getValue()), StandardCharsets.UTF_8)); - JsonNode textures = skinObject.get("textures"); - - JsonNode skinTexture = textures.get("SKIN"); - String skinUrl = skinTexture.get("url").asText().replace("http://", "https://"); - - isAlex = skinTexture.has("metadata"); - - String capeUrl = null; - if (textures.has("CAPE")) { - JsonNode capeTexture = textures.get("CAPE"); - capeUrl = capeTexture.get("url").asText().replace("http://", "https://"); - } - - return new GameProfileData(skinUrl, capeUrl, isAlex); - } catch (Exception exception) { - if (GeyserConnector.getInstance().getAuthType() != AuthType.OFFLINE) { - GeyserConnector.getInstance().getLogger().debug("Got invalid texture data for " + profile.getName() + " " + exception.getMessage()); - } - // return default skin with default cape when texture data is invalid - String skinUrl = isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl(); - if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) { - GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(profile.getId()); - - if (session != null) { - skinUrl = session.getClientData().getSkinId(); - } - } - return new GameProfileData(skinUrl, SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex); - } - } - } -} diff --git a/connector/src/main/java/org/geysermc/connector/skin/SkullSkinManager.java b/connector/src/main/java/org/geysermc/connector/skin/SkullSkinManager.java deleted file mode 100644 index 644323a4..00000000 --- a/connector/src/main/java/org/geysermc/connector/skin/SkullSkinManager.java +++ /dev/null @@ -1,100 +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.connector.skin; - -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.connector.GeyserConnector; -import org.geysermc.connector.entity.player.PlayerEntity; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.LanguageUtils; - -import java.util.Collections; -import java.util.UUID; -import java.util.function.Consumer; - -public class SkullSkinManager extends SkinManager { - - public static PlayerListPacket.Entry buildSkullEntryManually(UUID uuid, String username, long geyserId, - String skinId, byte[] skinData) { - // Prevents https://cdn.discordapp.com/attachments/613194828359925800/779458146191147008/unknown.png - skinId = skinId + "_skull"; - SerializedSkin serializedSkin = SerializedSkin.of( - skinId, SkinProvider.SKULL_GEOMETRY.getGeometryName(), ImageData.of(skinData), Collections.emptyList(), - ImageData.of(SkinProvider.EMPTY_CAPE.getCapeData()), SkinProvider.SKULL_GEOMETRY.getGeometryData(), - "", true, false, false, SkinProvider.EMPTY_CAPE.getCapeId(), skinId - ); - - PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid); - entry.setName(username); - entry.setEntityId(geyserId); - entry.setSkin(serializedSkin); - entry.setXuid(""); - entry.setPlatformChatId(""); - entry.setTeacher(false); - entry.setTrustedSkin(true); - return entry; - } - - public static void requestAndHandleSkin(PlayerEntity entity, GeyserSession session, - Consumer skinConsumer) { - GameProfileData data = GameProfileData.from(entity.getProfile()); - - SkinProvider.requestSkin(entity.getUuid(), data.getSkinUrl(), false) - .whenCompleteAsync((skin, throwable) -> { - try { - if (session.getUpstream().isInitialized()) { - PlayerListPacket.Entry updatedEntry = buildSkullEntryManually( - entity.getUuid(), - entity.getUsername(), - entity.getGeyserId(), - skin.getTextureUrl(), - skin.getSkinData() - ); - - PlayerListPacket playerAddPacket = new PlayerListPacket(); - playerAddPacket.setAction(PlayerListPacket.Action.ADD); - playerAddPacket.getEntries().add(updatedEntry); - session.sendUpstreamPacket(playerAddPacket); - - // It's a skull. We don't want them in the player list. - PlayerListPacket playerRemovePacket = new PlayerListPacket(); - playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE); - playerRemovePacket.getEntries().add(updatedEntry); - session.sendUpstreamPacket(playerRemovePacket); - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.skin.fail", entity.getUuid()), e); - } - - if (skinConsumer != null) { - skinConsumer.accept(skin); - } - }); - } - -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/AttributeUtils.java b/connector/src/main/java/org/geysermc/connector/utils/AttributeUtils.java index f2d5bd84..a69a5f19 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/AttributeUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/AttributeUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.connector.utils; import com.github.steveice10.mc.protocol.data.game.entity.attribute.AttributeModifier; import com.github.steveice10.mc.protocol.data.game.entity.attribute.ModifierOperation; -import com.nukkitx.protocol.bedrock.data.AttributeData; import org.geysermc.connector.entity.attribute.Attribute; import org.geysermc.connector.entity.attribute.AttributeType; @@ -63,20 +62,15 @@ public class AttributeUtils { return new com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute(type, attribute.getValue()); } - public static AttributeData getBedrockAttribute(Attribute attribute) { + public static com.nukkitx.protocol.bedrock.data.Attribute getBedrockAttribute(Attribute attribute) { AttributeType type = attribute.getType(); if (!type.isBedrockAttribute()) return null; - return new AttributeData(type.getBedrockIdentifier(), attribute.getMinimum(), attribute.getMaximum(), attribute.getValue(), attribute.getDefaultValue()); + return new com.nukkitx.protocol.bedrock.data.Attribute(type.getBedrockIdentifier(), attribute.getMinimum(), attribute.getMaximum(), attribute.getValue(), attribute.getDefaultValue()); } - /** - * Retrieve the base attribute value with all modifiers applied. - * https://minecraft.gamepedia.com/Attribute#Modifiers - * @param attribute The attribute to calculate the total value. - * @return The finished attribute with all modifiers applied. - */ + //https://minecraft.gamepedia.com/Attribute#Modifiers public static double calculateValue(com.github.steveice10.mc.protocol.data.game.entity.attribute.Attribute attribute) { double base = attribute.getValue(); for (AttributeModifier modifier : attribute.getModifiers()) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java b/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java index c7727cd6..f3ee956b 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.utils; diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java index 0c570dae..038084c3 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java @@ -1,76 +1,56 @@ -/* - * 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.connector.utils; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NbtMap; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; public class BlockEntityUtils { + private static final BlockEntityTranslator EMPTY_TRANSLATOR = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get("Empty"); public static String getBedrockBlockEntityId(String id) { // These are the only exceptions when it comes to block entity ids - String value = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id); - if (value != null) { - return value; + if (id.contains("piston_head")) + return "PistonArm"; + + if (id.contains("trapped_chest")) + return "Chest"; + + if (id.contains("EnderChest")) + return "EnderChest"; + + if (id.contains("enchanting_table")) { + return "EnchantTable"; } - id = id.replace("minecraft:", "") - .replace("_", " "); - // Split at every space or capital letter - for the latter, some legacy Java block entity tags are the correct format already - String[] words; - if (!id.toUpperCase().equals(id)) { // Otherwise we get [S, K, U, L, L] - words = id.split("(?=[A-Z])| "); // Split at every space or note or before every capital letter - } else { - words = id.split(" "); - } + id = id.toLowerCase() + .replace("minecraft:", "") + .replace("_", " "); + 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(); } - return String.join("", words); + id = String.join(" ", words); + return id.replace(" ", ""); } public static BlockEntityTranslator getBlockEntityTranslator(String name) { BlockEntityTranslator blockEntityTranslator = BlockEntityTranslator.BLOCK_ENTITY_TRANSLATORS.get(name); - if (blockEntityTranslator != null) { - return blockEntityTranslator; + if (blockEntityTranslator == null) { + return EMPTY_TRANSLATOR; } - return EMPTY_TRANSLATOR; + + return blockEntityTranslator; } - public static void updateBlockEntity(GeyserSession session, NbtMap blockEntity, Position position) { + public static void updateBlockEntity(GeyserSession session, com.nukkitx.nbt.tag.CompoundTag blockEntity, Position position) { updateBlockEntity(session, blockEntity, Vector3i.from(position.getX(), position.getY(), position.getZ())); } - public static void updateBlockEntity(GeyserSession session, NbtMap blockEntity, Vector3i position) { + public static void updateBlockEntity(GeyserSession session, com.nukkitx.nbt.tag.CompoundTag blockEntity, Vector3i position) { BlockEntityDataPacket blockEntityPacket = new BlockEntityDataPacket(); blockEntityPacket.setBlockPosition(position); blockEntityPacket.setData(blockEntity); diff --git a/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java index c859b9f6..6b9ab8ca 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +28,6 @@ package org.geysermc.connector.utils; import com.github.steveice10.mc.protocol.data.game.entity.Effect; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.math.vector.Vector3i; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.network.translators.item.ItemEntry; @@ -50,7 +49,6 @@ public class BlockUtils { if (toolType.equals("shears")) return isWoolBlock ? 5.0 : 15.0; if (toolType.equals("")) return 1.0; switch (toolTier) { - // https://minecraft.gamepedia.com/Breaking#Speed case "wooden": return 2.0; case "stone": @@ -59,8 +57,6 @@ public class BlockUtils { return 6.0; case "diamond": return 8.0; - case "netherite": - return 9.0; case "golden": return 12.0; default: @@ -128,8 +124,8 @@ public class BlockUtils { return calculateBreakTime(blockHardness, toolTier, canHarvestWithHand, correctTool, toolType, isWoolBlock, isCobweb, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, false, false, false); } - hasteLevel = session.getEffectCache().getEffectLevel(Effect.FASTER_DIG); - miningFatigueLevel = session.getEffectCache().getEffectLevel(Effect.SLOWER_DIG); + hasteLevel = session.getPlayerEntity().getEffectCache().getEffectLevel(Effect.FASTER_DIG); + miningFatigueLevel = session.getPlayerEntity().getEffectCache().getEffectLevel(Effect.SLOWER_DIG); boolean isInWater = session.getConnector().getConfig().isCacheChunks() && BlockTranslator.getBedrockBlockId(session.getConnector().getWorldManager().getBlockAt(session, session.getPlayerEntity().getPosition().toInt())) == BlockTranslator.BEDROCK_WATER_ID; @@ -142,28 +138,4 @@ public class BlockUtils { return calculateBreakTime(blockHardness, toolTier, canHarvestWithHand, correctTool, toolType, isWoolBlock, isCobweb, toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, outOfWaterButNotOnGround, insideWaterNotOnGround); } - /** - * Given a position, return the position if a block were located on the specified block face. - * @param blockPos the block position - * @param face the face of the block - see {@link com.github.steveice10.mc.protocol.data.game.world.block.BlockFace} - * @return the block position with the block face accounted for - */ - public static Vector3i getBlockPosition(Vector3i blockPos, int face) { - switch (face) { - case 0: - return blockPos.sub(0, 1, 0); - case 1: - return blockPos.add(0, 1, 0); - case 2: - return blockPos.sub(0, 0, 1); - case 3: - return blockPos.add(0, 0, 1); - case 4: - return blockPos.sub(1, 0, 0); - case 5: - return blockPos.add(1, 0, 0); - } - return blockPos; - } - } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java index e5e3f36d..010a87af 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ChunkUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,289 +25,139 @@ package org.geysermc.connector.utils; -import com.github.steveice10.mc.protocol.data.game.chunk.BitStorage; import com.github.steveice10.mc.protocol.data.game.chunk.Chunk; import com.github.steveice10.mc.protocol.data.game.chunk.Column; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette; -import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import com.github.steveice10.mc.protocol.data.game.world.block.BlockState; 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.math.vector.Vector2i; import com.nukkitx.math.vector.Vector3i; -import com.nukkitx.nbt.NBTOutputStream; -import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.NbtUtils; -import com.nukkitx.protocol.bedrock.packet.LevelChunkPacket; -import com.nukkitx.protocol.bedrock.packet.NetworkChunkPublisherUpdatePacket; -import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; -import it.unimi.dsi.fastutil.ints.IntArrayList; -import it.unimi.dsi.fastutil.ints.IntList; +import com.nukkitx.nbt.stream.NBTOutputStream; +import com.nukkitx.protocol.bedrock.packet.*; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; -import lombok.Data; -import lombok.experimental.UtilityClass; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import lombok.Getter; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.entity.ItemFrameEntity; -import org.geysermc.connector.entity.player.SkullPlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import org.geysermc.connector.network.translators.world.block.entity.*; import org.geysermc.connector.network.translators.world.block.BlockTranslator; -import org.geysermc.connector.network.translators.world.block.entity.BedrockOnlyBlockEntity; -import org.geysermc.connector.network.translators.world.block.entity.BlockEntityTranslator; -import org.geysermc.connector.network.translators.world.block.entity.RequiresBlockState; -import org.geysermc.connector.network.translators.world.block.entity.SkullBlockEntityTranslator; -import org.geysermc.connector.network.translators.world.chunk.BlockStorage; +import org.geysermc.connector.network.translators.world.chunk.ChunkPosition; import org.geysermc.connector.network.translators.world.chunk.ChunkSection; -import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArray; -import org.geysermc.connector.network.translators.world.chunk.bitarray.BitArrayVersion; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.List; +import java.util.HashMap; +import java.util.Map; -import static org.geysermc.connector.network.translators.world.block.BlockTranslator.*; +import static org.geysermc.connector.network.translators.world.block.BlockTranslator.AIR; +import static org.geysermc.connector.network.translators.world.block.BlockTranslator.BEDROCK_WATER_ID; -@UtilityClass public class ChunkUtils { + /** - * Temporarily stores positions of BlockState values that are needed for certain block entities actively. - * Not used if cache chunks is enabled + * Temporarily stores positions of BlockState values that are needed for certain block entities actively */ - public static final Object2IntMap CACHED_BLOCK_ENTITIES = new Object2IntOpenHashMap<>(); + public static final Map CACHED_BLOCK_ENTITIES = new HashMap<>(); - private static final NbtMap EMPTY_TAG = NbtMap.builder().build(); + private static final com.nukkitx.nbt.tag.CompoundTag EMPTY_TAG = CompoundTagBuilder.builder().buildRootTag(); public static final byte[] EMPTY_LEVEL_CHUNK_DATA; - public static final BlockStorage EMPTY_STORAGE = new BlockStorage(); - public static final ChunkSection EMPTY_SECTION = new ChunkSection(new BlockStorage[]{ EMPTY_STORAGE }); - static { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { outputStream.write(new byte[258]); // Biomes + Border Size + Extra Data Size try (NBTOutputStream stream = NbtUtils.createNetworkWriter(outputStream)) { - stream.writeTag(EMPTY_TAG); + stream.write(EMPTY_TAG); } EMPTY_LEVEL_CHUNK_DATA = outputStream.toByteArray(); - } catch (IOException e) { + }catch (IOException e) { throw new AssertionError("Unable to generate empty level chunk data"); } } - private static int indexYZXtoXZY(int yzx) { - return (yzx >> 8) | (yzx & 0x0F0) | ((yzx & 0x00F) << 8); - } - - public static ChunkData translateToBedrock(GeyserSession session, Column column, boolean isNonFullChunk) { - Chunk[] javaSections = column.getChunks(); - ChunkSection[] sections = new ChunkSection[javaSections.length]; - - // Temporarily stores compound tags of Bedrock-only block entities - List bedrockOnlyBlockEntities = new ArrayList<>(); - - BitSet waterloggedPaletteIds = new BitSet(); - BitSet pistonOrFlowerPaletteIds = new BitSet(); - - boolean worldManagerHasMoreBlockDataThanCache = session.getConnector().getWorldManager().hasMoreBlockDataThanChunkCache(); - - // If the received packet was a full chunk update, null sections in the chunk are guaranteed to also be null in the world manager - boolean shouldCheckWorldManagerOnMissingSections = isNonFullChunk && worldManagerHasMoreBlockDataThanCache; - Chunk temporarySection = null; - - for (int sectionY = 0; sectionY < javaSections.length; sectionY++) { - Chunk javaSection = javaSections[sectionY]; - - // Section is null, the cache will not contain anything of use - if (javaSection == null) { - // The column parameter contains all data currently available from the cache. If the chunk is null and the world manager - // reports the ability to access more data than the cache, attempt to fetch from the world manager instead. - if (shouldCheckWorldManagerOnMissingSections) { - // Ensure that temporary chunk is set - if (temporarySection == null) { - temporarySection = new Chunk(); - } - - // Read block data in section - session.getConnector().getWorldManager().getBlocksInSection(session, column.getX(), sectionY, column.getZ(), temporarySection); - - if (temporarySection.isEmpty()) { - // The world manager only contains air for the given section - // We can leave temporarySection as-is to allow it to potentially be re-used for later sections - continue; - } else { - javaSection = temporarySection; - - // Section contents have been modified, we can't re-use it - temporarySection = null; - } - } else { - continue; - } - } - - // No need to encode an empty section... - if (javaSection.isEmpty()) { - continue; - } - - Palette javaPalette = javaSection.getPalette(); - BitStorage javaData = javaSection.getStorage(); - - if (javaPalette instanceof GlobalPalette) { - // As this is the global palette, simply iterate through the whole chunk section once - ChunkSection section = new ChunkSection(); - for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) { - int javaId = javaData.get(yzx); - int bedrockId = BlockTranslator.getBedrockBlockId(javaId); - int xzy = indexYZXtoXZY(yzx); - section.getBlockStorageArray()[0].setFullBlock(xzy, bedrockId); - - if (BlockTranslator.isWaterlogged(javaId)) { - section.getBlockStorageArray()[1].setFullBlock(xzy, BEDROCK_WATER_ID); - } - - // Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock - if (BlockStateValues.getFlowerPotValues().containsKey(javaId) || BlockStateValues.getPistonValues().containsKey(javaId)) { - bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag( - Vector3i.from((column.getX() << 4) + (yzx & 0xF), (sectionY << 4) + ((yzx >> 8) & 0xF), (column.getZ() << 4) + ((yzx >> 4) & 0xF)), - javaId - )); - } - } - sections[sectionY] = section; - continue; - } - - IntList bedrockPalette = new IntArrayList(javaPalette.size()); - waterloggedPaletteIds.clear(); - pistonOrFlowerPaletteIds.clear(); - - // Iterate through palette and convert state IDs to Bedrock, doing some additional checks as we go - for (int i = 0; i < javaPalette.size(); i++) { - int javaId = javaPalette.idToState(i); - bedrockPalette.add(BlockTranslator.getBedrockBlockId(javaId)); - - if (BlockTranslator.isWaterlogged(javaId)) { - waterloggedPaletteIds.set(i); - } - - // Check if block is piston or flower to see if we'll need to create additional block entities, as they're only block entities in Bedrock - if (BlockStateValues.getFlowerPotValues().containsKey(javaId) || BlockStateValues.getPistonValues().containsKey(javaId)) { - pistonOrFlowerPaletteIds.set(i); - } - } - - // Add Bedrock-exclusive block entities - // We only if the palette contained any blocks that are Bedrock-exclusive block entities to avoid iterating through the whole block data - // for no reason, as most sections will not contain any pistons or flower pots - if (!pistonOrFlowerPaletteIds.isEmpty()) { - for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) { - int paletteId = javaData.get(yzx); - if (pistonOrFlowerPaletteIds.get(paletteId)) { - bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag( - Vector3i.from((column.getX() << 4) + (yzx & 0xF), (sectionY << 4) + ((yzx >> 8) & 0xF), (column.getZ() << 4) + ((yzx >> 4) & 0xF)), - javaPalette.idToState(paletteId) - )); - } - } - } - - BitArray bedrockData = BitArrayVersion.forBitsCeil(javaData.getBitsPerEntry()).createArray(BlockStorage.SIZE); - BlockStorage layer0 = new BlockStorage(bedrockData, bedrockPalette); - BlockStorage[] layers; - - // Convert data array from YZX to XZY coordinate order - if (waterloggedPaletteIds.isEmpty()) { - // No blocks are waterlogged, simply convert coordinate order - // This could probably be optimized further... - for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) { - bedrockData.set(indexYZXtoXZY(yzx), javaData.get(yzx)); - } - - layers = new BlockStorage[]{ layer0 }; - } else { - // The section contains waterlogged blocks, we need to convert coordinate order AND generate a V1 block storage for - // layer 1 with palette ID 1 indicating water - int[] layer1Data = new int[BlockStorage.SIZE >> 5]; - for (int yzx = 0; yzx < BlockStorage.SIZE; yzx++) { - int paletteId = javaData.get(yzx); - int xzy = indexYZXtoXZY(yzx); - bedrockData.set(xzy, paletteId); - - if (waterloggedPaletteIds.get(paletteId)) { - layer1Data[xzy >> 5] |= 1 << (xzy & 0x1F); - } - } - - // V1 palette - IntList layer1Palette = new IntArrayList(2); - layer1Palette.add(BEDROCK_AIR_ID); // Air - see BlockStorage's constructor for more information - layer1Palette.add(BEDROCK_WATER_ID); - - layers = new BlockStorage[]{ layer0, new BlockStorage(BitArrayVersion.V1.createArray(BlockStorage.SIZE, layer1Data), layer1Palette) }; - } - - sections[sectionY] = new ChunkSection(layers); - } + public static ChunkData translateToBedrock(Column column) { + ChunkData chunkData = new ChunkData(); + Chunk[] chunks = column.getChunks(); + chunkData.sections = new ChunkSection[chunks.length]; CompoundTag[] blockEntities = column.getTileEntities(); - NbtMap[] bedrockBlockEntities = new NbtMap[blockEntities.length + bedrockOnlyBlockEntities.size()]; + // Temporarily stores positions of BlockState values per chunk load + Map blockEntityPositions = new HashMap<>(); + + // Temporarily stores compound tags of Bedrock-only block entities + ObjectArrayList bedrockOnlyBlockEntities = new ObjectArrayList<>(); + + for (int chunkY = 0; chunkY < chunks.length; chunkY++) { + chunkData.sections[chunkY] = new ChunkSection(); + Chunk chunk = chunks[chunkY]; + + if (chunk == null || chunk.isEmpty()) + continue; + + ChunkSection section = chunkData.sections[chunkY]; + for (int x = 0; x < 16; x++) { + for (int y = 0; y < 16; y++) { + for (int z = 0; z < 16; z++) { + BlockState blockState = chunk.get(x, y, z); + int id = BlockTranslator.getBedrockBlockId(blockState); + + // Check to see if the name is in BlockTranslator.getBlockEntityString, and therefore must be handled differently + if (BlockTranslator.getBlockEntityString(blockState) != null) { + Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z); + blockEntityPositions.put(pos, blockState); + } + + section.getBlockStorageArray()[0].setFullBlock(ChunkSection.blockPosition(x, y, z), id); + + // Check if block is piston or flower - only block entities in Bedrock + if (BlockStateValues.getFlowerPotValues().containsKey(blockState.getId()) || + BlockStateValues.getPistonValues().containsKey(blockState.getId())) { + Position pos = new ChunkPosition(column.getX(), column.getZ()).getBlock(x, (chunkY << 4) + y, z); + bedrockOnlyBlockEntities.add(BedrockOnlyBlockEntity.getTag(Vector3i.from(pos.getX(), pos.getY(), pos.getZ()), blockState)); + } + + if (BlockTranslator.isWaterlogged(blockState)) { + section.getBlockStorageArray()[1].setFullBlock(ChunkSection.blockPosition(x, y, z), BEDROCK_WATER_ID); + } + } + } + } + + } + + com.nukkitx.nbt.tag.CompoundTag[] bedrockBlockEntities = new com.nukkitx.nbt.tag.CompoundTag[blockEntities.length + bedrockOnlyBlockEntities.size()]; int i = 0; while (i < blockEntities.length) { CompoundTag tag = blockEntities[i]; String tagName; - if (tag.contains("id")) { - tagName = (String) tag.get("id").getValue(); - } else { + if (!tag.contains("id")) { + GeyserConnector.getInstance().getLogger().debug("Got tag with no id: " + tag.getValue()); tagName = "Empty"; - // Sometimes legacy tags have their ID be a StringTag with empty value - for (Tag subTag : tag) { - if (subTag instanceof StringTag) { - StringTag stringTag = (StringTag) subTag; - if (stringTag.getValue().isEmpty()) { - tagName = stringTag.getName(); - break; - } - } - } - if (tagName.equals("Empty")) { - GeyserConnector.getInstance().getLogger().debug("Got tag with no id: " + tag.getValue()); - } + } else { + tagName = (String) tag.get("id").getValue(); } String id = BlockEntityUtils.getBedrockBlockEntityId(tagName); BlockEntityTranslator blockEntityTranslator = BlockEntityUtils.getBlockEntityTranslator(id); Position pos = new Position((int) tag.get("x").getValue(), (int) tag.get("y").getValue(), (int) tag.get("z").getValue()); - - // Get Java blockstate ID from block entity position - int blockState = 0; - Chunk section = column.getChunks()[pos.getY() >> 4]; - if (section != null) { - blockState = section.get(pos.getX() & 0xF, pos.getY() & 0xF, pos.getZ() & 0xF); - } - + BlockState blockState = blockEntityPositions.get(pos); bedrockBlockEntities[i] = blockEntityTranslator.getBlockEntityTag(tagName, tag, blockState); - - // Check for custom skulls - if (SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS && tag.contains("SkullOwner")) { - SkullBlockEntityTranslator.spawnPlayer(session, tag, blockState); - } i++; } - - // Append Bedrock-exclusive block entities to output array - for (NbtMap tag : bedrockOnlyBlockEntities) { + for (com.nukkitx.nbt.tag.CompoundTag tag : bedrockOnlyBlockEntities) { bedrockBlockEntities[i] = tag; i++; } - return new ChunkData(sections, bedrockBlockEntities); + chunkData.blockEntities = bedrockBlockEntities; + return chunkData; } public static void updateChunkPosition(GeyserSession session, Vector3i position) { @@ -324,37 +174,18 @@ 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) { + public static void updateBlock(GeyserSession session, BlockState 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 - * 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, Vector3i position) { + public static void updateBlock(GeyserSession session, BlockState blockState, Vector3i position) { // Checks for item frames so they aren't tripped up and removed - long frameEntityId = ItemFrameEntity.getItemFrameEntityId(session, position); - if (frameEntityId != -1) { - // TODO: Very occasionally the item frame doesn't sync up when destroyed - Entity entity = session.getEntityCache().getEntityByJavaId(frameEntityId); - if (blockState == JAVA_AIR_ID && entity != null) { // Item frame is still present and no block overrides that; refresh it - ((ItemFrameEntity) entity).updateBlock(session); - return; - } - - // Otherwise the item frame is gone + if (ItemFrameEntity.positionContainsItemFrame(session, position) && blockState.equals(AIR)) { + ((ItemFrameEntity) session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, position))).updateBlock(session); + return; + } else if (ItemFrameEntity.positionContainsItemFrame(session, position)) { + Entity entity = session.getEntityCache().getEntityByJavaId(ItemFrameEntity.getItemFrameEntityId(session, position)); if (entity != null) { session.getEntityCache().removeEntity(entity, false); } else { @@ -362,12 +193,6 @@ public class ChunkUtils { } } - SkullPlayerEntity skull = session.getSkullCache().get(position); - if (skull != null && blockState != skull.getBlockState()) { - // Skull is gone - skull.despawnEntity(session, position); - } - int blockId = BlockTranslator.getBedrockBlockId(blockState); UpdateBlockPacket updateBlockPacket = new UpdateBlockPacket(); @@ -375,7 +200,6 @@ public class ChunkUtils { updateBlockPacket.setBlockPosition(position); updateBlockPacket.setRuntimeId(blockId); updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NEIGHBORS); - updateBlockPacket.getFlags().add(UpdateBlockPacket.Flag.NETWORK); session.sendUpstreamPacket(updateBlockPacket); UpdateBlockPacket waterPacket = new UpdateBlockPacket(); @@ -384,7 +208,7 @@ public class ChunkUtils { if (BlockTranslator.isWaterlogged(blockState)) { waterPacket.setRuntimeId(BEDROCK_WATER_ID); } else { - waterPacket.setRuntimeId(BEDROCK_AIR_ID); + waterPacket.setRuntimeId(0); } session.sendUpstreamPacket(waterPacket); @@ -398,14 +222,11 @@ public class ChunkUtils { ((BedrockOnlyBlockEntity) requiresBlockState).updateBlock(session, blockState, position); break; } - if (!session.getConnector().getConfig().isCacheChunks()) { - // Blocks aren't saved to a chunk cache; resort to this smaller cache - CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState); - } + CACHED_BLOCK_ENTITIES.put(new Position(position.getX(), position.getY(), position.getZ()), blockState); break; //No block will be a part of two classes } } - session.getChunkCache().updateBlock(position.getX(), position.getY(), position.getZ(), blockState); + session.getChunkCache().updateBlock(new Position(position.getX(), position.getY(), position.getZ()), blockState); } public static void sendEmptyChunks(GeyserSession session, Vector3i position, int radius, boolean forceUpdate) { @@ -433,10 +254,12 @@ public class ChunkUtils { } } - @Data public static final class ChunkData { - private final ChunkSection[] sections; + public ChunkSection[] sections; - private final NbtMap[] blockEntities; + @Getter + private com.nukkitx.nbt.tag.CompoundTag[] blockEntities = new com.nukkitx.nbt.tag.CompoundTag[0]; + @Getter + private Object2IntMap loadBlockEntitiesLater = new Object2IntOpenHashMap<>(); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java b/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java deleted file mode 100644 index 5a49fd9b..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java +++ /dev/null @@ -1,120 +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.connector.utils; - -import com.nukkitx.protocol.bedrock.packet.SetTitlePacket; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; - -import java.util.concurrent.TimeUnit; - -/** - * Manages the sending of a cooldown indicator to the Bedrock player as there is no cooldown indicator in Bedrock. - * Much of the work here is from the wonderful folks from ViaRewind: https://github.com/ViaVersion/ViaRewind - */ -public class CooldownUtils { - - private final static boolean SHOW_COOLDOWN; - - static { - SHOW_COOLDOWN = GeyserConnector.getInstance().getConfig().isShowCooldown(); - } - - /** - * Starts sending the fake cooldown to the Bedrock client. - * @param session GeyserSession - */ - public static void sendCooldown(GeyserSession session) { - if (!SHOW_COOLDOWN) 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 - SetTitlePacket titlePacket = new SetTitlePacket(); - titlePacket.setType(SetTitlePacket.Type.TITLE); - titlePacket.setText(" "); - session.sendUpstreamPacket(titlePacket); - session.setLastHitTime(System.currentTimeMillis()); - long lastHitTime = session.getLastHitTime(); // Used later to prevent multiple scheduled cooldown threads - computeCooldown(session, lastHitTime); - } - - /** - * Keeps updating the cooldown until the bar is complete. - * @param session GeyserSession - * @param lastHitTime The time of the last hit. Used to gauge how long the cooldown is taking. - */ - private static void computeCooldown(GeyserSession session, long lastHitTime) { - if (session.isClosed()) return; // Don't run scheduled tasks if the client left - if (lastHitTime != session.getLastHitTime()) return; // Means another cooldown has started so there's no need to continue this one - SetTitlePacket titlePacket = new SetTitlePacket(); - titlePacket.setType(SetTitlePacket.Type.SUBTITLE); - titlePacket.setText(getTitle(session)); - titlePacket.setFadeInTime(0); - titlePacket.setFadeOutTime(5); - titlePacket.setStayTime(2); - session.sendUpstreamPacket(titlePacket); - if (hasCooldown(session)) { - session.getConnector().getGeneralThreadPool().schedule(() -> computeCooldown(session, lastHitTime), 50, TimeUnit.MILLISECONDS); // Updated per tick. 1000 divided by 20 ticks equals 50 - } else { - SetTitlePacket removeTitlePacket = new SetTitlePacket(); - removeTitlePacket.setType(SetTitlePacket.Type.SUBTITLE); - removeTitlePacket.setText(" "); - session.sendUpstreamPacket(removeTitlePacket); - } - } - - private static boolean hasCooldown(GeyserSession session) { - long time = System.currentTimeMillis() - session.getLastHitTime(); - double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1.5); - return cooldown < 1.1; - } - - - private static double restrain(double x, double max) { - if (x < 0d) - return 0d; - return Math.min(x, max); - } - - private static String getTitle(GeyserSession session) { - long time = System.currentTimeMillis() - session.getLastHitTime(); - double cooldown = restrain(((double) time) * session.getAttackSpeed() / 1000d, 1); - - int darkGrey = (int) Math.floor(10d * cooldown); - int grey = 10 - darkGrey; - StringBuilder builder = new StringBuilder("§8"); - while (darkGrey > 0) { - builder.append("˙"); - darkGrey--; - } - builder.append("§7"); - while (grey > 0) { - builder.append("˙"); - grey--; - } - return builder.toString(); - } - -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index f193a61d..6c8d9f94 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ package org.geysermc.connector.utils; 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.Vector3i; -import com.nukkitx.protocol.bedrock.packet.ChangeDimensionPacket; -import com.nukkitx.protocol.bedrock.packet.MobEffectPacket; -import com.nukkitx.protocol.bedrock.packet.StopSoundPacket; -import org.geysermc.connector.GeyserConnector; +import com.nukkitx.protocol.bedrock.packet.*; import org.geysermc.connector.entity.Entity; import org.geysermc.connector.network.session.GeyserSession; @@ -41,26 +36,17 @@ public class DimensionUtils { // Changes if the above-bedrock Nether building workaround is applied private static int BEDROCK_NETHER_ID = 1; - /** - * String reference to vanilla Java overworld dimension identifier - */ - public static final String OVERWORLD = "minecraft:overworld"; - /** - * String reference to vanilla Java nether dimension identifier - */ - public static final String NETHER = "minecraft:the_nether"; - /** - * String reference to vanilla Java end dimension identifier - */ - public static final String THE_END = "minecraft:the_end"; - - public static void switchDimension(GeyserSession session, String javaDimension) { + public static void switchDimension(GeyserSession session, int javaDimension) { int bedrockDimension = javaToBedrock(javaDimension); Entity player = session.getPlayerEntity(); + if (bedrockDimension == player.getDimension()) + return; session.getEntityCache().removeAllEntities(); session.getItemFrameCache().clear(); - session.getSkullCache().clear(); + if (session.getPendingDimSwitches().getAndIncrement() > 0) { + ChunkUtils.sendEmptyChunks(session, player.getPosition().toInt(), 3, true); + } Vector3i pos = Vector3i.from(0, Short.MAX_VALUE, 0); @@ -69,12 +55,12 @@ public class DimensionUtils { changeDimensionPacket.setRespawn(true); changeDimensionPacket.setPosition(pos.toFloat()); session.sendUpstreamPacket(changeDimensionPacket); - session.setDimension(javaDimension); + player.setDimension(bedrockDimension); player.setPosition(pos.toFloat()); session.setSpawned(false); session.setLastChunkPosition(null); - for (Effect effect : session.getEffectCache().getEntityEffects().keySet()) { + for (Effect effect : session.getPlayerEntity().getEffectCache().getEntityEffects().keySet()) { MobEffectPacket mobEffectPacket = new MobEffectPacket(); mobEffectPacket.setEvent(MobEffectPacket.Event.REMOVE); mobEffectPacket.setRuntimeEntityId(session.getPlayerEntity().getGeyserId()); @@ -82,17 +68,13 @@ public class DimensionUtils { session.sendUpstreamPacket(mobEffectPacket); } // Effects are re-sent from server - session.getEffectCache().getEntityEffects().clear(); + session.getPlayerEntity().getEffectCache().getEntityEffects().clear(); //let java server handle portal travel sound StopSoundPacket stopSoundPacket = new StopSoundPacket(); stopSoundPacket.setStoppingAllSound(true); stopSoundPacket.setSoundName(""); session.sendUpstreamPacket(stopSoundPacket); - - // TODO - fix this hack of a fix by sending the final dimension switching logic after chunks have been sent. - // The client wants chunks sent to it before it can successfully respawn. - ChunkUtils.sendEmptyChunks(session, player.getPosition().toInt(), 3, true); } /** @@ -101,60 +83,19 @@ public class DimensionUtils { * @param javaDimension Dimension ID to convert * @return Converted Bedrock edition dimension ID */ - public static int javaToBedrock(String javaDimension) { + public static int javaToBedrock(int javaDimension) { switch (javaDimension) { - case NETHER: + case -1: return BEDROCK_NETHER_ID; - case THE_END: + case 1: return 2; default: - return 0; + return javaDimension; } } - /** - * Determines the new dimension based on the {@link CompoundTag} sent by either the {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket} - * or {@link com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket}. - * - * @param dimensionTag the packet's dimension tag. - * @return the dimension identifier. - */ - public static String getNewDimension(CompoundTag dimensionTag) { - if (dimensionTag == null || dimensionTag.isEmpty()) { - GeyserConnector.getInstance().getLogger().debug("Dimension tag was null or empty."); - return OVERWORLD; - } - if (dimensionTag.getValue().get("effects") != null) { - return ((StringTag) dimensionTag.getValue().get("effects")).getValue(); - } - GeyserConnector.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. - * - * @param isAboveNetherBedrockBuilding true if we should apply The End workaround - */ - public static void changeBedrockNetherId(boolean isAboveNetherBedrockBuilding) { + public static void changeBedrockNetherId() { // Change dimension ID to the End to allow for building above Bedrock - BEDROCK_NETHER_ID = isAboveNetherBedrockBuilding ? 2 : 1; - } - - /** - * Gets the fake, temporary dimension we send clients to so we aren't switching to the same dimension without an additional - * dimension switch. - * - * @param currentDimension the current dimension of the player - * @param newDimension the new dimension that the player will be transferred to - * @return the fake dimension to transfer to - */ - public static String getTemporaryDimension(String currentDimension, String newDimension) { - if (BEDROCK_NETHER_ID == 2) { - // Prevents rare instances of Bedrock locking up - return javaToBedrock(newDimension) == 2 ? OVERWORLD : NETHER; - } - return currentDimension.equals(OVERWORLD) ? NETHER : OVERWORLD; + BEDROCK_NETHER_ID = 2; } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java b/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java index 31c37edf..0a5a2278 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java @@ -1,49 +1,58 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.utils; +import org.geysermc.connector.bootstrap.GeyserBootstrap; + +import java.net.InetAddress; import java.nio.file.Files; import java.nio.file.Paths; public class DockerCheck { - - // By default, Geyser now sets the IP to the local IP in all cases on plugin versions so we don't notify the user of anything - // However we still have this check for the potential future bug - public static boolean checkBasic() { + public static void check(GeyserBootstrap bootstrap) { try { String OS = System.getProperty("os.name").toLowerCase(); + String ipAddress = InetAddress.getLocalHost().getHostAddress(); + + // Check if the user is already using the recommended IP + if (ipAddress.equals(bootstrap.getGeyserConfig().getRemote().getAddress())) { + return; + } + if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0 || OS.indexOf("aix") > 0) { + bootstrap.getGeyserLogger().debug("We are on a Unix system, checking for Docker..."); + String output = new String(Files.readAllBytes(Paths.get("/proc/1/cgroup"))); if (output.contains("docker")) { - return true; + bootstrap.getGeyserLogger().warning("You are most likely in a Docker container, this may cause connection issues from Geyser to the Java server"); + bootstrap.getGeyserLogger().warning("We recommended using the following IP as the remote address: " + ipAddress); } } - } catch (Exception ignored) { } // Ignore any errors, inc ip failed to fetch, process could not run or access denied - - return false; + } catch (Exception e) { } // Ignore any errors, inc ip failed to fetch, process could not run or access denied } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java index eb712b13..b5033c94 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 @@ public class EntityUtils { case LUCK: case UNLUCK: case DOLPHINS_GRACE: - // All Java-exclusive effects as of 1.16.2 + case BAD_OMEN: + case HERO_OF_THE_VILLAGE: return 0; case LEVITATION: return 24; @@ -50,10 +51,6 @@ public class EntityUtils { return 26; case SLOW_FALLING: return 27; - case BAD_OMEN: - return 28; - case HERO_OF_THE_VILLAGE: - return 29; default: return effect.ordinal() + 1; } diff --git a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java index 862af548..04b6ecc4 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,14 @@ package org.geysermc.connector.utils; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import org.geysermc.connector.GeyserConnector; -import org.reflections.Reflections; -import org.reflections.serializers.XmlSerializer; -import org.reflections.util.ConfigurationBuilder; -import java.io.*; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.security.MessageDigest; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; import java.util.function.Function; public class FileUtils { @@ -48,7 +42,6 @@ public class FileUtils { * * @param src File to load * @param valueType Class to load file into - * @param the type * @return The data as the given class * @throws IOException if the config could not be loaded */ @@ -57,16 +50,6 @@ public class FileUtils { return objectMapper.readValue(src, valueType); } - public static T loadYaml(InputStream src, Class valueType) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory()).enable(JsonParser.Feature.IGNORE_UNDEFINED).disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); - return objectMapper.readValue(src, valueType); - } - - public static T loadJson(InputStream src, Class valueType) throws IOException { - // Read specifically with UTF-8 to allow any non-UTF-encoded JSON to read - return GeyserConnector.JSON_MAPPER.readValue(new InputStreamReader(src, StandardCharsets.UTF_8), valueType); - } - /** * Open the specified file or copy if from resources * @@ -152,92 +135,8 @@ public class FileUtils { public static InputStream getResource(String resource) { InputStream stream = FileUtils.class.getClassLoader().getResourceAsStream(resource); if (stream == null) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.resource", resource)); + throw new AssertionError("Unable to find resource: " + resource); } return stream; } - - /** - * Calculate the SHA256 hash of a file - * - * @param file File to calculate the hash for - * @return A byte[] representation of the hash - */ - public static byte[] calculateSHA256(File file) { - byte[] sha256; - - try { - sha256 = MessageDigest.getInstance("SHA-256").digest(readAllBytes(file)); - } catch (Exception e) { - throw new RuntimeException("Could not calculate pack hash", e); - } - - return sha256; - } - - /** - * Calculate the SHA1 hash of a file - * - * @param file File to calculate the hash for - * @return A byte[] representation of the hash - */ - public static byte[] calculateSHA1(File file) { - byte[] sha1; - - try { - sha1 = MessageDigest.getInstance("SHA-1").digest(readAllBytes(file)); - } catch (Exception e) { - throw new RuntimeException("Could not calculate pack hash", e); - } - - return sha1; - } - - /** - * Get the stored reflection data for a given path - * - * @param path The path to get the reflection data for - * @return The created Reflections object - */ - public static Reflections getReflections(String path) { - Reflections reflections = new Reflections(new ConfigurationBuilder().setScanners()); - XmlSerializer serializer = new XmlSerializer(); - URL resource = FileUtils.class.getClassLoader().getResource("META-INF/reflections/" + path + "-reflections.xml"); - try (InputStream inputStream = resource.openConnection().getInputStream()) { - reflections.merge(serializer.read(inputStream)); - } catch (IOException e) { } - - return reflections; - } - - /** - * An android compatible version of {@link Files#readAllBytes} - * - * @param file File to read bytes of - * @return The byte array of the file - */ - public static byte[] readAllBytes(File file) { - try { - return readAllBytes(new FileInputStream(file)); - } catch (IOException e) { - throw new RuntimeException("Cannot read " + file); - } - } - - /** - * @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]; - BufferedInputStream buf = new BufferedInputStream(stream); - buf.read(bytes, 0, bytes.length); - buf.close(); - return bytes; - } catch (IOException e) { - throw new RuntimeException("Error while trying to read input stream!"); - } - } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java index 36eda6ad..d729e3a1 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.utils; diff --git a/connector/src/main/java/org/geysermc/connector/utils/GameRule.java b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java deleted file mode 100644 index a4e4ef23..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/GameRule.java +++ /dev/null @@ -1,123 +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.connector.utils; - -import lombok.Getter; - -/** - * This enum stores each gamerule along with the value type and the default. - * It is used to construct the list for the settings menu - */ -public enum GameRule { - ANNOUNCEADVANCEMENTS("announceAdvancements", Boolean.class, true), // JE only - COMMANDBLOCKOUTPUT("commandBlockOutput", Boolean.class, true), - DISABLEELYTRAMOVEMENTCHECK("disableElytraMovementCheck", Boolean.class, false), // JE only - DISABLERAIDS("disableRaids", Boolean.class, false), // JE only - DODAYLIGHTCYCLE("doDaylightCycle", Boolean.class, true), - DOENTITYDROPS("doEntityDrops", Boolean.class, true), - DOFIRETICK("doFireTick", Boolean.class, true), - DOIMMEDIATERESPAWN("doImmediateRespawn", Boolean.class, false), - DOINSOMNIA("doInsomnia", Boolean.class, true), - DOLIMITEDCRAFTING("doLimitedCrafting", Boolean.class, false), // JE only - DOMOBLOOT("doMobLoot", Boolean.class, true), - DOMOBSPAWNING("doMobSpawning", Boolean.class, true), - DOPATROLSPAWNING("doPatrolSpawning", Boolean.class, true), // JE only - DOTILEDROPS("doTileDrops", Boolean.class, true), - DOTRADERSPAWNING("doTraderSpawning", Boolean.class, true), // JE only - DOWEATHERCYCLE("doWeatherCycle", Boolean.class, true), - DROWNINGDAMAGE("drowningDamage", Boolean.class, true), - FALLDAMAGE("fallDamage", Boolean.class, true), - FIREDAMAGE("fireDamage", Boolean.class, true), - FORGIVEDEADPLAYERS("forgiveDeadPlayers", Boolean.class, true), // JE only - KEEPINVENTORY("keepInventory", Boolean.class, false), - LOGADMINCOMMANDS("logAdminCommands", Boolean.class, true), // JE only - MAXCOMMANDCHAINLENGTH("maxCommandChainLength", Integer.class, 65536), - MAXENTITYCRAMMING("maxEntityCramming", Integer.class, 24), // JE only - MOBGRIEFING("mobGriefing", Boolean.class, true), - NATURALREGENERATION("naturalRegeneration", Boolean.class, true), - RANDOMTICKSPEED("randomTickSpeed", Integer.class, 3), - REDUCEDDEBUGINFO("reducedDebugInfo", Boolean.class, false), // JE only - SENDCOMMANDFEEDBACK("sendCommandFeedback", Boolean.class, true), - SHOWDEATHMESSAGES("showDeathMessages", Boolean.class, true), - SPAWNRADIUS("spawnRadius", Integer.class, 10), - SPECTATORSGENERATECHUNKS("spectatorsGenerateChunks", Boolean.class, true), // JE only - UNIVERSALANGER("universalAnger", Boolean.class, false), // JE only - - UNKNOWN("unknown", Object.class); - - private static final GameRule[] VALUES = values(); - - @Getter - private String javaID; - - @Getter - private Class type; - - @Getter - private Object defaultValue; - - GameRule(String javaID, Class type) { - this(javaID, type, null); - } - - GameRule(String javaID, Class type, Object defaultValue) { - this.javaID = javaID; - this.type = type; - this.defaultValue = defaultValue; - } - - /** - * Convert a string to an object of the correct type for the current gamerule - * - * @param value The string value to convert - * @return The converted and formatted value - */ - public Object convertValue(String value) { - if (type.equals(Boolean.class)) { - return Boolean.parseBoolean(value); - } else if (type.equals(Integer.class)) { - return Integer.parseInt(value); - } - - return null; - } - - /** - * Fetch a game rule by the given Java ID - * - * @param id The ID of the gamerule - * @return A {@link GameRule} object representing the requested ID or {@link GameRule#UNKNOWN} - */ - public static GameRule fromJavaID(String id) { - for (GameRule gamerule : VALUES) { - if (gamerule.javaID.equals(id)) { - return gamerule; - } - } - - return UNKNOWN; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/GeyserAdvancement.java b/connector/src/main/java/org/geysermc/connector/utils/GeyserAdvancement.java deleted file mode 100644 index 31560498..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/GeyserAdvancement.java +++ /dev/null @@ -1,89 +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.connector.utils; - -import com.github.steveice10.mc.protocol.data.game.advancement.Advancement; -import lombok.NonNull; -import org.geysermc.connector.network.session.cache.AdvancementsCache; - -import java.util.List; - -/** - * A wrapper around MCProtocolLib's {@link Advancement} class so we can control the parent of an advancement - */ -public class GeyserAdvancement { - private final Advancement advancement; - private String rootId = null; - - public static GeyserAdvancement from(Advancement advancement) { - return new GeyserAdvancement(advancement); - } - - private GeyserAdvancement(Advancement advancement) { - this.advancement = advancement; - } - - @NonNull - public String getId() { - return this.advancement.getId(); - } - - @NonNull - public List getCriteria() { - return this.advancement.getCriteria(); - } - - @NonNull - public List> getRequirements() { - return this.advancement.getRequirements(); - } - - public String getParentId() { - return this.advancement.getParentId(); - } - - public Advancement.DisplayData getDisplayData() { - return this.advancement.getDisplayData(); - } - - public String getRootId(AdvancementsCache advancementsCache) { - if (rootId == null) { - if (this.advancement.getParentId() == null) { - // We are the root ID - this.rootId = this.advancement.getId(); - } else { - // Go through our cache, and descend until we find the root ID - GeyserAdvancement advancement = advancementsCache.getStoredAdvancements().get(this.advancement.getParentId()); - if (advancement.getParentId() == null) { - this.rootId = advancement.getId(); - } else { - this.rootId = advancement.getRootId(advancementsCache); - } - } - } - return rootId; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java index a4d72226..ded47723 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/InventoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,27 +26,21 @@ package org.geysermc.connector.utils; 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.packet.ingame.client.window.ClientCreativeInventoryActionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.client.window.ClientMoveItemToHotbarPacket; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMap; -import com.nukkitx.nbt.NbtMapBuilder; -import com.nukkitx.nbt.NbtType; -import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; -import com.nukkitx.protocol.bedrock.data.inventory.ItemData; +import com.nukkitx.nbt.CompoundTagBuilder; +import com.nukkitx.nbt.tag.StringTag; +import com.nukkitx.protocol.bedrock.data.ContainerId; +import com.nukkitx.protocol.bedrock.data.ItemData; +import com.nukkitx.protocol.bedrock.packet.ContainerClosePacket; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; +import org.geysermc.common.ChatColor; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.common.ChatColor; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.DoubleChestInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; -import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; import org.geysermc.connector.network.translators.item.ItemTranslator; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; import java.util.Collections; import java.util.Objects; @@ -62,7 +56,7 @@ public class InventoryUtils { translator.prepareInventory(session, inventory); //Ensure at least half a second passes between closing and opening a new window //The client will not open the new window if it is still closing the old one - long delay = 700 - (System.currentTimeMillis() - session.getLastWindowCloseTime()); + long delay = 500 - (System.currentTimeMillis() - session.getLastWindowCloseTime()); //TODO: find better way to handle double chest delay if (translator instanceof DoubleChestInventoryTranslator) { delay = Math.max(delay, 200); @@ -93,7 +87,6 @@ public class InventoryUtils { } } else { Inventory inventory = session.getInventory(); - inventory.setOpen(false); InventoryTranslator translator = InventoryTranslator.INVENTORY_TRANSLATORS.get(inventory.getWindowType()); translator.updateInventory(session, inventory); } @@ -104,24 +97,18 @@ public class InventoryUtils { } public static void closeWindow(GeyserSession session, int windowId) { - //TODO: Investigate client crash when force closing window and opening a new one - //Instead, the window will eventually close by removing the fake blocks - session.setLastWindowCloseTime(System.currentTimeMillis()); - - /* //Spamming close window packets can bug the client if (System.currentTimeMillis() - session.getLastWindowCloseTime() > 500) { ContainerClosePacket closePacket = new ContainerClosePacket(); - closePacket.setId((byte) windowId); + closePacket.setWindowId((byte) windowId); session.sendUpstreamPacket(closePacket); session.setLastWindowCloseTime(System.currentTimeMillis()); } - */ } public static void updateCursor(GeyserSession session) { InventorySlotPacket cursorPacket = new InventorySlotPacket(); - cursorPacket.setContainerId(ContainerId.UI); + cursorPacket.setContainerId(ContainerId.CURSOR); cursorPacket.setSlot(0); cursorPacket.setItem(ItemTranslator.translateToBedrock(session, session.getInventory().getCursor())); session.sendUpstreamPacket(cursorPacket); @@ -142,114 +129,15 @@ public class InventoryUtils { /** * Returns a barrier block with custom name and lore to explain why * part of the inventory is unusable. - * - * @param description the description - * @return the unusable space block */ public static ItemData createUnusableSpaceBlock(String description) { - NbtMapBuilder root = NbtMap.builder(); - NbtMapBuilder display = NbtMap.builder(); + CompoundTagBuilder root = CompoundTagBuilder.builder(); + CompoundTagBuilder display = CompoundTagBuilder.builder(); - // Not ideal to use log here but we dont get a session - display.putString("Name", ChatColor.RESET + LanguageUtils.getLocaleStringLog("geyser.inventory.unusable_item.name")); - display.putList("Lore", NbtType.STRING, Collections.singletonList(ChatColor.RESET + ChatColor.DARK_PURPLE + description)); + display.stringTag("Name", ChatColor.RESET + "Unusable inventory space"); + display.listTag("Lore", StringTag.class, Collections.singletonList(new StringTag("", ChatColor.RESET + ChatColor.DARK_PURPLE + description))); - root.put("display", display.build()); - return ItemData.of(ItemRegistry.ITEM_ENTRIES.get(ItemRegistry.BARRIER_INDEX).getBedrockId(), (short) 0, 1, root.build()); - } - - /** - * Attempt to find the specified item name in the session's inventory. - * If it is found and in the hotbar, set the user's held item to that slot. - * If it is found in another part of the inventory, move it. - * If it is not found and the user is in creative mode, create the item, - * overriding the current item slot if no other hotbar slots are empty, or otherwise selecting the empty slot. - * - * This attempts to mimic Java Edition behavior as best as it can. - * @param session the Bedrock client's session - * @param itemName the Java identifier of the item to search/select - */ - public static void findOrCreateItem(GeyserSession session, String itemName) { - // Get the inventory to choose a slot to pick - Inventory inventory = session.getInventoryCache().getOpenInventory(); - if (inventory == null) { - inventory = session.getInventory(); - } - - if (itemName.equals("minecraft:air")) { - return; - } - - // Check hotbar for item - for (int i = 36; i < 45; i++) { - if (inventory.getItem(i) == null) { - continue; - } - ItemEntry item = ItemRegistry.getItem(inventory.getItem(i)); - // If this isn't the item we're looking for - if (!item.getJavaIdentifier().equals(itemName)) { - continue; - } - - setHotbarItem(session, i); - // Don't check inventory if item was in hotbar - return; - } - - // Check inventory for item - for (int i = 9; i < 36; i++) { - if (inventory.getItem(i) == null) { - continue; - } - ItemEntry item = ItemRegistry.getItem(inventory.getItem(i)); - // If this isn't the item we're looking for - if (!item.getJavaIdentifier().equals(itemName)) { - continue; - } - - ClientMoveItemToHotbarPacket packetToSend = new ClientMoveItemToHotbarPacket(i); // https://wiki.vg/Protocol#Pick_Item - session.sendDownstreamPacket(packetToSend); - return; - } - - // If we still have not found the item, and we're in creative, ask for the item from the server. - if (session.getGameMode() == GameMode.CREATIVE) { - int slot = session.getInventory().getHeldItemSlot() + 36; - if (session.getInventory().getItemInHand() != null) { // Otherwise we should just use the current slot - for (int i = 36; i < 45; i++) { - if (inventory.getItem(i) == null) { - slot = i; - break; - } - } - } - - ItemEntry entry = ItemRegistry.getItemEntry(itemName); - if (entry != null) { - ClientCreativeInventoryActionPacket actionPacket = new ClientCreativeInventoryActionPacket(slot, - new ItemStack(entry.getJavaId())); - if ((slot - 36) != session.getInventory().getHeldItemSlot()) { - setHotbarItem(session, slot); - } - session.sendDownstreamPacket(actionPacket); - } else { - session.getConnector().getLogger().debug("Cannot find item for block " + itemName); - } - } - } - - /** - * Changes the held item slot to the specified slot - * @param session GeyserSession - * @param slot inventory slot to be selected - */ - private static void setHotbarItem(GeyserSession session, int slot) { - PlayerHotbarPacket hotbarPacket = new PlayerHotbarPacket(); - hotbarPacket.setContainerId(0); - // Java inventory slot to hotbar slot ID - hotbarPacket.setSelectedHotbarSlot(slot - 36); - hotbarPacket.setSelectHotbarSlot(true); - session.sendUpstreamPacket(hotbarPacket); - // No need to send a Java packet as Bedrock sends a confirmation packet back that we translate + root.tag(display.build("display")); + return ItemData.of(ItemRegistry.ITEM_ENTRIES.get(ItemRegistry.BARRIER_INDEX).getBedrockId(), (short) 0, 1, root.buildRootTag()); } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java index 07063164..b9600222 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ItemUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 @@ package org.geysermc.connector.utils; import com.github.steveice10.opennbt.tag.builtin.*; +import com.nukkitx.nbt.CompoundTagBuilder; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class ItemUtils { diff --git a/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java deleted file mode 100644 index 1a1f758d..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java +++ /dev/null @@ -1,207 +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.connector.utils; - -import org.geysermc.connector.GeyserConnector; - -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.text.MessageFormat; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; - -public class LanguageUtils { - - /** - * If we determine the locale that the user wishes to use, use that locale - */ - private static String CACHED_LOCALE; - - private static final Map LOCALE_MAPPINGS = new HashMap<>(); - - static { - // Load it as a backup in case something goes really wrong - if (!"en_US".equals(formatLocale(getDefaultLocale()))) { // getDefaultLocale() loads the locale automatically - loadGeyserLocale("en_US"); - } - } - - /** - * Loads a Geyser locale from resources, if the file doesn't exist it just logs a warning - * - * @param locale Locale to load - */ - public static void loadGeyserLocale(String locale) { - locale = formatLocale(locale); - // Don't load the locale if it's already loaded. - if (LOCALE_MAPPINGS.containsKey(locale)) return; - - InputStream localeStream = GeyserConnector.class.getClassLoader().getResourceAsStream("languages/texts/" + locale + ".properties"); - - // Load the locale - if (localeStream != null) { - Properties localeProp = new Properties(); - try { - localeProp.load(new InputStreamReader(localeStream, StandardCharsets.UTF_8)); - } catch (Exception e) { - throw new AssertionError(getLocaleStringLog("geyser.language.load_failed", locale), e); - } - - // Insert the locale into the mappings - LOCALE_MAPPINGS.put(locale, localeProp); - } else { - if (GeyserConnector.getInstance() != null && GeyserConnector.getInstance().getLogger() != null) { - GeyserConnector.getInstance().getLogger().warning("Missing locale: " + locale); - } - } - } - - /** - * Get a formatted language string with the default locale for Geyser - * - * @param key Language string to translate - * @param values Values to put into the string - * @return Translated string or the original message if it was not found in the given locale - */ - public static String getLocaleStringLog(String key, Object... values) { - return getPlayerLocaleString(key, getDefaultLocale(), values); - } - - /** - * Get a formatted language string with the given locale for Geyser - * - * @param key Language string to translate - * @param locale Locale to translate to - * @param values Values to put into the string - * @return Translated string or the original message if it was not found in the given locale - */ - public static String getPlayerLocaleString(String key, String locale, Object... values) { - locale = formatLocale(locale); - - Properties properties = LOCALE_MAPPINGS.get(locale); - String formatString = null; - - if (properties != null) { - formatString = properties.getProperty(key); - } - - // Try and get the key from the default locale - if (formatString == null) { - properties = LOCALE_MAPPINGS.get(formatLocale(getDefaultLocale())); - formatString = properties.getProperty(key); - } - - // Try and get the key from en_US (this should only ever happen in development) - if (formatString == null) { - properties = LOCALE_MAPPINGS.get("en_US"); - formatString = properties.getProperty(key); - } - - // Final fallback - if (formatString == null) { - formatString = key; - } - - return MessageFormat.format(formatString.replace("'", "''").replace("&", "\u00a7"), values); - } - - /** - * Cleans up and formats a locale string - * - * @param locale The locale to format - * @return The formatted locale - */ - public static String formatLocale(String locale) { - try { - String[] parts = locale.toLowerCase().split("_"); - return parts[0] + "_" + parts[1].toUpperCase(); - } catch (Exception e) { - return locale; - } - } - - /** - * Get the default locale that Geyser should use - * @return the current default locale - */ - public static String getDefaultLocale() { - if (CACHED_LOCALE != null) return CACHED_LOCALE; // We definitely know the locale the user is using - String locale; - boolean isValid = true; - if (GeyserConnector.getInstance() != null && - GeyserConnector.getInstance().getConfig() != null && - GeyserConnector.getInstance().getConfig().getDefaultLocale() != null) { // If the config option for getDefaultLocale does not equal null, use that - locale = formatLocale(GeyserConnector.getInstance().getConfig().getDefaultLocale()); - if (isValidLanguage(locale)) { - CACHED_LOCALE = locale; - return locale; - } else { - isValid = false; - } - } - locale = formatLocale(Locale.getDefault().getLanguage() + "_" + Locale.getDefault().getCountry()); - if (!isValidLanguage(locale)) { // Bedrock does not support this language - locale = "en_US"; - loadGeyserLocale(locale); - } - if (GeyserConnector.getInstance() != null && - GeyserConnector.getInstance().getConfig() != null && (GeyserConnector.getInstance().getConfig().getDefaultLocale() == null || !isValid)) { // Means we should use the system locale for sure - CACHED_LOCALE = locale; - } - return locale; - } - - /** - * Ensures that the given locale is supported by Bedrock - * @param locale the locale to validate - * @return true if the given locale is supported by Bedrock and by extension Geyser - */ - private static boolean isValidLanguage(String locale) { - boolean result = true; - if (FileUtils.class.getResource("/languages/texts/" + locale + ".properties") == null) { - result = false; - if (GeyserConnector.getInstance() != null && GeyserConnector.getInstance().getLogger() != null) { // Could be too early for these to be initialized - if (locale.equals("en_US")) { - GeyserConnector.getInstance().getLogger().error("English locale not found in Geyser. Did you clone the submodules? (git submodule update --init)"); - } else { - GeyserConnector.getInstance().getLogger().warning(locale + " is not a valid Bedrock language."); // We can't translate this since we just loaded an invalid language - } - } - } else { - if (!LOCALE_MAPPINGS.containsKey(locale)) { - loadGeyserLocale(locale); - } - } - return result; - } - - public static void init() { - // no-op - } -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java b/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java deleted file mode 100644 index bd41c34a..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java +++ /dev/null @@ -1,83 +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.connector.utils; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; - -public class LoadstoneTracker { - - private static final Int2ObjectMap LOADSTONES = new Int2ObjectOpenHashMap<>(); - - /** - * Store the given coordinates and dimensions - * - * @param x The X position of the Loadstone - * @param y The Y position of the Loadstone - * @param z The Z position of the Loadstone - * @param dim The dimension containing of the Loadstone - * @return The id in the Map - */ - public static int store(int x, int y, int z, String dim) { - LoadstonePos pos = new LoadstonePos(x, y, z, dim); - - if (!LOADSTONES.containsValue(pos)) { - // Start at 1 as 0 seems to not work - LOADSTONES.put(LOADSTONES.size() + 1, pos); - } - - for (Int2ObjectMap.Entry loadstone : LOADSTONES.int2ObjectEntrySet()) { - if (loadstone.getValue().equals(pos)) { - return loadstone.getIntKey(); - } - } - - return 0; - } - - /** - * Get the loadstone data - * - * @param id The ID to get the data for - * @return The stored data - */ - public static LoadstonePos getPos(int id) { - return LOADSTONES.get(id); - } - - @Getter - @AllArgsConstructor - @EqualsAndHashCode - public static class LoadstonePos { - int x; - int y; - int z; - String dimension; - } -} \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index e180682d..f55cb261 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 @@ package org.geysermc.connector.utils; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.JsonNode; -import com.github.steveice10.mc.protocol.MinecraftConstants; import lombok.Getter; import org.geysermc.connector.GeyserConnector; import java.io.*; import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.nio.file.Paths; +import java.util.*; import java.util.zip.ZipFile; public class LocaleUtils { @@ -47,17 +43,18 @@ public class LocaleUtils { private static final Map ASSET_MAP = new HashMap<>(); - private static VersionDownload clientJarInfo; + private static final String DEFAULT_LOCALE = (GeyserConnector.getInstance().getConfig().getDefaultLocale() != null ? GeyserConnector.getInstance().getConfig().getDefaultLocale() : "en_us"); + + private static String smallestURL = ""; static { // Create the locales folder - File localesFolder = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales").toFile(); - //noinspection ResultOfMethodCallIgnored + File localesFolder = new File("locales/"); localesFolder.mkdir(); // Download the latest asset list and cache it generateAssetCache(); - downloadAndLoadLocale(LanguageUtils.getDefaultLocale()); + downloadAndLoadLocale(DEFAULT_LOCALE); } /** @@ -71,7 +68,7 @@ public class LocaleUtils { // Get the url for the latest version of the games manifest String latestInfoURL = ""; for (Version version : versionManifest.getVersions()) { - if (version.getId().equals(MinecraftConstants.GAME_VERSION)) { + if (version.getId().equals(versionManifest.getLatestVersion().getRelease())) { latestInfoURL = version.getUrl(); break; } @@ -79,16 +76,20 @@ public class LocaleUtils { // Make sure we definitely got a version if (latestInfoURL.isEmpty()) { - throw new Exception(LanguageUtils.getLocaleStringLog("geyser.locale.fail.latest_version")); + throw new Exception("Unable to get latest Minecraft version"); } // Get the individual version manifest VersionInfo versionInfo = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); - // Get the client jar for use when downloading the en_us locale - GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(versionInfo.getDownloads())); - clientJarInfo = versionInfo.getDownloads().get("client"); - GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(clientJarInfo)); + // Get the smallest jar for use when downloading the en_us locale, will be either the server or client + int currentSize = Integer.MAX_VALUE; + for (VersionDownload download : versionInfo.getDownloads().values()) { + if (download.getUrl().endsWith(".jar") && download.getSize() < currentSize) { + smallestURL = download.getUrl(); + currentSize = download.getSize(); + } + } // Get the assets list JsonNode assets = GeyserConnector.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); @@ -101,7 +102,7 @@ public class LocaleUtils { ASSET_MAP.put(entry.getKey(), asset); } } catch (Exception e) { - GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.locale.fail.asset_cache", (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace()))); + GeyserConnector.getInstance().getLogger().info("Failed to load locale asset cache: " + (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace())); } } @@ -115,7 +116,7 @@ public class LocaleUtils { // Check the locale isn't already loaded if (!ASSET_MAP.containsKey("minecraft/lang/" + locale + ".json") && !locale.equals("en_us")) { - GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.locale.fail.invalid", locale)); + GeyserConnector.getInstance().getLogger().warning("Invalid locale requested to download and load: " + locale); return; } @@ -131,33 +132,12 @@ public class LocaleUtils { * @param locale Locale to download */ private static void downloadLocale(String locale) { - File localeFile = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales/" + locale + ".json").toFile(); + File localeFile = new File("locales/" + locale + ".json"); // Check if we have already downloaded the locale file if (localeFile.exists()) { - String curHash = ""; - String targetHash = ""; - - if (locale.equals("en_us")) { - try { - File hashFile = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales/en_us.hash").toFile(); - if (hashFile.exists()) { - BufferedReader br = new BufferedReader(new FileReader(hashFile)); - curHash = br.readLine().trim(); - } - } catch (IOException ignored) { } - targetHash = clientJarInfo.getSha1(); - } else { - curHash = byteArrayToHexString(FileUtils.calculateSHA1(localeFile)); - targetHash = ASSET_MAP.get("minecraft/lang/" + locale + ".json").getHash(); - } - - if (!curHash.equals(targetHash)) { - GeyserConnector.getInstance().getLogger().debug("Locale out of date; re-downloading: " + locale); - } else { - GeyserConnector.getInstance().getLogger().debug("Locale already downloaded and up-to date: " + locale); - return; - } + GeyserConnector.getInstance().getLogger().debug("Locale already downloaded: " + locale); + return; } // Create the en_us locale @@ -169,7 +149,7 @@ public class LocaleUtils { // Get the hash and download the locale String hash = ASSET_MAP.get("minecraft/lang/" + locale + ".json").getHash(); - WebUtils.downloadFile("https://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash, localeFile.toString()); + WebUtils.downloadFile("http://resources.download.minecraft.net/" + hash.substring(0, 2) + "/" + hash, "locales/" + locale + ".json"); } /** @@ -178,7 +158,7 @@ public class LocaleUtils { * @param locale Locale to load */ private static void loadLocale(String locale) { - File localeFile = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales/" + locale + ".json").toFile(); + File localeFile = new File("locales/" + locale + ".json"); // Load the locale if (localeFile.exists()) { @@ -187,7 +167,7 @@ public class LocaleUtils { try { localeStream = new FileInputStream(localeFile); } catch (FileNotFoundException e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.file", locale, e.getMessage())); + throw new AssertionError("Unable to load locale: " + locale + " (" + e.getMessage() + ")"); } // Parse the file as json @@ -195,7 +175,7 @@ public class LocaleUtils { try { localeObj = GeyserConnector.JSON_MAPPER.readTree(localeStream); } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.json", locale), e); + throw new AssertionError("Unable to load Java edition lang map for " + locale, e); } // Parse all the locale fields @@ -209,7 +189,7 @@ public class LocaleUtils { // Insert the locale into the mappings LOCALE_MAPPINGS.put(locale.toLowerCase(), langMap); } else { - GeyserConnector.getInstance().getLogger().warning(LanguageUtils.getLocaleStringLog("geyser.locale.fail.missing", locale)); + GeyserConnector.getInstance().getLogger().warning("Missing locale file: " + locale); } } @@ -221,39 +201,35 @@ public class LocaleUtils { private static void downloadEN_US(File localeFile) { try { // Let the user know we are downloading the JAR - GeyserConnector.getInstance().getLogger().info(LanguageUtils.getLocaleStringLog("geyser.locale.download.en_us")); - GeyserConnector.getInstance().getLogger().debug("Download URL: " + clientJarInfo.getUrl()); + GeyserConnector.getInstance().getLogger().info("Downloading Minecraft JAR to extract en_us locale, please wait... (this may take some time depending on the speed of your internet connection)"); + GeyserConnector.getInstance().getLogger().debug("Download URL: " + smallestURL); // Download the smallest JAR (client or server) - Path tmpFilePath = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("tmp_locale.jar"); - WebUtils.downloadFile(clientJarInfo.getUrl(), tmpFilePath.toString()); + WebUtils.downloadFile(smallestURL, "tmp_locale.jar"); // Load in the JAR as a zip and extract the file - ZipFile localeJar = new ZipFile(tmpFilePath.toString()); - InputStream fileStream = localeJar.getInputStream(localeJar.getEntry("assets/minecraft/lang/en_us.json")); - FileOutputStream outStream = new FileOutputStream(localeFile); + ZipFile localeJar = new ZipFile("tmp_locale.jar"); + InputStream inputStream = localeJar.getInputStream(localeJar.getEntry("assets/minecraft/lang/en_us.json")); + FileOutputStream outputStream = new FileOutputStream(localeFile); // Write the file to the locale dir - byte[] buf = new byte[fileStream.available()]; - int length; - while ((length = fileStream.read(buf)) != -1) { - outStream.write(buf, 0, length); + int data = inputStream.read(); + while(data != -1){ + outputStream.write(data); + data = inputStream.read(); } // Flush all changes to disk and cleanup - outStream.flush(); - outStream.close(); + outputStream.flush(); + outputStream.close(); - fileStream.close(); + inputStream.close(); localeJar.close(); - // Store the latest jar hash - FileUtils.writeFile(GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("locales/en_us.hash").toString(), clientJarInfo.getSha1().toCharArray()); - // Delete the nolonger needed client/server jar - Files.delete(tmpFilePath); + Files.delete(Paths.get("tmp_locale.jar")); } catch (Exception e) { - throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.locale.fail.en_us"), e); + throw new AssertionError("Unable to download and extract en_us locale!", e); } } @@ -266,32 +242,12 @@ public class LocaleUtils { */ public static String getLocaleString(String messageText, String locale) { Map localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase()); - if (localeStrings == null) { - localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(LanguageUtils.getDefaultLocale()); - if (localeStrings == null) { - // Don't cause a NPE if the locale is STILL missing - GeyserConnector.getInstance().getLogger().debug("MISSING DEFAULT LOCALE: " + LanguageUtils.getDefaultLocale()); - return messageText; - } - } + if (localeStrings == null) + localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(DEFAULT_LOCALE); return localeStrings.getOrDefault(messageText, messageText); } - /** - * Convert a byte array into a hex string - * - * @param b Byte array to convert - * @return The hex representation of the given byte array - */ - private static String byteArrayToHexString(byte[] b) { - StringBuilder result = new StringBuilder(); - for (byte value : b) { - result.append(Integer.toString((value & 0xff) + 0x100, 16).substring(1)); - } - return result.toString(); - } - public static void init() { // no-op } @@ -398,4 +354,4 @@ class Asset { @JsonProperty("size") private int size; -} \ No newline at end of file +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java index fd7ef4e6..f9a7fec2 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LoginEncryptionUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 +29,19 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.JsonNodeType; -import com.github.steveice10.mc.auth.service.MsaAuthenticationService; import com.nimbusds.jose.JWSObject; 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.common.window.*; +import org.geysermc.common.window.CustomFormBuilder; +import org.geysermc.common.window.CustomFormWindow; +import org.geysermc.common.window.FormWindow; +import org.geysermc.common.window.SimpleFormWindow; import org.geysermc.common.window.button.FormButton; import org.geysermc.common.window.component.InputComponent; import org.geysermc.common.window.component.LabelComponent; import org.geysermc.common.window.response.CustomFormResponse; -import org.geysermc.common.window.response.ModalFormResponse; import org.geysermc.common.window.response.SimpleFormResponse; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; @@ -71,7 +72,7 @@ public class LoginEncryptionUtils { } if (lastKey != null) { - if (!EncryptionUtils.verifyJwt(jwt, lastKey)) return false; + EncryptionUtils.verifyJwt(jwt, lastKey); } JsonNode payloadNode = JSON_MAPPER.readTree(jwt.getPayload().toString()); @@ -104,10 +105,6 @@ public class LoginEncryptionUtils { connector.getLogger().debug(String.format("Is player data valid? %s", validChain)); - if (!validChain && !session.getConnector().getConfig().isEnableProxyConnections()) { - session.disconnect(LanguageUtils.getLocaleStringLog("geyser.network.remote.invalid_xbox_account")); - return; - } JWSObject jwt = JWSObject.parse(certChainData.get(certChainData.size() - 1).asText()); JsonNode payload = JSON_MAPPER.readTree(jwt.getPayload().toBytes()); @@ -155,64 +152,33 @@ public class LoginEncryptionUtils { session.sendUpstreamPacketImmediately(packet); } - private static final int AUTH_MSA_DETAILS_FORM_ID = 1334; - private static final int AUTH_MSA_CODE_FORM_ID = 1335; - private static final int AUTH_FORM_ID = 1336; - private static final int AUTH_DETAILS_FORM_ID = 1337; + private static int AUTH_FORM_ID = 1336; + private static int AUTH_DETAILS_FORM_ID = 1337; public static void showLoginWindow(GeyserSession session) { - // Set DoDaylightCycle to false so the time doesn't accelerate while we're here - session.setDaylightCycle(false); - - String userLanguage = session.getLocale(); - SimpleFormWindow window = new SimpleFormWindow(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.title", userLanguage), LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.desc", userLanguage)); - if (session.getConnector().getConfig().getRemote().isPasswordAuthentication()) { - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_login.mojang", userLanguage))); - } - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_login.microsoft", userLanguage))); - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_disconnect", userLanguage))); + SimpleFormWindow window = new SimpleFormWindow("Login", "You need a Java Edition account to play on this server."); + window.getButtons().add(new FormButton("Login with Minecraft")); + window.getButtons().add(new FormButton("Disconnect")); session.sendForm(window, AUTH_FORM_ID); } public static void showLoginDetailsWindow(GeyserSession session) { - String userLanguage = session.getLocale(); - CustomFormWindow window = new CustomFormBuilder(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.title", userLanguage)) - .addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.desc", userLanguage))) - .addComponent(new InputComponent(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.email", userLanguage), "account@geysermc.org", "")) - .addComponent(new InputComponent(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.details.pass", userLanguage), "123456", "")) + CustomFormWindow window = new CustomFormBuilder("Login Details") + .addComponent(new LabelComponent("Enter the credentials for your Minecraft: Java Edition account below.")) + .addComponent(new InputComponent("Email/Username", "account@geysermc.org", "")) + .addComponent(new InputComponent("Password", "123456", "")) .build(); session.sendForm(window, AUTH_DETAILS_FORM_ID); } - /** - * Prompts the user between either OAuth code login or manual password authentication - */ - public static void showMicrosoftAuthenticationWindow(GeyserSession session) { - String userLanguage = session.getLocale(); - SimpleFormWindow window = new SimpleFormWindow(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_login.microsoft", userLanguage), ""); - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.method.browser", userLanguage))); - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.method.password", userLanguage))); // This form won't show if password authentication is disabled - window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_disconnect", userLanguage))); - session.sendForm(window, AUTH_MSA_DETAILS_FORM_ID); - } - - /** - * Shows the code that a user must input into their browser - */ - public static void showMicrosoftCodeWindow(GeyserSession session, MsaAuthenticationService.MsCodeResponse response) { - ModalFormWindow msaCodeWindow = new ModalFormWindow("%xbox.signin", "%xbox.signin.website\n%xbox.signin.url\n%xbox.signin.enterCode\n" + - response.user_code, "Done", "%menu.disconnect"); - session.sendForm(msaCodeWindow, LoginEncryptionUtils.AUTH_MSA_CODE_FORM_ID); - } - public static boolean authenticateFromForm(GeyserSession session, GeyserConnector connector, int formId, String formData) { WindowCache windowCache = session.getWindowCache(); if (!windowCache.getWindows().containsKey(formId)) return false; - if (formId == AUTH_MSA_DETAILS_FORM_ID || formId == AUTH_FORM_ID || formId == AUTH_DETAILS_FORM_ID || formId == AUTH_MSA_CODE_FORM_ID) { + if(formId == AUTH_FORM_ID || formId == AUTH_DETAILS_FORM_ID) { FormWindow window = windowCache.getWindows().remove(formId); window.setResponse(formData.trim()); @@ -226,57 +192,23 @@ public class LoginEncryptionUtils { String password = response.getInputResponses().get(2); session.authenticate(email, password); - - // Clear windows so authentication data isn't accidentally cached - windowCache.getWindows().clear(); } else { showLoginDetailsWindow(session); } + + // Clear windows so authentication data isn't accidentally cached + windowCache.getWindows().clear(); } else if (formId == AUTH_FORM_ID && window instanceof SimpleFormWindow) { - boolean isPasswordAuthentication = session.getConnector().getConfig().getRemote().isPasswordAuthentication(); - int microsoftButton = isPasswordAuthentication ? 1 : 0; - int disconnectButton = isPasswordAuthentication ? 2 : 1; - SimpleFormResponse response = (SimpleFormResponse) window.getResponse(); - if (response != null) { - if (isPasswordAuthentication && response.getClickedButtonId() == 0) { - session.setMicrosoftAccount(false); - showLoginDetailsWindow(session); - } else if (response.getClickedButtonId() == microsoftButton) { - session.setMicrosoftAccount(true); - if (isPasswordAuthentication) { - showMicrosoftAuthenticationWindow(session); - } else { - // Just show the OAuth code - session.authenticateWithMicrosoftCode(); - } - } else if (response.getClickedButtonId() == disconnectButton) { - session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); - } - } else { - showLoginWindow(session); - } - } else if (formId == AUTH_MSA_DETAILS_FORM_ID && window instanceof SimpleFormWindow) { SimpleFormResponse response = (SimpleFormResponse) window.getResponse(); if (response != null) { if (response.getClickedButtonId() == 0) { - session.authenticateWithMicrosoftCode(); - } else if (response.getClickedButtonId() == 1) { showLoginDetailsWindow(session); - } else if (response.getClickedButtonId() == 2) { - session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); + } else if (response.getClickedButtonId() == 1) { + session.disconnect("Login is required"); } } else { showLoginWindow(session); } - } else if (formId == AUTH_MSA_CODE_FORM_ID && window instanceof ModalFormWindow) { - ModalFormResponse response = (ModalFormResponse) window.getResponse(); - if (response != null) { - if (response.getClickedButtonId() == 1) { - session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getLocale())); - } - } else { - showMicrosoftAuthenticationWindow(session); - } } } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/MapColor.java b/connector/src/main/java/org/geysermc/connector/utils/MapColor.java index f3752741..4328d758 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MapColor.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MapColor.java @@ -1,26 +1,27 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * - * 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. + * 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 * - * @author GeyserMC - * @link https://github.com/GeyserMC/Geyser */ package org.geysermc.connector.utils; @@ -30,238 +31,210 @@ public enum MapColor { COLOR_1(-1, -1, -1), COLOR_2(-1, -1, -1), COLOR_3(-1, -1, -1), - COLOR_4(90, 126, 40), - COLOR_5(110, 154, 48), + COLOR_4(89, 125, 39), + COLOR_5(109, 153, 48), COLOR_6(127, 178, 56), - COLOR_7(67, 94, 30), + COLOR_7(67, 94, 29), COLOR_8(174, 164, 115), - COLOR_9(213, 201, 141), + COLOR_9(213, 201, 140), COLOR_10(247, 233, 163), - COLOR_11(131, 123, 86), + COLOR_11(130, 123, 86), COLOR_12(140, 140, 140), - COLOR_13(172, 172, 172), + COLOR_13(171, 171, 171), COLOR_14(199, 199, 199), COLOR_15(105, 105, 105), COLOR_16(180, 0, 0), COLOR_17(220, 0, 0), COLOR_18(255, 0, 0), COLOR_19(135, 0, 0), - COLOR_20(113, 113, 180), + COLOR_20(112, 112, 180), COLOR_21(138, 138, 220), COLOR_22(160, 160, 255), - COLOR_23(85, 85, 135), - COLOR_24(118, 118, 118), + COLOR_23(84, 84, 135), + COLOR_24(117, 117, 117), COLOR_25(144, 144, 144), COLOR_26(167, 167, 167), COLOR_27(88, 88, 88), - COLOR_28(0, 88, 0), - COLOR_29(0, 107, 0), + COLOR_28(0, 87, 0), + COLOR_29(0, 106, 0), COLOR_30(0, 124, 0), - COLOR_31(0, 66, 0), + COLOR_31(0, 65, 0), COLOR_32(180, 180, 180), COLOR_33(220, 220, 220), COLOR_34(255, 255, 255), COLOR_35(135, 135, 135), - COLOR_36(116, 119, 130), - COLOR_37(141, 145, 159), + COLOR_36(115, 118, 129), + COLOR_37(141, 144, 158), COLOR_38(164, 168, 184), - COLOR_39(87, 89, 97), - COLOR_40(107, 77, 54), + COLOR_39(86, 88, 97), + COLOR_40(106, 76, 54), COLOR_41(130, 94, 66), COLOR_42(151, 109, 77), - COLOR_43(80, 58, 41), + COLOR_43(79, 57, 40), COLOR_44(79, 79, 79), - COLOR_45(97, 97, 97), + COLOR_45(96, 96, 96), COLOR_46(112, 112, 112), COLOR_47(59, 59, 59), COLOR_48(45, 45, 180), COLOR_49(55, 55, 220), COLOR_50(64, 64, 255), - COLOR_51(34, 34, 135), - COLOR_52(101, 84, 51), - COLOR_53(123, 103, 62), + COLOR_51(33, 33, 135), + COLOR_52(100, 84, 50), + COLOR_53(123, 102, 62), COLOR_54(143, 119, 72), - COLOR_55(76, 63, 38), - COLOR_56(180, 178, 173), + COLOR_55(75, 63, 38), + COLOR_56(180, 177, 172), COLOR_57(220, 217, 211), COLOR_58(255, 252, 245), - COLOR_59(135, 133, 130), - COLOR_60(152, 90, 36), - COLOR_61(186, 110, 44), + COLOR_59(135, 133, 129), + COLOR_60(152, 89, 36), + COLOR_61(186, 109, 44), COLOR_62(216, 127, 51), COLOR_63(114, 67, 27), - COLOR_64(126, 54, 152), - COLOR_65(154, 66, 186), + COLOR_64(125, 53, 152), + COLOR_65(153, 65, 186), COLOR_66(178, 76, 216), COLOR_67(94, 40, 114), COLOR_68(72, 108, 152), COLOR_69(88, 132, 186), COLOR_70(102, 153, 216), COLOR_71(54, 81, 114), - COLOR_72(162, 162, 36), - COLOR_73(198, 198, 44), + COLOR_72(161, 161, 36), + COLOR_73(197, 197, 44), COLOR_74(229, 229, 51), COLOR_75(121, 121, 27), - COLOR_76(90, 144, 18), - COLOR_77(110, 176, 22), + COLOR_76(89, 144, 17), + COLOR_77(109, 176, 21), COLOR_78(127, 204, 25), COLOR_79(67, 108, 13), - COLOR_80(171, 90, 116), - COLOR_81(209, 110, 142), + COLOR_80(170, 89, 116), + COLOR_81(208, 109, 142), COLOR_82(242, 127, 165), COLOR_83(128, 67, 87), - COLOR_84(54, 54, 54), - COLOR_85(66, 66, 66), + COLOR_84(53, 53, 53), + COLOR_85(65, 65, 65), COLOR_86(76, 76, 76), COLOR_87(40, 40, 40), COLOR_88(108, 108, 108), COLOR_89(132, 132, 132), COLOR_90(153, 153, 153), COLOR_91(81, 81, 81), - COLOR_92(54, 90, 108), - COLOR_93(66, 110, 132), + COLOR_92(53, 89, 108), + COLOR_93(65, 109, 132), COLOR_94(76, 127, 153), COLOR_95(40, 67, 81), - COLOR_96(90, 44, 126), - COLOR_97(110, 54, 154), + COLOR_96(89, 44, 125), + COLOR_97(109, 54, 153), COLOR_98(127, 63, 178), COLOR_99(67, 33, 94), - COLOR_100(36, 54, 126), - COLOR_101(44, 66, 154), + COLOR_100(36, 53, 125), + COLOR_101(44, 65, 153), COLOR_102(51, 76, 178), COLOR_103(27, 40, 94), - COLOR_104(72, 54, 36), - COLOR_105(88, 66, 44), + COLOR_104(72, 53, 36), + COLOR_105(88, 65, 44), COLOR_106(102, 76, 51), COLOR_107(54, 40, 27), - COLOR_108(72, 90, 36), - COLOR_109(88, 110, 44), + COLOR_108(72, 89, 36), + COLOR_109(88, 109, 44), COLOR_110(102, 127, 51), COLOR_111(54, 67, 27), COLOR_112(108, 36, 36), COLOR_113(132, 44, 44), COLOR_114(153, 51, 51), COLOR_115(81, 27, 27), - COLOR_116(18, 18, 18), - COLOR_117(22, 22, 22), + COLOR_116(17, 17, 17), + COLOR_117(21, 21, 21), COLOR_118(25, 25, 25), COLOR_119(13, 13, 13), COLOR_120(176, 168, 54), - COLOR_121(216, 205, 66), + COLOR_121(215, 205, 66), COLOR_122(250, 238, 77), - COLOR_123(132, 126, 41), - COLOR_124(65, 155, 150), - COLOR_125(79, 189, 184), + COLOR_123(132, 126, 40), + COLOR_124(64, 154, 150), + COLOR_125(79, 188, 183), COLOR_126(92, 219, 213), - COLOR_127(49, 116, 113), + COLOR_127(48, 115, 112), COLOR_128(52, 90, 180), - COLOR_129(64, 110, 220), + COLOR_129(63, 110, 220), COLOR_130(74, 128, 255), - COLOR_131(39, 68, 135), - COLOR_132(0, 153, 41), + COLOR_131(39, 67, 135), + COLOR_132(0, 153, 40), COLOR_133(0, 187, 50), COLOR_134(0, 217, 58), - COLOR_135(0, 115, 31), - COLOR_136(91, 61, 35), + COLOR_135(0, 114, 30), + COLOR_136(91, 60, 34), COLOR_137(111, 74, 42), COLOR_138(129, 86, 49), - COLOR_139(68, 46, 26), + COLOR_139(68, 45, 25), COLOR_140(79, 1, 0), - COLOR_141(97, 2, 0), + COLOR_141(96, 1, 0), COLOR_142(112, 2, 0), COLOR_143(59, 1, 0), - COLOR_144(148, 125, 114), - COLOR_145(180, 153, 139), + COLOR_144(147, 124, 113), + COLOR_145(180, 152, 138), COLOR_146(209, 177, 161), - COLOR_147(111, 94, 85), - COLOR_148(112, 58, 25), - COLOR_149(137, 71, 31), + COLOR_147(110, 93, 85), + COLOR_148(112, 57, 25), + COLOR_149(137, 70, 31), COLOR_150(159, 82, 36), COLOR_151(84, 43, 19), COLOR_152(105, 61, 76), - COLOR_153(129, 75, 93), + COLOR_153(128, 75, 93), COLOR_154(149, 87, 108), - COLOR_155(79, 46, 57), + COLOR_155(78, 46, 57), COLOR_156(79, 76, 97), - COLOR_157(97, 93, 119), + COLOR_157(96, 93, 119), COLOR_158(112, 108, 138), COLOR_159(59, 57, 73), - COLOR_160(131, 94, 25), - COLOR_161(160, 115, 31), + COLOR_160(131, 93, 25), + COLOR_161(160, 114, 31), COLOR_162(186, 133, 36), COLOR_163(98, 70, 19), - COLOR_164(73, 83, 37), - COLOR_165(89, 101, 46), + COLOR_164(72, 82, 37), + COLOR_165(88, 100, 45), COLOR_166(103, 117, 53), - COLOR_167(55, 62, 28), - COLOR_168(113, 54, 55), + COLOR_167(54, 61, 28), + COLOR_168(112, 54, 55), COLOR_169(138, 66, 67), COLOR_170(160, 77, 78), - COLOR_171(85, 41, 41), - COLOR_172(40, 29, 25), + COLOR_171(84, 40, 41), + COLOR_172(40, 28, 24), COLOR_173(49, 35, 30), COLOR_174(57, 41, 35), - COLOR_175(30, 22, 19), - COLOR_176(95, 76, 69), - COLOR_177(116, 92, 85), + COLOR_175(30, 21, 18), + COLOR_176(95, 75, 69), + COLOR_177(116, 92, 84), COLOR_178(135, 107, 98), - COLOR_179(71, 57, 52), - COLOR_180(61, 65, 65), + COLOR_179(71, 56, 51), + COLOR_180(61, 64, 64), COLOR_181(75, 79, 79), COLOR_182(87, 92, 92), - COLOR_183(46, 49, 49), - COLOR_184(86, 52, 62), - COLOR_185(105, 63, 76), + COLOR_183(46, 48, 48), + COLOR_184(86, 51, 62), + COLOR_185(105, 62, 75), COLOR_186(122, 73, 88), - COLOR_187(65, 39, 47), - COLOR_188(54, 44, 65), - COLOR_189(66, 53, 79), + COLOR_187(64, 38, 46), + COLOR_188(53, 43, 64), + COLOR_189(65, 53, 79), COLOR_190(76, 62, 92), - COLOR_191(40, 33, 49), - COLOR_192(54, 35, 25), - COLOR_193(66, 43, 30), + COLOR_191(40, 32, 48), + COLOR_192(53, 35, 24), + COLOR_193(65, 43, 30), COLOR_194(76, 50, 35), - COLOR_195(40, 26, 19), - COLOR_196(54, 58, 30), - COLOR_197(66, 71, 36), + COLOR_195(40, 26, 18), + COLOR_196(53, 57, 29), + COLOR_197(65, 70, 36), COLOR_198(76, 82, 42), COLOR_199(40, 43, 22), COLOR_200(100, 42, 32), - COLOR_201(123, 52, 40), + COLOR_201(122, 51, 39), COLOR_202(142, 60, 46), - COLOR_203(75, 32, 24), - COLOR_204(26, 16, 11), - COLOR_205(32, 19, 14), + COLOR_203(75, 31, 24), + COLOR_204(26, 15, 11), + COLOR_205(31, 18, 13), COLOR_206(37, 22, 16), - COLOR_207(20, 12, 8), - COLOR_208(133, 34, 35), - COLOR_209(163, 41, 42), - COLOR_210(189, 48, 49), - COLOR_211(100, 25, 26), - COLOR_212(104, 44, 68), - COLOR_213(128, 54, 84), - COLOR_214(148, 63, 97), - COLOR_215(78, 33, 51), - COLOR_216(65, 18, 20), - COLOR_217(79, 22, 25), - COLOR_218(92, 25, 29), - COLOR_219(49, 13, 15), - COLOR_220(16, 89, 95), - COLOR_221(19, 109, 116), - COLOR_222(22, 126, 134), - COLOR_223(12, 67, 71), - COLOR_224(41, 100, 99), - COLOR_225(50, 123, 121), - COLOR_226(58, 142, 140), - COLOR_227(31, 75, 74), - COLOR_228(61, 31, 44), - COLOR_229(74, 38, 53), - COLOR_230(86, 44, 62), - COLOR_231(46, 23, 33), - COLOR_232(14, 127, 94), - COLOR_233(17, 155, 115), - COLOR_234(20, 180, 133), - COLOR_235(11, 95, 70); + COLOR_207(19, 11, 8); private static final MapColor[] VALUES = values(); diff --git a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java index 0bb85442..f66e869d 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +27,6 @@ package org.geysermc.connector.utils; public class MathUtils { - public static final double SQRT_OF_TWO = Math.sqrt(2); - /** * Round the given float to the next whole number * @@ -40,26 +38,6 @@ public class MathUtils { return floatNumber > truncated ? truncated + 1 : truncated; } - /** - * If number is greater than the max, set it to max, and if number is lower than low, set it to low. - * @param num number to calculate - * @param min the lowest value the number can be - * @param max the greatest value the number can be - * @return - min if num is lower than min
- * - max if num is greater than max
- * - num otherwise - */ - public static double constrain(double num, double min, double max) { - if (num > max) { - num = max; - } - if (num < min) { - num = min; - } - - return num; - } - /** * Converts the given object from an int or byte to byte. * This is used for NBT data that might be either an int @@ -74,15 +52,4 @@ public class MathUtils { } return (Byte) value; } - - /** - * Packs a chunk's X and Z coordinates into a single {@code long}. - * - * @param x the X coordinate - * @param z the Z coordinate - * @return the packed coordinates - */ - public static long chunkPositionToLong(int x, int z) { - return ((x & 0xFFFFFFFFL) << 32L) | (z & 0xFFFFFFFFL); - } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java new file mode 100644 index 00000000..d79cdab8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.utils; + +import com.github.steveice10.mc.protocol.data.game.scoreboard.TeamColor; +import com.github.steveice10.mc.protocol.data.message.*; +import com.google.gson.*; +import net.kyori.text.Component; +import net.kyori.text.serializer.gson.GsonComponentSerializer; +import net.kyori.text.serializer.legacy.LegacyComponentSerializer; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MessageUtils { + + public static List getTranslationParams(Message[] messages, String locale) { + List strings = new ArrayList<>(); + for (Message message : messages) { + if (message instanceof TranslationMessage) { + TranslationMessage translation = (TranslationMessage) message; + + if (locale == null) { + String builder = "%" + translation.getTranslationKey(); + strings.add(builder); + } + + if (translation.getTranslationKey().equals("commands.gamemode.success.other")) { + strings.add(""); + } + + if (translation.getTranslationKey().equals("command.context.here")) { + strings.add(" - no permission or invalid command!"); + } + + List furtherParams = getTranslationParams(translation.getTranslationParams(), locale); + if (locale != null) { + strings.add(insertParams(LocaleUtils.getLocaleString(translation.getTranslationKey(), locale), furtherParams)); + } else { + strings.addAll(furtherParams); + } + } else { + String builder = getFormat(message.getStyle().getFormats()) + + getColorOrParent(message.getStyle()); + builder += getTranslatedBedrockMessage(message, locale, false); + strings.add(builder); + } + } + + return strings; + } + + public static List getTranslationParams(Message[] messages) { + return getTranslationParams(messages, null); + } + + public static String getTranslationText(TranslationMessage message) { + return getFormat(message.getStyle().getFormats()) + getColorOrParent(message.getStyle()) + + "%" + message.getTranslationKey(); + } + + public static String getTranslatedBedrockMessage(Message message, String locale, boolean shouldTranslate) { + JsonParser parser = new JsonParser(); + if (isMessage(message.getText())) { + JsonObject object = parser.parse(message.getText()).getAsJsonObject(); + message = Message.fromJson(formatJson(object)); + } + + String messageText = message.getText(); + if (locale != null && shouldTranslate) { + messageText = LocaleUtils.getLocaleString(messageText, locale); + } + + StringBuilder builder = new StringBuilder(); + builder.append(getFormat(message.getStyle().getFormats())); + builder.append(getColorOrParent(message.getStyle())); + builder.append(messageText); + + for (Message msg : message.getExtra()) { + builder.append(getFormat(msg.getStyle().getFormats())); + builder.append(getColorOrParent(msg.getStyle())); + if (!(msg.getText() == null)) { + boolean isTranslationMessage = (msg instanceof TranslationMessage); + String extraText = ""; + + if (isTranslationMessage) { + List paramsTranslated = getTranslationParams(((TranslationMessage) msg).getTranslationParams(), locale); + extraText = insertParams(getTranslatedBedrockMessage(msg, locale, isTranslationMessage), paramsTranslated); + } else { + extraText = getTranslatedBedrockMessage(msg, locale, isTranslationMessage); + } + + builder.append(extraText); + builder.append("\u00a7r"); + } + } + + return builder.toString(); + } + + public static String getTranslatedBedrockMessage(Message message, String locale) { + return getTranslatedBedrockMessage(message, locale, true); + } + + public static String getBedrockMessage(Message message) { + if (isMessage(message.getText())) { + return getBedrockMessage(message.getText()); + } else { + return getBedrockMessage(message.toJsonString()); + } + } + + /** + * Verifies the message is valid JSON in case it's plaintext. Works around GsonComponentSeraializer not using lenient mode. + * See https://wiki.vg/Chat for messages sent in lenient mode, and for a description on leniency. + * + * @param message Potentially lenient JSON message + * @return Bedrock formatted message + */ + public static String getBedrockMessageLenient(String message) { + if (isMessage(message)) { + return getBedrockMessage(message); + } else { + final JsonObject obj = new JsonObject(); + obj.addProperty("text", message); + return getBedrockMessage(obj.toString()); + } + } + + public static String getBedrockMessage(String message) { + Component component = phraseJavaMessage(message); + return LegacyComponentSerializer.legacy().serialize(component); + } + + public static Component phraseJavaMessage(String message) { + return GsonComponentSerializer.INSTANCE.deserialize(message); + } + + public static String getJavaMessage(String message) { + Component component = LegacyComponentSerializer.legacy().deserialize(message); + return GsonComponentSerializer.INSTANCE.serialize(component); + } + + /** + * Inserts the given parameters into the given message both in sequence and as requested + * + * @param message Message containing possible parameter replacement strings + * @param params A list of parameter strings + * @return Parsed message with all params inserted as needed + */ + public static String insertParams(String message, List params) { + String newMessage = message; + + Pattern p = Pattern.compile("%([1-9])\\$s"); + Matcher m = p.matcher(message); + while (m.find()) { + try { + newMessage = newMessage.replaceFirst("%" + m.group(1) + "\\$s", params.get(Integer.parseInt(m.group(1)) - 1)); + } catch (Exception e) { + // Couldn't find the param to replace + } + } + + for (String text : params) { + newMessage = newMessage.replaceFirst("%s", text.replaceAll("%s", "%r")); + } + + newMessage = newMessage.replaceAll("%r", "MISSING!"); + + return newMessage; + } + + /** + * Gets the colour for the message style or fetches it from the parent (recursive) + * + * @param style The style to get the colour from + * @return Colour string to be used + */ + private static String getColorOrParent(MessageStyle style) { + ChatColor chatColor = style.getColor(); + + if (chatColor == ChatColor.NONE && style.getParent() != null) { + return getColorOrParent(style.getParent()); + } + + return getColor(chatColor); + } + + /** + * Convert a ChatColor into a string for inserting into messages + * + * @param color ChatColor to convert + * @return The converted color string + */ + private static String getColor(ChatColor color) { + String base = "\u00a7"; + switch (color) { + case BLACK: + base += "0"; + break; + case DARK_BLUE: + base += "1"; + break; + case DARK_GREEN: + base += "2"; + break; + case DARK_AQUA: + base += "3"; + break; + case DARK_RED: + base += "4"; + break; + case DARK_PURPLE: + base += "5"; + break; + case GOLD: + base += "6"; + break; + case GRAY: + base += "7"; + break; + case DARK_GRAY: + base += "8"; + break; + case BLUE: + base += "9"; + break; + case GREEN: + base += "a"; + break; + case AQUA: + base += "b"; + break; + case RED: + base += "c"; + break; + case LIGHT_PURPLE: + base += "d"; + break; + case YELLOW: + base += "e"; + break; + case WHITE: + base += "f"; + break; + case RESET: + case NONE: + base += "r"; + break; + default: + return ""; + } + + return base; + } + + /** + * Convert a list of ChatFormats into a string for inserting into messages + * + * @param formats ChatFormats to convert + * @return The converted chat formatting string + */ + private static String getFormat(List formats) { + StringBuilder str = new StringBuilder(); + for (ChatFormat cf : formats) { + String base = "\u00a7"; + switch (cf) { + case OBFUSCATED: + base += "k"; + break; + case BOLD: + base += "l"; + break; + case STRIKETHROUGH: + base += "m"; + break; + case UNDERLINED: + base += "n"; + break; + case ITALIC: + base += "o"; + break; + default: + return ""; + } + + str.append(base); + } + + return str.toString(); + } + + /** + * Checks if the given text string is a json message + * + * @param text String to test + * @return True if its a valid message json string, false if not + */ + public static boolean isMessage(String text) { + JsonParser parser = new JsonParser(); + try { + JsonObject object = parser.parse(text).getAsJsonObject(); + try { + Message.fromJson(formatJson(object)); + } catch (Exception ex) { + return false; + } + } catch (Exception ex) { + return false; + } + return true; + } + + public static JsonObject formatJson(JsonObject object) { + if (object.has("hoverEvent")) { + JsonObject sub = (JsonObject) object.get("hoverEvent"); + JsonElement element = sub.get("value"); + + if (element instanceof JsonArray) { + JsonObject newobj = new JsonObject(); + newobj.add("extra", element); + newobj.addProperty("text", ""); + sub.remove("value"); + sub.add("value", newobj); + } + } + + if (object.has("extra")) { + JsonArray a = object.getAsJsonArray("extra"); + for (int i = 0; i < a.size(); i++) { + if (!(a.get(i) instanceof JsonPrimitive)) + formatJson((JsonObject) a.get(i)); + } + } + return object; + } + + public static String toChatColor(TeamColor teamColor) { + for (ChatColor color : ChatColor.values()) { + if (color.name().equals(teamColor.name())) { + return getColor(color); + } + } + for (ChatFormat format : ChatFormat.values()) { + if (format.name().equals(teamColor.name())) { + return getFormat(Collections.singletonList(format)); + } + } + return ""; + } + + /** + * Checks if the given message is over 256 characters (Java edition server chat limit) and sends a message to the user if it is + * + * @param message Message to check + * @param session GeyserSession for the user + * @return True if the message is too long, false if not + */ + public static boolean isTooLong(String message, GeyserSession session) { + if (message.length() > 256) { + // TODO: Add Geyser localization and translate this based on language + session.sendMessage("Your message is bigger than 256 characters (" + message.length() + ") so it has not been sent."); + return true; + } + + return false; + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java b/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java index 02482be3..63f1119c 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java +++ b/connector/src/main/java/org/geysermc/connector/utils/PaintingType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/connector/src/main/java/org/geysermc/connector/skin/ProvidedSkin.java b/connector/src/main/java/org/geysermc/connector/utils/ProvidedSkin.java similarity index 96% rename from connector/src/main/java/org/geysermc/connector/skin/ProvidedSkin.java rename to connector/src/main/java/org/geysermc/connector/utils/ProvidedSkin.java index 36b7d2d3..2c0165d3 100644 --- a/connector/src/main/java/org/geysermc/connector/skin/ProvidedSkin.java +++ b/connector/src/main/java/org/geysermc/connector/utils/ProvidedSkin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +23,7 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.skin; +package org.geysermc.connector.utils; import lombok.Getter; diff --git a/connector/src/main/java/org/geysermc/connector/utils/ResourcePack.java b/connector/src/main/java/org/geysermc/connector/utils/ResourcePack.java deleted file mode 100644 index bcb1ffd5..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/ResourcePack.java +++ /dev/null @@ -1,117 +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.connector.utils; - -import org.geysermc.connector.GeyserConnector; - -import java.io.File; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.ZipFile; - -/** - * This represents a resource pack and all the data relevant to it - */ -public class ResourcePack { - /** - * The list of loaded resource packs - */ - public static final Map PACKS = new HashMap<>(); - - /** - * The size of each chunk to use when sending the resource packs to clients in bytes - */ - public static final int CHUNK_SIZE = 102400; - - private byte[] sha256; - private File file; - private ResourcePackManifest manifest; - private ResourcePackManifest.Version version; - - /** - * Loop through the packs directory and locate valid resource pack files - */ - public static void loadPacks() { - File directory = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("packs").toFile(); - - if (!directory.exists()) { - directory.mkdir(); - - // As we just created the directory it will be empty - return; - } - - for (File file : directory.listFiles()) { - if (file.getName().endsWith(".zip") || file.getName().endsWith(".mcpack")) { - ResourcePack pack = new ResourcePack(); - - pack.sha256 = FileUtils.calculateSHA256(file); - - try { - ZipFile zip = new ZipFile(file); - - zip.stream().forEach((x) -> { - if (x.getName().contains("manifest.json")) { - try { - ResourcePackManifest manifest = FileUtils.loadJson(zip.getInputStream(x), ResourcePackManifest.class); - // Sometimes a pack_manifest file is present and not in a valid format, - // but a manifest file is, so we null check through that one - if (manifest.getHeader().getUuid() != null) { - pack.file = file; - pack.manifest = manifest; - pack.version = ResourcePackManifest.Version.fromArray(manifest.getHeader().getVersion()); - - PACKS.put(pack.getManifest().getHeader().getUuid().toString(), pack); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - }); - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.resource_pack.broken", file.getName())); - e.printStackTrace(); - } - } - } - } - - public byte[] getSha256() { - return sha256; - } - - public File getFile() { - return file; - } - - public ResourcePackManifest getManifest() { - return manifest; - } - - public ResourcePackManifest.Version getVersion() { - return version; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/ResourcePackManifest.java b/connector/src/main/java/org/geysermc/connector/utils/ResourcePackManifest.java deleted file mode 100644 index 972c732f..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/ResourcePackManifest.java +++ /dev/null @@ -1,117 +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.connector.utils; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.ToString; -import lombok.Value; - -import java.util.Collection; -import java.util.Collections; -import java.util.UUID; - -/** - * author: NukkitX - * Nukkit Project - */ -@Getter -@EqualsAndHashCode -public class ResourcePackManifest { - @JsonProperty("format_version") - private Integer formatVersion; - private Header header; - private Collection modules; - protected Collection dependencies; - - public Collection getModules() { - return Collections.unmodifiableCollection(modules); - } - - @Getter - @ToString - public static class Header { - private String description; - private String name; - private UUID uuid; - private int[] version; - @JsonProperty("min_engine_version") - private int[] minimumSupportedMinecraftVersion; - - public String getVersionString() { - return version[0] + "." + version[1] + "." + version[2]; - } - } - - @Getter - @ToString - public static class Module { - private String description; - private String name; - private UUID uuid; - private int[] version; - } - - @Getter - @ToString - public static class Dependency { - private UUID uuid; - private int[] version; - } - - @Value - public static class Version { - private final int major; - private final int minor; - private final int patch; - - public static Version fromString(String ver) { - String[] split = ver.replace(']', ' ') - .replace('[', ' ') - .replaceAll(" ", "").split(","); - - return new Version(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2])); - } - - public static Version fromArray(int[] ver) { - return new Version(ver[0], ver[1], ver[2]); - } - - private Version(int major, int minor, int patch) { - this.major = major; - this.minor = minor; - this.patch = patch; - } - - - @Override - public String toString() { - return major + "." + minor + "." + patch; - } - } -} - diff --git a/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java deleted file mode 100644 index 77afda53..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java +++ /dev/null @@ -1,166 +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.connector.utils; - -import com.github.steveice10.mc.protocol.data.game.entity.player.GameMode; -import com.github.steveice10.mc.protocol.data.game.setting.Difficulty; -import org.geysermc.common.window.CustomFormBuilder; -import org.geysermc.common.window.CustomFormWindow; -import org.geysermc.common.window.button.FormImage; -import org.geysermc.common.window.component.DropdownComponent; -import org.geysermc.common.window.component.InputComponent; -import org.geysermc.common.window.component.LabelComponent; -import org.geysermc.common.window.component.ToggleComponent; -import org.geysermc.common.window.response.CustomFormResponse; -import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; - -import java.util.ArrayList; - -public class SettingsUtils { - - // Used in UpstreamPacketHandler.java - public static final int SETTINGS_FORM_ID = 1338; - - /** - * Build a settings form for the given session and store it for later - * - * @param session The session to build the form for - */ - public static void buildForm(GeyserSession session) { - // Cache the language for cleaner access - String language = session.getLocale(); - - CustomFormBuilder builder = new CustomFormBuilder(LanguageUtils.getPlayerLocaleString("geyser.settings.title.main", language)); - builder.setIcon(new FormImage(FormImage.FormImageType.PATH, "textures/ui/settings_glyph_color_2x.png")); - - builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.client", language))); - builder.addComponent(new ToggleComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.option.coordinates", language), session.getWorldCache().isShowCoordinates())); - - - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { - builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.server", language))); - - DropdownComponent gamemodeDropdown = new DropdownComponent(); - gamemodeDropdown.setText("%createWorldScreen.gameMode.personal"); - gamemodeDropdown.setOptions(new ArrayList<>()); - for (GameMode gamemode : GameMode.values()) { - gamemodeDropdown.addOption(LocaleUtils.getLocaleString("selectWorld.gameMode." + gamemode.name().toLowerCase(), language), session.getGameMode() == gamemode); - } - builder.addComponent(gamemodeDropdown); - - DropdownComponent difficultyDropdown = new DropdownComponent(); - difficultyDropdown.setText("%options.difficulty"); - difficultyDropdown.setOptions(new ArrayList<>()); - for (Difficulty difficulty : Difficulty.values()) { - difficultyDropdown.addOption("%options.difficulty." + difficulty.name().toLowerCase(), session.getWorldCache().getDifficulty() == difficulty); - } - builder.addComponent(difficultyDropdown); - } - - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules")) { - builder.addComponent(new LabelComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.title.game_rules", language))); - for (GameRule gamerule : GameRule.values()) { - if (gamerule.equals(GameRule.UNKNOWN)) { - continue; - } - - // Add the relevant form item based on the gamerule type - if (Boolean.class.equals(gamerule.getType())) { - builder.addComponent(new ToggleComponent(LocaleUtils.getLocaleString("gamerule." + gamerule.getJavaID(), language), GeyserConnector.getInstance().getWorldManager().getGameRuleBool(session, gamerule))); - } else if (Integer.class.equals(gamerule.getType())) { - builder.addComponent(new InputComponent(LocaleUtils.getLocaleString("gamerule." + gamerule.getJavaID(), language), "", String.valueOf(GeyserConnector.getInstance().getWorldManager().getGameRuleInt(session, gamerule)))); - } - } - } - - session.setSettingsForm(builder.build()); - } - - /** - * Handle the settings form response - * - * @param session The session that sent the response - * @param response The response string to parse - * @return True if the form was parsed correctly, false if not - */ - public static boolean handleSettingsForm(GeyserSession session, String response) { - CustomFormWindow settingsForm = session.getSettingsForm(); - settingsForm.setResponse(response); - - CustomFormResponse settingsResponse = (CustomFormResponse) settingsForm.getResponse(); - if (settingsResponse == null) { - return false; - } - int offset = 0; - - offset++; // Client settings title - - session.getWorldCache().setShowCoordinates(settingsResponse.getToggleResponses().get(offset)); - offset++; - - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { - offset++; // Server settings title - - GameMode gameMode = GameMode.values()[settingsResponse.getDropdownResponses().get(offset).getElementID()]; - if (gameMode != null && gameMode != session.getGameMode()) { - session.getConnector().getWorldManager().setPlayerGameMode(session, gameMode); - } - offset++; - - Difficulty difficulty = Difficulty.values()[settingsResponse.getDropdownResponses().get(offset).getElementID()]; - if (difficulty != null && difficulty != session.getWorldCache().getDifficulty()) { - session.getConnector().getWorldManager().setDifficulty(session, difficulty); - } - offset++; - } - - if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.gamerules")) { - offset++; // Game rule title - - for (GameRule gamerule : GameRule.values()) { - if (gamerule.equals(GameRule.UNKNOWN)) { - continue; - } - - if (Boolean.class.equals(gamerule.getType())) { - Boolean value = settingsResponse.getToggleResponses().get(offset).booleanValue(); - if (value != session.getConnector().getWorldManager().getGameRuleBool(session, gamerule)) { - session.getConnector().getWorldManager().setGameRule(session, gamerule.getJavaID(), value); - } - } else if (Integer.class.equals(gamerule.getType())) { - int value = Integer.parseInt(settingsResponse.getInputResponses().get(offset)); - if (value != session.getConnector().getWorldManager().getGameRuleInt(session, gamerule)) { - session.getConnector().getWorldManager().setGameRule(session, gamerule.getJavaID(), value); - } - } - offset++; - } - } - - return true; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/SignUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SignUtils.java deleted file mode 100644 index f396fce9..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/SignUtils.java +++ /dev/null @@ -1,99 +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.connector.utils; - -/** - * Provides utilities for interacting with signs. Mainly, it deals with the widths of each character. - * Since Bedrock auto-wraps signs and Java does not, we have to take this into account when translating signs. - */ -public class SignUtils { - - // TODO: If we send the Java font via resource pack, does width change? - /** - * The maximum character width that a sign can hold in Bedrock - */ - public static final int BEDROCK_CHARACTER_WIDTH_MAX = 88; - - /** - * The maximum character width that a sign can hold in Java - */ - public static final int JAVA_CHARACTER_WIDTH_MAX = 90; - - /** - * Gets the Minecraft width of a character - * @param c character to determine - * @return width of the character - */ - public static int getCharacterWidth(char c) { - switch (c) { - case '!': - case ',': - case '.': - case ':': - case ';': - case 'i': - case '|': - case '¡': - return 2; - - case '\'': - case 'l': - case 'ì': - case 'í': - return 3; - - case ' ': - case 'I': - case '[': - case ']': - case 't': - case '×': - case 'ï': - return 4; - - case '"': - case '(': - case ')': - case '*': - case '<': - case '>': - case 'f': - case 'k': - case '{': - case '}': - return 5; - - case '@': - case '~': - case '®': - return 7; - - default: - return 6; - } - } - -} diff --git a/connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java similarity index 65% rename from connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java rename to connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java index 3f236932..aea9ba18 100644 --- a/connector/src/main/java/org/geysermc/connector/skin/SkinProvider.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,36 +23,26 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.skin; +package org.geysermc.connector.utils; 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; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import org.geysermc.connector.GeyserConnector; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.utils.FileUtils; -import org.geysermc.connector.utils.WebUtils; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.net.HttpURLConnection; +import java.io.*; import java.net.URL; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.*; +import java.util.Arrays; +import java.util.Base64; +import java.util.Map; +import java.util.UUID; import java.util.concurrent.*; public class SkinProvider { @@ -63,97 +53,79 @@ public class SkinProvider { public static final Skin EMPTY_SKIN = new Skin(-1, "steve", STEVE_SKIN); public static final byte[] ALEX_SKIN = new ProvidedSkin("bedrock/skin/skin_alex.png").getSkin(); public static final Skin EMPTY_SKIN_ALEX = new Skin(-1, "alex", ALEX_SKIN); - private static final Map permanentSkins = new HashMap() {{ - put("steve", EMPTY_SKIN); - put("alex", EMPTY_SKIN_ALEX); - }}; - private static final Cache cachedSkins = CacheBuilder.newBuilder() - .expireAfterAccess(1, TimeUnit.HOURS) - .build(); - - private static final Map> requestedSkins = new ConcurrentHashMap<>(); + private static Map cachedSkins = new ConcurrentHashMap<>(); + private static Map> requestedSkins = new ConcurrentHashMap<>(); public static final Cape EMPTY_CAPE = new Cape("", "no-cape", new byte[0], -1, true); - private static final Cache cachedCapes = CacheBuilder.newBuilder() - .expireAfterAccess(1, TimeUnit.HOURS) - .build(); - private static final Map> requestedCapes = new ConcurrentHashMap<>(); + private static Map cachedCapes = new ConcurrentHashMap<>(); + private static Map> requestedCapes = new ConcurrentHashMap<>(); public static final SkinGeometry EMPTY_GEOMETRY = SkinProvider.SkinGeometry.getLegacy(false); - private static final Map cachedGeometry = new ConcurrentHashMap<>(); + private static Map cachedGeometry = new ConcurrentHashMap<>(); public static final boolean ALLOW_THIRD_PARTY_EARS = GeyserConnector.getInstance().getConfig().isAllowThirdPartyEars(); public static String EARS_GEOMETRY; public static String EARS_GEOMETRY_SLIM; - public static SkinGeometry SKULL_GEOMETRY; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static final int CACHE_INTERVAL = 8 * 60 * 1000; // 8 minutes static { /* Load in the normal ears geometry */ - EARS_GEOMETRY = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.ears.json")), StandardCharsets.UTF_8); + InputStream earsStream = FileUtils.getResource("bedrock/skin/geometry.humanoid.ears.json"); + + StringBuilder earsDataBuilder = new StringBuilder(); + try (Reader reader = new BufferedReader(new InputStreamReader(earsStream, Charset.forName(StandardCharsets.UTF_8.name())))) { + int c = 0; + while ((c = reader.read()) != -1) { + earsDataBuilder.append((char) c); + } + } catch (IOException e) { + throw new AssertionError("Unable to load ears geometry", e); + } + + EARS_GEOMETRY = earsDataBuilder.toString(); + /* Load in the slim ears geometry */ - EARS_GEOMETRY_SLIM = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.earsSlim.json")), StandardCharsets.UTF_8); + earsStream = FileUtils.getResource("bedrock/skin/geometry.humanoid.earsSlim.json"); - /* Load in the custom skull geometry */ - String skullData = new String(FileUtils.readAllBytes(FileUtils.getResource("bedrock/skin/geometry.humanoid.customskull.json")), StandardCharsets.UTF_8); - SKULL_GEOMETRY = new SkinGeometry("{\"geometry\" :{\"default\" :\"geometry.humanoid.customskull\"}}", skullData, false); - - // Schedule Daily Image Expiry if we are caching them - if (GeyserConnector.getInstance().getConfig().getCacheImages() > 0) { - GeyserConnector.getInstance().getGeneralThreadPool().scheduleAtFixedRate(() -> { - File cacheFolder = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("images").toFile(); - if (!cacheFolder.exists()) { - return; - } - - int count = 0; - final long expireTime = ((long)GeyserConnector.getInstance().getConfig().getCacheImages()) * ((long)1000 * 60 * 60 * 24); - for (File imageFile : Objects.requireNonNull(cacheFolder.listFiles())) { - if (imageFile.lastModified() < System.currentTimeMillis() - expireTime) { - //noinspection ResultOfMethodCallIgnored - imageFile.delete(); - count++; - } - } - - if (count > 0) { - GeyserConnector.getInstance().getLogger().debug(String.format("Removed %d cached image files as they have expired", count)); - } - }, 10, 1440, TimeUnit.MINUTES); + earsDataBuilder = new StringBuilder(); + try (Reader reader = new BufferedReader(new InputStreamReader(earsStream, Charset.forName(StandardCharsets.UTF_8.name())))) { + int c = 0; + while ((c = reader.read()) != -1) { + earsDataBuilder.append((char) c); + } + } catch (IOException e) { + throw new AssertionError("Unable to load ears geometry", e); } + + EARS_GEOMETRY_SLIM = earsDataBuilder.toString(); + } + + public static boolean hasSkinCached(UUID uuid) { + return cachedSkins.containsKey(uuid); } public static boolean hasCapeCached(String capeUrl) { - return cachedCapes.getIfPresent(capeUrl) != null; + return cachedCapes.containsKey(capeUrl); } - public static Skin getCachedSkin(String skinUrl) { - return permanentSkins.getOrDefault(skinUrl, cachedSkins.getIfPresent(skinUrl)); + public static Skin getCachedSkin(UUID uuid) { + return cachedSkins.getOrDefault(uuid, EMPTY_SKIN); } public static Cape getCachedCape(String capeUrl) { - Cape cape = capeUrl != null ? cachedCapes.getIfPresent(capeUrl) : EMPTY_CAPE; - return cape != null ? cape : EMPTY_CAPE; + return capeUrl != null ? cachedCapes.getOrDefault(capeUrl, EMPTY_CAPE) : EMPTY_CAPE; } public static CompletableFuture requestSkinAndCape(UUID playerId, String skinUrl, String capeUrl) { return CompletableFuture.supplyAsync(() -> { long time = System.currentTimeMillis(); - String newSkinUrl = skinUrl; - - if ("steve".equals(skinUrl) || "alex".equals(skinUrl)) { - GeyserSession session = GeyserConnector.getInstance().getPlayerByUuid(playerId); - - if (session != null) { - newSkinUrl = session.getClientData().getSkinId(); - } - } CapeProvider provider = capeUrl != null ? CapeProvider.MINECRAFT : null; SkinAndCape skinAndCape = new SkinAndCape( - getOrDefault(requestSkin(playerId, newSkinUrl, false), EMPTY_SKIN, 5), + getOrDefault(requestSkin(playerId, skinUrl, false), EMPTY_SKIN, 5), getOrDefault(requestCape(capeUrl, provider, false), EMPTY_CAPE, 5) ); @@ -164,26 +136,28 @@ public class SkinProvider { public static CompletableFuture requestSkin(UUID playerId, String textureUrl, boolean newThread) { if (textureUrl == null || textureUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_SKIN); - if (requestedSkins.containsKey(textureUrl)) return requestedSkins.get(textureUrl); // already requested + if (requestedSkins.containsKey(playerId)) return requestedSkins.get(playerId); // already requested - Skin cachedSkin = getCachedSkin(textureUrl); - if (cachedSkin != null) { - return CompletableFuture.completedFuture(cachedSkin); + if ((System.currentTimeMillis() - CACHE_INTERVAL) < cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getRequestedOn()) { + // no need to update, still cached + return CompletableFuture.completedFuture(cachedSkins.get(playerId)); } CompletableFuture future; if (newThread) { future = CompletableFuture.supplyAsync(() -> supplySkin(playerId, textureUrl), EXECUTOR_SERVICE) .whenCompleteAsync((skin, throwable) -> { - skin.updated = true; - cachedSkins.put(textureUrl, skin); - requestedSkins.remove(textureUrl); + if (!cachedSkins.getOrDefault(playerId, EMPTY_SKIN).getTextureUrl().equals(textureUrl)) { + skin.updated = true; + cachedSkins.put(playerId, skin); + } + requestedSkins.remove(skin.getSkinOwner()); }); - requestedSkins.put(textureUrl, future); + requestedSkins.put(playerId, future); } else { Skin skin = supplySkin(playerId, textureUrl); future = CompletableFuture.completedFuture(skin); - cachedSkins.put(textureUrl, skin); + cachedSkins.put(playerId, skin); } return future; } @@ -192,9 +166,12 @@ public class SkinProvider { if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE); if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested - Cape cachedCape = cachedCapes.getIfPresent(capeUrl); - if (cachedCape != null) { - return CompletableFuture.completedFuture(cachedCape); + boolean officialCape = provider == CapeProvider.MINECRAFT; + boolean validCache = (System.currentTimeMillis() - CACHE_INTERVAL) < cachedCapes.getOrDefault(capeUrl, EMPTY_CAPE).getRequestedOn(); + + if ((cachedCapes.containsKey(capeUrl) && officialCape) || validCache) { + // the cape is an official cape (static) or the cape doesn't need a update yet + return CompletableFuture.completedFuture(cachedCapes.get(capeUrl)); } CompletableFuture future; @@ -266,22 +243,19 @@ public class SkinProvider { return CompletableFuture.completedFuture(officialSkin); } - public static CompletableFuture requestBedrockCape(UUID playerID) { - Cape bedrockCape = cachedCapes.getIfPresent(playerID.toString() + ".Bedrock"); - if (bedrockCape == null) { - bedrockCape = EMPTY_CAPE; - } + public static CompletableFuture requestBedrockCape(UUID playerID, boolean newThread) { + Cape bedrockCape = cachedCapes.getOrDefault(playerID.toString() + ".Bedrock", EMPTY_CAPE); return CompletableFuture.completedFuture(bedrockCape); } - public static CompletableFuture requestBedrockGeometry(SkinGeometry currentGeometry, UUID playerID) { + public static CompletableFuture requestBedrockGeometry(SkinGeometry currentGeometry, UUID playerID, boolean newThread) { SkinGeometry bedrockGeometry = cachedGeometry.getOrDefault(playerID, currentGeometry); return CompletableFuture.completedFuture(bedrockGeometry); } public static void storeBedrockSkin(UUID playerID, String skinID, byte[] skinData) { Skin skin = new Skin(playerID, skinID, skinData, System.currentTimeMillis(), true, false); - cachedSkins.put(skin.getTextureUrl(), skin); + cachedSkins.put(playerID, skin); } public static void storeBedrockCape(UUID playerID, byte[] capeData) { @@ -301,7 +275,7 @@ public class SkinProvider { * @param skin The skin to cache */ public static void storeEarSkin(UUID playerID, Skin skin) { - cachedSkins.put(skin.getTextureUrl(), skin); + cachedSkins.put(playerID, skin); } /** @@ -315,12 +289,11 @@ public class SkinProvider { } private static Skin supplySkin(UUID uuid, String textureUrl) { + byte[] skin = EMPTY_SKIN.getSkinData(); try { - byte[] skin = requestImage(textureUrl, null); - return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false); + skin = requestImage(textureUrl, null); } catch (Exception ignored) {} // just ignore I guess - - return new Skin(uuid, "empty", EMPTY_SKIN.getSkinData(), System.currentTimeMillis(), false, false); + return new Skin(uuid, textureUrl, skin, System.currentTimeMillis(), false, false); } private static Cape supplyCape(String capeUrl, CapeProvider provider) { @@ -382,38 +355,11 @@ public class SkinProvider { return existingSkin; } - @SuppressWarnings("ResultOfMethodCallIgnored") private static byte[] requestImage(String imageUrl, CapeProvider provider) throws Exception { - BufferedImage image = null; + BufferedImage image = downloadImage(imageUrl, provider); + GeyserConnector.getInstance().getLogger().debug("Downloaded " + imageUrl); - // First see if we have a cached file. We also update the modification stamp so we know when the file was last used - File imageFile = GeyserConnector.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("images").resolve(UUID.nameUUIDFromBytes(imageUrl.getBytes()).toString() + ".png").toFile(); - if (imageFile.exists()) { - try { - GeyserConnector.getInstance().getLogger().debug("Reading cached image from file " + imageFile.getPath() + " for " + imageUrl); - imageFile.setLastModified(System.currentTimeMillis()); - image = ImageIO.read(imageFile); - } catch (IOException ignored) {} - } - - // If no image we download it - if (image == null) { - image = downloadImage(imageUrl, provider); - GeyserConnector.getInstance().getLogger().debug("Downloaded " + imageUrl); - - // Write to cache if we are allowed - if (GeyserConnector.getInstance().getConfig().getCacheImages() > 0) { - imageFile.getParentFile().mkdirs(); - try { - ImageIO.write(image, "png", imageFile); - GeyserConnector.getInstance().getLogger().debug("Writing cached skin to file " + imageFile.getPath() + " for " + imageUrl); - } catch (IOException e) { - GeyserConnector.getInstance().getLogger().error("Failed to write cached skin to file " + imageFile.getPath() + " for " + imageUrl); - } - } - } - - // if the requested image is a cape + // if the requested image is an cape if (provider != null) { while(image.getWidth() > 64) { image = scale(image); @@ -430,68 +376,10 @@ public class SkinProvider { return data; } - /** - * If a skull has a username but no textures, request them. - * @param skullOwner the CompoundTag of the skull with no textures - * @return a completable GameProfile with textures included - */ - 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) { - int[] uuidAsArray = ((IntArrayTag) uuidTag).getValue(); - // thank u viaversion - UUID uuid = new UUID((long) uuidAsArray[0] << 32 | ((long) uuidAsArray[1] & 0xFFFFFFFFL), - (long) uuidAsArray[2] << 32 | ((long) uuidAsArray[3] & 0xFFFFFFFFL)); - retrieveUuidFromInternet = uuid.version() != 4; - uuidToString = uuid.toString().replace("-", ""); - } - - try { - if (retrieveUuidFromInternet) { - // Offline skin, or no present UUID - node = WebUtils.getJson("https://api.mojang.com/users/profiles/minecraft/" + skullOwner.get("Name").getValue()); - JsonNode id = node.get("id"); - if (id == null) { - GeyserConnector.getInstance().getLogger().debug("No UUID found in Mojang response for " + skullOwner.get("Name").getValue()); - return null; - } - uuidToString = id.asText(); - } - - // 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) { - GeyserConnector.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; - } catch (Exception e) { - if (GeyserConnector.getInstance().getConfig().isDebugMode()) { - e.printStackTrace(); - } - return null; - } - }, EXECUTOR_SERVICE); - } - private static BufferedImage downloadImage(String imageUrl, CapeProvider provider) throws IOException { if (provider == CapeProvider.FIVEZIG) return readFiveZigCape(imageUrl); - - HttpURLConnection con = (HttpURLConnection) new URL(imageUrl).openConnection(); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserConnector.getInstance().getPlatformType().toString() + "/" + GeyserConnector.VERSION); - - BufferedImage image = ImageIO.read(con.getInputStream()); + BufferedImage image = ImageIO.read(new URL(imageUrl)); if (image == null) throw new NullPointerException(); return image; } @@ -646,10 +534,10 @@ public class SkinProvider { @Getter public enum CapeProvider { MINECRAFT, - OPTIFINE("https://optifine.net/capes/%s.png", CapeUrlType.USERNAME), - LABYMOD("https://dl.labymod.net/capes/%s", CapeUrlType.UUID_DASHED), + OPTIFINE("http://s.optifine.net/capes/%s.png", CapeUrlType.USERNAME), + LABYMOD("https://www.labymod.net/page/php/getCapeTexture.php?uuid=%s", CapeUrlType.UUID_DASHED), FIVEZIG("https://textures.5zigreborn.eu/profile/%s", CapeUrlType.UUID_DASHED), - MINECRAFTCAPES("https://minecraftcapes.net/profile/%s/cape", CapeUrlType.UUID); + MINECRAFTCAPES("https://www.minecraftcapes.co.uk/getCape/%s", CapeUrlType.UUID); public static final CapeProvider[] VALUES = Arrays.copyOfRange(values(), 1, 5); private String url; @@ -685,7 +573,7 @@ public class SkinProvider { @NoArgsConstructor @Getter public enum EarsProvider { - MINECRAFTCAPES("https://minecraftcapes.net/profile/%s/ears", CapeUrlType.UUID); + MINECRAFTCAPES("https://www.minecraftcapes.co.uk/getEars/%s", CapeUrlType.UUID); public static final EarsProvider[] VALUES = values(); private String url; diff --git a/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java new file mode 100644 index 00000000..48e4c4c8 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * 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.connector.utils; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.steveice10.mc.auth.data.GameProfile; +import com.nukkitx.protocol.bedrock.data.ImageData; +import com.nukkitx.protocol.bedrock.data.SerializedSkin; +import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import org.geysermc.common.AuthType; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.auth.BedrockClientData; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.Collections; +import java.util.UUID; +import java.util.function.Consumer; + +public class SkinUtils { + + public static PlayerListPacket.Entry buildCachedEntry(GameProfile profile, long geyserId) { + GameProfileData data = GameProfileData.from(profile); + SkinProvider.Cape cape = SkinProvider.getCachedCape(data.getCapeUrl()); + + SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); + + return buildEntryManually( + profile.getId(), + profile.getName(), + geyserId, + profile.getIdAsString(), + SkinProvider.getCachedSkin(profile.getId()).getSkinData(), + cape.getCapeId(), + cape.getCapeData(), + geometry.getGeometryName(), + geometry.getGeometryData() + ); + } + + public static PlayerListPacket.Entry buildDefaultEntry(GameProfile profile, long geyserId) { + return buildEntryManually( + profile.getId(), + profile.getName(), + geyserId, + profile.getIdAsString(), + SkinProvider.STEVE_SKIN, + SkinProvider.EMPTY_CAPE.getCapeId(), + SkinProvider.EMPTY_CAPE.getCapeData(), + SkinProvider.EMPTY_GEOMETRY.getGeometryName(), + SkinProvider.EMPTY_GEOMETRY.getGeometryData() + ); + } + + public static PlayerListPacket.Entry buildEntryManually(UUID uuid, String username, long geyserId, + String skinId, byte[] skinData, + String capeId, byte[] capeData, + String geometryName, String geometryData) { + SerializedSkin serializedSkin = SerializedSkin.of( + skinId, geometryName, ImageData.of(skinData), Collections.emptyList(), + ImageData.of(capeData), geometryData, "", true, false, !capeId.equals(SkinProvider.EMPTY_CAPE.getCapeId()), capeId, uuid.toString() + ); + + PlayerListPacket.Entry entry = new PlayerListPacket.Entry(uuid); + entry.setName(username); + entry.setEntityId(geyserId); + entry.setSkin(serializedSkin); + entry.setXuid(""); + entry.setPlatformChatId(""); + entry.setTeacher(false); + return entry; + } + + @AllArgsConstructor + @Getter + public static class GameProfileData { + private String skinUrl; + private String capeUrl; + private boolean alex; + + /** + * Generate the GameProfileData from the given GameProfile + * + * @param profile GameProfile to build the GameProfileData from + * @return The built GameProfileData + */ + public static GameProfileData from(GameProfile profile) { + // Fallback to the offline mode of working it out + boolean isAlex = ((profile.getId().hashCode() % 2) == 1); + + try { + GameProfile.Property skinProperty = profile.getProperty("textures"); + + JsonNode skinObject = new ObjectMapper().readTree(new String(Base64.getDecoder().decode(skinProperty.getValue()), StandardCharsets.UTF_8)); + JsonNode textures = skinObject.get("textures"); + + JsonNode skinTexture = textures.get("SKIN"); + String skinUrl = skinTexture.get("url").asText(); + + isAlex = skinTexture.has("metadata"); + + String capeUrl = null; + if (textures.has("CAPE")) { + JsonNode capeTexture = textures.get("CAPE"); + capeUrl = capeTexture.get("url").asText(); + } + + return new GameProfileData(skinUrl, capeUrl, isAlex); + } catch (Exception exception) { + if (GeyserConnector.getInstance().getAuthType() != AuthType.OFFLINE) { + GeyserConnector.getInstance().getLogger().debug("Got invalid texture data for " + profile.getName() + " " + exception.getMessage()); + } + // return default skin with default cape when texture data is invalid + return new GameProfileData((isAlex ? SkinProvider.EMPTY_SKIN_ALEX.getTextureUrl() : SkinProvider.EMPTY_SKIN.getTextureUrl()), SkinProvider.EMPTY_CAPE.getTextureUrl(), isAlex); + } + } + } + + public static void requestAndHandleSkinAndCape(PlayerEntity entity, GeyserSession session, + Consumer skinAndCapeConsumer) { + GeyserConnector.getInstance().getGeneralThreadPool().execute(() -> { + GameProfileData data = GameProfileData.from(entity.getProfile()); + + SkinProvider.requestSkinAndCape(entity.getUuid(), data.getSkinUrl(), data.getCapeUrl()) + .whenCompleteAsync((skinAndCape, throwable) -> { + try { + SkinProvider.Skin skin = skinAndCape.getSkin(); + SkinProvider.Cape cape = skinAndCape.getCape(); + + if (cape.isFailed()) { + cape = SkinProvider.getOrDefault(SkinProvider.requestBedrockCape( + entity.getUuid(), false + ), SkinProvider.EMPTY_CAPE, 3); + } + + if (cape.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_CAPES) { + cape = SkinProvider.getOrDefault(SkinProvider.requestUnofficialCape( + cape, entity.getUuid(), + entity.getUsername(), false + ), SkinProvider.EMPTY_CAPE, SkinProvider.CapeProvider.VALUES.length * 3); + } + + SkinProvider.SkinGeometry geometry = SkinProvider.SkinGeometry.getLegacy(data.isAlex()); + geometry = SkinProvider.getOrDefault(SkinProvider.requestBedrockGeometry( + geometry, entity.getUuid(), false + ), geometry, 3); + + // Not a bedrock player check for ears + if (geometry.isFailed() && SkinProvider.ALLOW_THIRD_PARTY_EARS) { + boolean isEars = false; + + // Its deadmau5, gotta support his skin :) + if (entity.getUuid().toString().equals("1e18d5ff-643d-45c8-b509-43b8461d8614")) { + isEars = true; + } else { + // Get the ears texture for the player + skin = SkinProvider.getOrDefault(SkinProvider.requestUnofficialEars( + skin, entity.getUuid(), entity.getUsername(), false + ), skin, 3); + + isEars = skin.isEars(); + } + + // Does the skin have an ears texture + if (isEars) { + // Get the new geometry + geometry = SkinProvider.SkinGeometry.getEars(data.isAlex()); + + // Store the skin and geometry for the ears + SkinProvider.storeEarSkin(entity.getUuid(), skin); + SkinProvider.storeEarGeometry(entity.getUuid(), data.isAlex()); + } + } + + if (entity.getLastSkinUpdate() < skin.getRequestedOn()) { + entity.setLastSkinUpdate(skin.getRequestedOn()); + + if (session.getUpstream().isInitialized()) { + PlayerListPacket.Entry updatedEntry = buildEntryManually( + entity.getUuid(), + entity.getUsername(), + entity.getGeyserId(), + entity.getUuid().toString(), + skin.getSkinData(), + cape.getCapeId(), + cape.getCapeData(), + geometry.getGeometryName(), + geometry.getGeometryData() + ); + + // If it is our skin we replace the UUID with the authdata UUID + if (session.getPlayerEntity() == entity) { + // Copy the entry with our identity instead. + PlayerListPacket.Entry copy = new PlayerListPacket.Entry(session.getAuthData().getUUID()); + copy.setName(updatedEntry.getName()); + copy.setEntityId(updatedEntry.getEntityId()); + copy.setSkin(updatedEntry.getSkin()); + copy.setXuid(updatedEntry.getXuid()); + copy.setPlatformChatId(updatedEntry.getPlatformChatId()); + copy.setTeacher(updatedEntry.isTeacher()); + updatedEntry = copy; + } + + PlayerListPacket playerRemovePacket = new PlayerListPacket(); + playerRemovePacket.setAction(PlayerListPacket.Action.REMOVE); + playerRemovePacket.getEntries().add(updatedEntry); + session.sendUpstreamPacket(playerRemovePacket); + + PlayerListPacket playerAddPacket = new PlayerListPacket(); + playerAddPacket.setAction(PlayerListPacket.Action.ADD); + playerAddPacket.getEntries().add(updatedEntry); + session.sendUpstreamPacket(playerAddPacket); + + if(entity.getUuid().equals(session.getPlayerEntity().getUuid())) { + session.fetchOurSkin(updatedEntry); + } + } + } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().error("Failed getting skin for " + entity.getUuid(), e); + } + + if (skinAndCapeConsumer != null) skinAndCapeConsumer.accept(skinAndCape); + }); + }); + } + + public static void handleBedrockSkin(PlayerEntity playerEntity, BedrockClientData clientData) { + GameProfileData data = GameProfileData.from(playerEntity.getProfile()); + + GeyserConnector.getInstance().getLogger().info("Registering bedrock skin for " + playerEntity.getUsername() + " (" + playerEntity.getUuid() + ")"); + + try { + byte[] skinBytes = com.github.steveice10.mc.auth.util.Base64.decode(clientData.getSkinData().getBytes("UTF-8")); + byte[] capeBytes = clientData.getCapeData(); + + byte[] geometryNameBytes = Base64.getDecoder().decode(clientData.getGeometryName().getBytes("UTF-8")); + byte[] geometryBytes = Base64.getDecoder().decode(clientData.getGeometryData().getBytes("UTF-8")); + + if (skinBytes.length <= (128 * 128 * 4) && !clientData.isPersonaSkin()) { + SkinProvider.storeBedrockSkin(playerEntity.getUuid(), data.getSkinUrl(), skinBytes); + SkinProvider.storeBedrockGeometry(playerEntity.getUuid(), geometryNameBytes, geometryBytes); + } else { + GeyserConnector.getInstance().getLogger().info("Unable to load bedrock skin for '" + playerEntity.getUsername() + "' as they are likely using a customised skin"); + GeyserConnector.getInstance().getLogger().debug("The size of '" + playerEntity.getUsername() + "' skin is: " + clientData.getSkinImageWidth() + "x" + clientData.getSkinImageHeight()); + } + + if (!clientData.getCapeId().equals("")) { + SkinProvider.storeBedrockCape(playerEntity.getUuid(), capeBytes); + } + } catch (Exception e) { + throw new AssertionError("Failed to cache skin for bedrock user (" + playerEntity.getUsername() + "): ", e); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java b/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java deleted file mode 100644 index 7d2a75fc..00000000 --- a/connector/src/main/java/org/geysermc/connector/utils/StatisticsUtils.java +++ /dev/null @@ -1,233 +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.connector.utils; - -import com.github.steveice10.mc.protocol.data.MagicValues; -import com.github.steveice10.mc.protocol.data.game.entity.type.EntityType; -import com.github.steveice10.mc.protocol.data.game.statistic.*; -import org.geysermc.common.window.SimpleFormWindow; -import org.geysermc.common.window.button.FormButton; -import org.geysermc.common.window.response.SimpleFormResponse; -import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.item.ItemRegistry; -import org.geysermc.connector.network.translators.world.block.BlockTranslator; - -import java.util.Map; - -public class StatisticsUtils { - - // Used in UpstreamPacketHandler.java - public static final int STATISTICS_MENU_FORM_ID = 1339; - public static final int STATISTICS_LIST_FORM_ID = 1340; - - /** - * Build a form for the given session with all statistic categories - * - * @param session The session to build the form for - */ - public static SimpleFormWindow buildMenuForm(GeyserSession session) { - // Cache the language for cleaner access - String language = session.getClientData().getLanguageCode(); - - SimpleFormWindow window = new SimpleFormWindow(LocaleUtils.getLocaleString("gui.stats", language), ""); - - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.generalButton", language))); - - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.mined", language))); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.broken", language))); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.crafted", language))); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.used", language))); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.picked_up", language))); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.dropped", language))); - - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.mobsButton", language) + " - " + LanguageUtils.getPlayerLocaleString("geyser.statistics.killed", language))); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("stat.mobsButton", language) + " - " + LanguageUtils.getPlayerLocaleString("geyser.statistics.killed_by", language))); - - return window; - } - - /** - * Handle the menu form response - * - * @param session The session that sent the response - * @param response The response string to parse - * @return True if the form was parsed correctly, false if not - */ - public static boolean handleMenuForm(GeyserSession session, String response) { - SimpleFormWindow menuForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(STATISTICS_MENU_FORM_ID); - menuForm.setResponse(response); - SimpleFormResponse formResponse = (SimpleFormResponse) menuForm.getResponse(); - - // Cache the language for cleaner access - String language = session.getClientData().getLanguageCode(); - - if (formResponse != null && formResponse.getClickedButton() != null) { - String title; - StringBuilder content = new StringBuilder(); - - switch (formResponse.getClickedButtonId()) { - case 0: - title = LocaleUtils.getLocaleString("stat.generalButton", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof GenericStatistic) { - content.append(LocaleUtils.getLocaleString("stat.minecraft." + ((GenericStatistic) entry.getKey()).name().toLowerCase(), language) + ": " + entry.getValue() + "\n"); - } - } - break; - case 1: - title = LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.mined", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof BreakBlockStatistic) { - String block = BlockTranslator.JAVA_ID_TO_JAVA_IDENTIFIER_MAP.get(((BreakBlockStatistic) entry.getKey()).getId()); - block = block.replace("minecraft:", "block.minecraft."); - block = LocaleUtils.getLocaleString(block, language); - content.append(block + ": " + entry.getValue() + "\n"); - } - } - break; - case 2: - title = LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.broken", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof BreakItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((BreakItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); - content.append(getItemTranslateKey(item, language) + ": " + entry.getValue() + "\n"); - } - } - break; - case 3: - title = LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.crafted", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof CraftItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((CraftItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); - content.append(getItemTranslateKey(item, language) + ": " + entry.getValue() + "\n"); - } - } - break; - case 4: - title = LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.used", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof UseItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((UseItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); - content.append(getItemTranslateKey(item, language) + ": " + entry.getValue() + "\n"); - } - } - break; - case 5: - title = LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.picked_up", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof PickupItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((PickupItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); - content.append(getItemTranslateKey(item, language) + ": " + entry.getValue() + "\n"); - } - } - break; - case 6: - title = LocaleUtils.getLocaleString("stat.itemsButton", language) + " - " + LocaleUtils.getLocaleString("stat_type.minecraft.dropped", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof DropItemStatistic) { - String item = ItemRegistry.ITEM_ENTRIES.get(((DropItemStatistic) entry.getKey()).getId()).getJavaIdentifier(); - content.append(getItemTranslateKey(item, language) + ": " + entry.getValue() + "\n"); - } - } - break; - case 7: - title = LocaleUtils.getLocaleString("stat.mobsButton", language) + " - " + LanguageUtils.getPlayerLocaleString("geyser.statistics.killed", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof KillEntityStatistic) { - String mob = LocaleUtils.getLocaleString("entity.minecraft." + MagicValues.key(EntityType.class, ((KillEntityStatistic) entry.getKey()).getId()).name().toLowerCase(), language); - content.append(mob + ": " + entry.getValue() + "\n"); - } - } - break; - case 8: - title = LocaleUtils.getLocaleString("stat.mobsButton", language) + " - " + LanguageUtils.getPlayerLocaleString("geyser.statistics.killed_by", language); - - for (Map.Entry entry : session.getStatistics().entrySet()) { - if (entry.getKey() instanceof KilledByEntityStatistic) { - String mob = LocaleUtils.getLocaleString("entity.minecraft." + MagicValues.key(EntityType.class, ((KilledByEntityStatistic) entry.getKey()).getId()).name().toLowerCase(), language); - content.append(mob + ": " + entry.getValue() + "\n"); - } - } - break; - default: - return false; - } - - if (content.length() == 0) { - content = new StringBuilder(LanguageUtils.getPlayerLocaleString("geyser.statistics.none", language)); - } - - SimpleFormWindow window = new SimpleFormWindow(title, content.toString()); - window.getButtons().add(new FormButton(LocaleUtils.getLocaleString("gui.back", language))); - session.sendForm(window, STATISTICS_LIST_FORM_ID); - } - - return true; - } - - /** - * Handle the list form response - * - * @param session The session that sent the response - * @param response The response string to parse - * @return True if the form was parsed correctly, false if not - */ - public static boolean handleListForm(GeyserSession session, String response) { - SimpleFormWindow listForm = (SimpleFormWindow) session.getWindowCache().getWindows().get(STATISTICS_LIST_FORM_ID); - listForm.setResponse(response); - - if (!listForm.isClosed()) { - session.sendForm(buildMenuForm(session), STATISTICS_MENU_FORM_ID); - } - - return true; - } - - /** - * Finds the item translation key from the Java locale. - * - * @param item the namespaced item to search for. - * @param language the language to search in - * @return the full name of the item - */ - private static String getItemTranslateKey(String item, String language) { - item = item.replace("minecraft:", "item.minecraft."); - String translatedItem = LocaleUtils.getLocaleString(item, language); - if (translatedItem.equals(item)) { - // Didn't translate; must be a block - translatedItem = LocaleUtils.getLocaleString(item.replace("item.", "block."), language); - } - return translatedItem; - } -} diff --git a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java index 874fb062..50ab76d0 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/WebUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 +25,11 @@ package org.geysermc.connector.utils; -import com.fasterxml.jackson.databind.JsonNode; -import org.geysermc.connector.GeyserConnector; - -import java.io.*; +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @@ -50,26 +48,25 @@ public class WebUtils { url = new URL(reqURL); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserConnector.getInstance().getPlatformType().toString() + "/" + GeyserConnector.VERSION); // Otherwise Java 8 fails on checking updates - return connectionToString(con); + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuffer content = new StringBuffer(); + + while ((inputLine = in.readLine()) != null) { + content.append(inputLine); + content.append("\n"); + } + + in.close(); + con.disconnect(); + + return content.toString(); } catch (Exception e) { return e.getMessage(); } } - /** - * Makes a web request to the given URL and returns the body as a {@link JsonNode}. - * - * @param reqURL URL to fetch - * @return the response as JSON - */ - public static JsonNode getJson(String reqURL) throws IOException { - HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserConnector.getInstance().getPlatformType().toString() + "/" + GeyserConnector.VERSION); - return GeyserConnector.JSON_MAPPER.readTree(con.getInputStream()); - } - /** * Downloads a file from the given URL and saves it to disk * @@ -78,60 +75,10 @@ public class WebUtils { */ public static void downloadFile(String reqURL, String fileLocation) { try { - HttpURLConnection con = (HttpURLConnection) new URL(reqURL).openConnection(); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserConnector.getInstance().getPlatformType().toString() + "/" + GeyserConnector.VERSION); - InputStream in = con.getInputStream(); + InputStream in = new URL(reqURL).openStream(); Files.copy(in, Paths.get(fileLocation), StandardCopyOption.REPLACE_EXISTING); } catch (Exception e) { throw new AssertionError("Unable to download and save file: " + fileLocation + " (" + reqURL + ")", e); } } - - public static String post(String reqURL, String postContent) throws IOException { - URL url = null; - url = new URL(reqURL); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("POST"); - con.setRequestProperty("Content-Type", "text/plain"); - con.setRequestProperty("User-Agent", "Geyser-" + GeyserConnector.getInstance().getPlatformType().toString() + "/" + GeyserConnector.VERSION); - con.setDoOutput(true); - - OutputStream out = con.getOutputStream(); - out.write(postContent.getBytes(StandardCharsets.UTF_8)); - out.close(); - - return connectionToString(con); - } - - /** - * Get the string output from the passed {@link HttpURLConnection} - * - * @param con The connection to get the string from - * @return The body of the returned page - * @throws IOException - */ - private static String connectionToString(HttpURLConnection con) throws IOException { - // Send the request (we dont use this but its required for getErrorStream() to work) - int code = con.getResponseCode(); - - // Read the error message if there is one if not just read normally - InputStream inputStream = con.getErrorStream(); - if (inputStream == null) { - inputStream = con.getInputStream(); - } - - BufferedReader in = new BufferedReader(new InputStreamReader(inputStream)); - String inputLine; - StringBuffer content = new StringBuffer(); - - while ((inputLine = in.readLine()) != null) { - content.append(inputLine); - content.append("\n"); - } - - in.close(); - con.disconnect(); - - return content.toString(); - } } diff --git a/connector/src/main/resources/bedrock/biome_definitions.dat b/connector/src/main/resources/bedrock/biome_definitions.dat index 6d72cc92..b8c6df4a 100644 Binary files a/connector/src/main/resources/bedrock/biome_definitions.dat and b/connector/src/main/resources/bedrock/biome_definitions.dat differ diff --git a/connector/src/main/resources/bedrock/blockpalette.nbt b/connector/src/main/resources/bedrock/blockpalette.nbt deleted file mode 100644 index b92a0626..00000000 Binary files a/connector/src/main/resources/bedrock/blockpalette.nbt and /dev/null differ diff --git a/connector/src/main/resources/bedrock/creative_items.json b/connector/src/main/resources/bedrock/creative_items.json index 90839b0d..8045b219 100644 --- a/connector/src/main/resources/bedrock/creative_items.json +++ b/connector/src/main/resources/bedrock/creative_items.json @@ -23,12 +23,6 @@ "id" : 5, "damage" : 5 }, - { - "id" : -242 - }, - { - "id" : -243 - }, { "id" : 139 }, @@ -84,15 +78,6 @@ "id" : 139, "damage" : 11 }, - { - "id" : -277 - }, - { - "id" : -297 - }, - { - "id" : -278 - }, { "id" : 85 }, @@ -119,12 +104,6 @@ { "id" : 113 }, - { - "id" : -256 - }, - { - "id" : -257 - }, { "id" : 107 }, @@ -143,12 +122,6 @@ { "id" : 186 }, - { - "id" : -258 - }, - { - "id" : -259 - }, { "id" : -180 }, @@ -243,46 +216,25 @@ "id" : -4 }, { - "id" : -254 + "id" : 324 }, { - "id" : -255 + "id" : 427 }, { - "id" : -276 + "id" : 428 }, { - "id" : -292 + "id" : 429 }, { - "id" : -275 + "id" : 430 }, { - "id" : 359 + "id" : 431 }, { - "id" : 543 - }, - { - "id" : 544 - }, - { - "id" : 545 - }, - { - "id" : 546 - }, - { - "id" : 547 - }, - { - "id" : 370 - }, - { - "id" : 604 - }, - { - "id" : 605 + "id" : 330 }, { "id" : 96 @@ -305,12 +257,6 @@ { "id" : 167 }, - { - "id" : -246 - }, - { - "id" : -247 - }, { "id" : 101 }, @@ -583,33 +529,9 @@ "id" : 182, "damage" : 4 }, - { - "id" : -264 - }, - { - "id" : -265 - }, - { - "id" : -282 - }, - { - "id" : -293 - }, - { - "id" : -284 - }, { "id" : 45 }, - { - "id" : -302 - }, - { - "id" : -303 - }, - { - "id" : -304 - }, { "id" : 98 }, @@ -632,18 +554,6 @@ "id" : 168, "damage" : 2 }, - { - "id" : -274 - }, - { - "id" : -280 - }, - { - "id" : -281 - }, - { - "id" : -279 - }, { "id" : 4 }, @@ -741,18 +651,15 @@ { "id" : 216 }, + { + "id" : 214 + }, { "id" : 112 }, { "id" : 215 }, - { - "id" : -270 - }, - { - "id" : -222 - }, { "id" : 35 }, @@ -1129,30 +1036,6 @@ "id" : 201, "damage" : 2 }, - { - "id" : 214 - }, - { - "id" : -227 - }, - { - "id" : -230 - }, - { - "id" : -232 - }, - { - "id" : -233 - }, - { - "id" : -234 - }, - { - "id" : -235 - }, - { - "id" : -236 - }, { "id" : 3 }, @@ -1160,9 +1043,6 @@ "id" : 3, "damage" : 1 }, - { - "id" : 60 - }, { "id" : 2 }, @@ -1202,12 +1082,6 @@ { "id" : 153 }, - { - "id" : -288 - }, - { - "id" : -271 - }, { "id" : 13 }, @@ -1223,9 +1097,6 @@ "id" : 1, "damage" : 5 }, - { - "id" : -273 - }, { "id" : 1, "damage" : 2 @@ -1238,9 +1109,6 @@ "id" : 1, "damage" : 6 }, - { - "id" : -291 - }, { "id" : 12 }, @@ -1291,18 +1159,6 @@ { "id" : -9 }, - { - "id" : -225 - }, - { - "id" : -240 - }, - { - "id" : -226 - }, - { - "id" : -241 - }, { "id" : -212 }, @@ -1350,18 +1206,6 @@ "id" : -212, "damage" : 13 }, - { - "id" : -299 - }, - { - "id" : -300 - }, - { - "id" : -298 - }, - { - "id" : -301 - }, { "id" : 18 }, @@ -1410,56 +1254,56 @@ { "id" : -218 }, - { - "id" : 291 - }, - { - "id" : 292 - }, - { - "id" : 293 - }, { "id" : 295 }, { - "id" : 334 + "id" : 361 }, { - "id" : 285 + "id" : 362 }, { - "id" : 280 + "id" : 458 }, { - "id" : 282 + "id" : 296 }, { - "id" : 279 + "id" : 457 }, { - "id" : 283 + "id" : 392 }, { - "id" : 257 + "id" : 394 }, { - "id" : 258 + "id" : 391 }, { - "id" : 259 + "id" : 396 + }, + { + "id" : 260 + }, + { + "id" : 322 + }, + { + "id" : 466 }, { "id" : 103 }, { - "id" : 272 + "id" : 360 }, { - "id" : 432 + "id" : 382 }, { - "id" : 287 + "id" : 477 }, { "id" : 86 @@ -1471,7 +1315,7 @@ "id" : 91 }, { - "id" : 580 + "id" : 736 }, { "id" : 31, @@ -1489,9 +1333,6 @@ "id" : 175, "damage" : 2 }, - { - "id" : 609 - }, { "id" : -131, "damage" : 3 @@ -1570,17 +1411,11 @@ "damage" : 4 }, { - "id" : 380 + "id" : 335 }, { "id" : -130 }, - { - "id" : -223 - }, - { - "id" : -224 - }, { "id" : 37 }, @@ -1646,74 +1481,87 @@ "id" : -216 }, { - "id" : 408 + "id" : 351, + "damage" : 19 }, { - "id" : 400 + "id" : 351, + "damage" : 7 }, { - "id" : 401 + "id" : 351, + "damage" : 8 }, { - "id" : 393 + "id" : 351, + "damage" : 16 }, { - "id" : 396 + "id" : 351, + "damage" : 17 }, { - "id" : 394 + "id" : 351, + "damage" : 1 }, { - "id" : 407 + "id" : 351, + "damage" : 14 }, { - "id" : 404 + "id" : 351, + "damage" : 11 }, { - "id" : 403 + "id" : 351, + "damage" : 10 }, { - "id" : 395 + "id" : 351, + "damage" : 2 }, { - "id" : 399 + "id" : 351, + "damage" : 6 }, { - "id" : 405 + "id" : 351, + "damage" : 12 }, { - "id" : 397 + "id" : 351, + "damage" : 18 }, { - "id" : 398 + "id" : 351, + "damage" : 5 }, { - "id" : 406 + "id" : 351, + "damage" : 13 }, { - "id" : 402 + "id" : 351, + "damage" : 9 }, { - "id" : 411 + "id" : 351 }, { - "id" : 410 + "id" : 351, + "damage" : 3 }, { - "id" : 412 + "id" : 351, + "damage" : 4 }, { - "id" : 409 + "id" : 351, + "damage" : 15 }, { "id" : 106 }, - { - "id" : -231 - }, - { - "id" : -287 - }, { "id" : 111 }, @@ -1739,31 +1587,31 @@ "id" : 78 }, { - "id" : 275 + "id" : 365 }, { - "id" : 262 + "id" : 319 }, { - "id" : 273 + "id" : 363 }, { - "id" : 540 + "id" : 423 }, { - "id" : 288 + "id" : 411 }, { - "id" : 264 + "id" : 349 }, { - "id" : 265 + "id" : 460 }, { - "id" : 266 + "id" : 461 }, { - "id" : 267 + "id" : 462 }, { "id" : 39 @@ -1771,12 +1619,6 @@ { "id" : 40 }, - { - "id" : -228 - }, - { - "id" : -229 - }, { "id" : 99, "damage" : 14 @@ -1793,25 +1635,25 @@ "id" : 99 }, { - "id" : 388 + "id" : 344 }, { - "id" : 383 + "id" : 338 }, { - "id" : 414 + "id" : 353 }, { - "id" : 277 + "id" : 367 }, { - "id" : 413 + "id" : 352 }, { "id" : 30 }, { - "id" : 278 + "id" : 375 }, { "id" : 52 @@ -1846,200 +1688,240 @@ "id" : -159 }, { - "id" : 433 + "id" : 383, + "damage" : 10 }, { - "id" : 492 + "id" : 383, + "damage" : 122 }, { - "id" : 434 + "id" : 383, + "damage" : 11 }, { - "id" : 435 + "id" : 383, + "damage" : 12 }, { - "id" : 436 + "id" : 383, + "damage" : 13 }, { - "id" : 437 + "id" : 383, + "damage" : 14 }, { - "id" : 470 + "id" : 383, + "damage" : 28 }, { - "id" : 449 + "id" : 383, + "damage" : 22 }, { - "id" : 486 + "id" : 383, + "damage" : 75 }, { - "id" : 438 + "id" : 383, + "damage" : 16 }, { - "id" : 451 + "id" : 383, + "damage" : 19 }, { - "id" : 476 + "id" : 383, + "damage" : 30 }, { - "id" : 457 + "id" : 383, + "damage" : 18 }, { - "id" : 471 + "id" : 383, + "damage" : 29 }, { - "id" : 456 + "id" : 383, + "damage" : 23 }, { - "id" : 463 + "id" : 383, + "damage" : 24 }, { - "id" : 464 + "id" : 383, + "damage" : 25 }, { - "id" : 465 + "id" : 383, + "damage" : 26 }, { - "id" : 466 + "id" : 383, + "damage" : 27 }, { - "id" : 477 + "id" : 383, + "damage" : 111 }, { - "id" : 478 + "id" : 383, + "damage" : 112 }, { - "id" : 479 + "id" : 383, + "damage" : 108 }, { - "id" : 480 + "id" : 383, + "damage" : 109 }, { - "id" : 482 + "id" : 383, + "damage" : 31 }, { - "id" : 483 + "id" : 383, + "damage" : 74 }, { - "id" : 487 + "id" : 383, + "damage" : 113 }, { - "id" : 488 + "id" : 383, + "damage" : 121 }, { - "id" : 439 + "id" : 383, + "damage" : 33 }, { - "id" : 440 + "id" : 383, + "damage" : 38 }, { - "id" : 441 + "id" : 383, + "damage" : 39 }, { - "id" : 442 + "id" : 383, + "damage" : 34 }, { - "id" : 462 + "id" : 383, + "damage" : 48 }, { - "id" : 460 + "id" : 383, + "damage" : 46 }, { - "id" : 443 + "id" : 383, + "damage" : 37 }, { - "id" : 444 + "id" : 383, + "damage" : 35 }, { - "id" : 445 + "id" : 383, + "damage" : 32 }, { - "id" : 446 + "id" : 383, + "damage" : 36 }, { - "id" : 461 + "id" : 383, + "damage" : 47 }, { - "id" : 481 + "id" : 383, + "damage" : 110 }, { - "id" : 448 + "id" : 383, + "damage" : 17 }, { - "id" : 455 + "id" : 383, + "damage" : 40 }, { - "id" : 450 + "id" : 383, + "damage" : 45 }, { - "id" : 459 + "id" : 383, + "damage" : 49 }, { - "id" : 469 + "id" : 383, + "damage" : 50 }, { - "id" : 458 + "id" : 383, + "damage" : 55 }, { - "id" : 453 + "id" : 383, + "damage" : 42 }, { - "id" : 493 + "id" : 383, + "damage" : 41 }, { - "id" : 494 + "id" : 383, + "damage" : 43 }, { - "id" : 495 + "id" : 383, + "damage" : 54 }, { - "id" : 496 + "id" : 383, + "damage" : 57 }, { - "id" : 497 + "id" : 383, + "damage" : 104 }, { - "id" : 452 + "id" : 383, + "damage" : 105 }, { - "id" : 454 + "id" : 383, + "damage" : 115 }, { - "id" : 467 + "id" : 383, + "damage" : 118 }, { - "id" : 472 + "id" : 383, + "damage" : 116 }, { - "id" : 473 + "id" : 383, + "damage" : 58 }, { - "id" : 474 + "id" : 383, + "damage" : 114 }, { - "id" : 447 - }, - { - "id" : 490 - }, - { - "id" : 475 - }, - { - "id" : 484 - }, - { - "id" : 489 - }, - { - "id" : 491 + "id" : 383, + "damage" : 59 }, { "id" : 49 }, - { - "id" : -289 - }, { "id" : 7 }, @@ -2053,7 +1935,7 @@ "id" : 213 }, { - "id" : 294 + "id" : 372 }, { "id" : 121 @@ -2065,10 +1947,10 @@ "id" : 240 }, { - "id" : 548 + "id" : 432 }, { - "id" : 549 + "id" : 433 }, { "id" : 19 @@ -2116,1041 +1998,989 @@ "id" : -132, "damage" : 12 }, - { - "id" : 335 - }, - { - "id" : 339 - }, - { - "id" : 343 - }, - { - "id" : 351 - }, - { - "id" : 347 - }, - { - "id" : 597 - }, - { - "id" : 336 - }, - { - "id" : 340 - }, - { - "id" : 344 - }, - { - "id" : 352 - }, - { - "id" : 348 - }, - { - "id" : 598 - }, - { - "id" : 337 - }, - { - "id" : 341 - }, - { - "id" : 345 - }, - { - "id" : 353 - }, - { - "id" : 349 - }, - { - "id" : 599 - }, - { - "id" : 338 - }, - { - "id" : 342 - }, - { - "id" : 346 - }, - { - "id" : 354 - }, - { - "id" : 350 - }, - { - "id" : 600 - }, - { - "id" : 308 - }, - { - "id" : 312 - }, - { - "id" : 307 - }, - { - "id" : 322 - }, - { - "id" : 316 - }, - { - "id" : 592 - }, - { - "id" : 311 - }, - { - "id" : 315 - }, { "id" : 298 }, { - "id" : 325 + "id" : 302 }, { - "id" : 319 - }, - { - "id" : 595 - }, - { - "id" : 310 + "id" : 306 }, { "id" : 314 }, { - "id" : 297 - }, - { - "id" : 324 - }, - { - "id" : 318 - }, - { - "id" : 594 - }, - { - "id" : 309 - }, - { - "id" : 313 - }, - { - "id" : 296 - }, - { - "id" : 323 - }, - { - "id" : 317 - }, - { - "id" : 593 - }, - { - "id" : 329 - }, - { - "id" : 330 - }, - { - "id" : 331 - }, - { - "id" : 333 - }, - { - "id" : 332 - }, - { - "id" : 596 - }, - { - "id" : 300 - }, - { - "id" : 565 - }, - { - "id" : 301 - }, - { - "id" : 301, - "damage" : 6 - }, - { - "id" : 301, - "damage" : 7 - }, - { - "id" : 301, - "damage" : 8 - }, - { - "id" : 301, - "damage" : 9 - }, - { - "id" : 301, - "damage" : 10 - }, - { - "id" : 301, - "damage" : 11 - }, - { - "id" : 301, - "damage" : 12 - }, - { - "id" : 301, - "damage" : 13 - }, - { - "id" : 301, - "damage" : 14 - }, - { - "id" : 301, - "damage" : 15 - }, - { - "id" : 301, - "damage" : 16 - }, - { - "id" : 301, - "damage" : 17 - }, - { - "id" : 301, - "damage" : 18 - }, - { - "id" : 301, - "damage" : 19 - }, - { - "id" : 301, - "damage" : 20 - }, - { - "id" : 301, - "damage" : 21 - }, - { - "id" : 301, - "damage" : 22 - }, - { - "id" : 301, - "damage" : 23 - }, - { - "id" : 301, - "damage" : 24 - }, - { - "id" : 301, - "damage" : 25 - }, - { - "id" : 301, - "damage" : 26 - }, - { - "id" : 301, - "damage" : 27 - }, - { - "id" : 301, - "damage" : 28 - }, - { - "id" : 301, - "damage" : 29 - }, - { - "id" : 301, - "damage" : 30 - }, - { - "id" : 301, - "damage" : 31 - }, - { - "id" : 301, - "damage" : 32 - }, - { - "id" : 301, - "damage" : 33 - }, - { - "id" : 301, - "damage" : 34 - }, - { - "id" : 301, - "damage" : 35 - }, - { - "id" : 301, - "damage" : 36 - }, - { - "id" : 301, - "damage" : 37 - }, - { - "id" : 301, - "damage" : 38 - }, - { - "id" : 301, - "damage" : 39 - }, - { - "id" : 301, - "damage" : 40 - }, - { - "id" : 301, - "damage" : 41 - }, - { - "id" : 301, - "damage" : 42 - }, - { - "id" : 301, - "damage" : 43 - }, - { - "id" : 355 - }, - { - "id" : 276 - }, - { - "id" : 263 - }, - { - "id" : 274 - }, - { - "id" : 541 - }, - { - "id" : 289 - }, - { - "id" : 268 - }, - { - "id" : 269 - }, - { - "id" : 261 - }, - { - "id" : 260 - }, - { - "id" : 286 - }, - { - "id" : 290 - }, - { - "id" : 281 - }, - { - "id" : 271 - }, - { - "id" : 284 - }, - { - "id" : 415 - }, - { - "id" : 270 - }, - { - "id" : 390 - }, - { - "id" : 507 - }, - { - "id" : 606 - }, - { - "id" : 372 - }, - { - "id" : 419 + "id" : 310 }, { "id" : 299 }, { - "id" : 537 + "id" : 303 }, { - "id" : 391 + "id" : 307 }, { - "id" : 389 + "id" : 315 }, { - "id" : 505 + "id" : 311 }, { - "id" : 505, - "damage" : 2 + "id" : 300 }, { - "id" : 369 + "id" : 304 }, { - "id" : 520 + "id" : 308 }, { - "id" : 521 + "id" : 316 }, { - "id" : 522 + "id" : 312 }, { - "id" : 523 + "id" : 301 }, { - "id" : 536 + "id" : 305 }, { - "id" : 563 + "id" : 309 }, { - "id" : 554 + "id" : 317 }, { - "id" : 558 + "id" : 313 }, { - "id" : 425 + "id" : 268 }, { - "id" : 498 + "id" : 272 }, { - "id" : 424 + "id" : 267 }, { - "id" : 424, - "damage" : 1 + "id" : 283 }, { - "id" : 424, - "damage" : 2 + "id" : 276 }, { - "id" : 424, - "damage" : 3 + "id" : 271 }, { - "id" : 424, - "damage" : 4 + "id" : 275 }, { - "id" : 424, - "damage" : 5 + "id" : 258 }, { - "id" : 424, + "id" : 286 + }, + { + "id" : 279 + }, + { + "id" : 270 + }, + { + "id" : 274 + }, + { + "id" : 257 + }, + { + "id" : 285 + }, + { + "id" : 278 + }, + { + "id" : 269 + }, + { + "id" : 273 + }, + { + "id" : 256 + }, + { + "id" : 284 + }, + { + "id" : 277 + }, + { + "id" : 290 + }, + { + "id" : 291 + }, + { + "id" : 292 + }, + { + "id" : 294 + }, + { + "id" : 293 + }, + { + "id" : 261 + }, + { + "id" : 471 + }, + { + "id" : 262 + }, + { + "id" : 262, "damage" : 6 }, { - "id" : 424, + "id" : 262, "damage" : 7 }, { - "id" : 424, + "id" : 262, "damage" : 8 }, { - "id" : 424, + "id" : 262, "damage" : 9 }, { - "id" : 424, + "id" : 262, "damage" : 10 }, { - "id" : 424, + "id" : 262, "damage" : 11 }, { - "id" : 424, + "id" : 262, "damage" : 12 }, { - "id" : 424, + "id" : 262, "damage" : 13 }, { - "id" : 424, + "id" : 262, "damage" : 14 }, { - "id" : 424, + "id" : 262, "damage" : 15 }, { - "id" : 424, + "id" : 262, "damage" : 16 }, { - "id" : 424, + "id" : 262, "damage" : 17 }, { - "id" : 424, + "id" : 262, "damage" : 18 }, { - "id" : 424, + "id" : 262, "damage" : 19 }, { - "id" : 424, + "id" : 262, "damage" : 20 }, { - "id" : 424, + "id" : 262, "damage" : 21 }, { - "id" : 424, + "id" : 262, "damage" : 22 }, { - "id" : 424, + "id" : 262, "damage" : 23 }, { - "id" : 424, + "id" : 262, "damage" : 24 }, { - "id" : 424, + "id" : 262, "damage" : 25 }, { - "id" : 424, + "id" : 262, "damage" : 26 }, { - "id" : 424, + "id" : 262, "damage" : 27 }, { - "id" : 424, + "id" : 262, "damage" : 28 }, { - "id" : 424, + "id" : 262, "damage" : 29 }, { - "id" : 424, + "id" : 262, "damage" : 30 }, { - "id" : 424, + "id" : 262, "damage" : 31 }, { - "id" : 424, + "id" : 262, "damage" : 32 }, { - "id" : 424, + "id" : 262, "damage" : 33 }, { - "id" : 424, + "id" : 262, "damage" : 34 }, { - "id" : 424, + "id" : 262, "damage" : 35 }, { - "id" : 424, + "id" : 262, "damage" : 36 }, { - "id" : 424, + "id" : 262, "damage" : 37 }, { - "id" : 424, + "id" : 262, "damage" : 38 }, { - "id" : 424, + "id" : 262, "damage" : 39 }, { - "id" : 424, + "id" : 262, "damage" : 40 }, { - "id" : 424, + "id" : 262, "damage" : 41 }, { - "id" : 424, + "id" : 262, "damage" : 42 }, { - "id" : 551 + "id" : 513 }, { - "id" : 551, - "damage" : 1 - }, - { - "id" : 551, - "damage" : 2 - }, - { - "id" : 551, - "damage" : 3 - }, - { - "id" : 551, - "damage" : 4 - }, - { - "id" : 551, - "damage" : 5 - }, - { - "id" : 551, - "damage" : 6 - }, - { - "id" : 551, - "damage" : 7 - }, - { - "id" : 551, - "damage" : 8 - }, - { - "id" : 551, - "damage" : 9 - }, - { - "id" : 551, - "damage" : 10 - }, - { - "id" : 551, - "damage" : 11 - }, - { - "id" : 551, - "damage" : 12 - }, - { - "id" : 551, - "damage" : 13 - }, - { - "id" : 551, - "damage" : 14 - }, - { - "id" : 551, - "damage" : 15 - }, - { - "id" : 551, - "damage" : 16 - }, - { - "id" : 551, - "damage" : 17 - }, - { - "id" : 551, - "damage" : 18 - }, - { - "id" : 551, - "damage" : 19 - }, - { - "id" : 551, - "damage" : 20 - }, - { - "id" : 551, - "damage" : 21 - }, - { - "id" : 551, - "damage" : 22 - }, - { - "id" : 551, - "damage" : 23 - }, - { - "id" : 551, - "damage" : 24 - }, - { - "id" : 551, - "damage" : 25 - }, - { - "id" : 551, - "damage" : 26 - }, - { - "id" : 551, - "damage" : 27 - }, - { - "id" : 551, - "damage" : 28 - }, - { - "id" : 551, - "damage" : 29 - }, - { - "id" : 551, - "damage" : 30 - }, - { - "id" : 551, - "damage" : 31 - }, - { - "id" : 551, - "damage" : 32 - }, - { - "id" : 551, - "damage" : 33 - }, - { - "id" : 551, - "damage" : 34 - }, - { - "id" : 551, - "damage" : 35 - }, - { - "id" : 551, - "damage" : 36 - }, - { - "id" : 551, - "damage" : 37 - }, - { - "id" : 551, - "damage" : 38 - }, - { - "id" : 551, - "damage" : 39 - }, - { - "id" : 551, - "damage" : 40 - }, - { - "id" : 551, - "damage" : 41 - }, - { - "id" : 551, - "damage" : 42 - }, - { - "id" : 552 - }, - { - "id" : 552, - "damage" : 1 - }, - { - "id" : 552, - "damage" : 2 - }, - { - "id" : 552, - "damage" : 3 - }, - { - "id" : 552, - "damage" : 4 - }, - { - "id" : 552, - "damage" : 5 - }, - { - "id" : 552, - "damage" : 6 - }, - { - "id" : 552, - "damage" : 7 - }, - { - "id" : 552, - "damage" : 8 - }, - { - "id" : 552, - "damage" : 9 - }, - { - "id" : 552, - "damage" : 10 - }, - { - "id" : 552, - "damage" : 11 - }, - { - "id" : 552, - "damage" : 12 - }, - { - "id" : 552, - "damage" : 13 - }, - { - "id" : 552, - "damage" : 14 - }, - { - "id" : 552, - "damage" : 15 - }, - { - "id" : 552, - "damage" : 16 - }, - { - "id" : 552, - "damage" : 17 - }, - { - "id" : 552, - "damage" : 18 - }, - { - "id" : 552, - "damage" : 19 - }, - { - "id" : 552, - "damage" : 20 - }, - { - "id" : 552, - "damage" : 21 - }, - { - "id" : 552, - "damage" : 22 - }, - { - "id" : 552, - "damage" : 23 - }, - { - "id" : 552, - "damage" : 24 - }, - { - "id" : 552, - "damage" : 25 - }, - { - "id" : 552, - "damage" : 26 - }, - { - "id" : 552, - "damage" : 27 - }, - { - "id" : 552, - "damage" : 28 - }, - { - "id" : 552, - "damage" : 29 - }, - { - "id" : 552, - "damage" : 30 - }, - { - "id" : 552, - "damage" : 31 - }, - { - "id" : 552, - "damage" : 32 - }, - { - "id" : 552, - "damage" : 33 - }, - { - "id" : 552, - "damage" : 34 - }, - { - "id" : 552, - "damage" : 35 - }, - { - "id" : 552, - "damage" : 36 - }, - { - "id" : 552, - "damage" : 37 - }, - { - "id" : 552, - "damage" : 38 - }, - { - "id" : 552, - "damage" : 39 - }, - { - "id" : 552, - "damage" : 40 - }, - { - "id" : 552, - "damage" : 41 - }, - { - "id" : 552, - "damage" : 42 + "id" : 366 }, { "id" : 320 }, { - "id" : 416 + "id" : 364 }, { - "id" : 416, - "damage" : 8 + "id" : 424 }, { - "id" : 416, - "damage" : 7 + "id" : 412 }, { - "id" : 416, - "damage" : 15 + "id" : 350 }, { - "id" : 416, - "damage" : 12 + "id" : 463 }, { - "id" : 416, - "damage" : 14 + "id" : 297 }, { - "id" : 416, - "damage" : 1 + "id" : 282 }, { - "id" : 416, - "damage" : 4 + "id" : 459 }, { - "id" : 416, - "damage" : 5 + "id" : 413 }, { - "id" : 416, - "damage" : 13 + "id" : 393 }, { - "id" : 416, - "damage" : 9 + "id" : 357 }, { - "id" : 416, - "damage" : 3 + "id" : 400 }, { - "id" : 416, - "damage" : 11 + "id" : 354 }, { - "id" : 416, - "damage" : 10 + "id" : 464 }, { - "id" : 416, + "id" : 346 + }, + { + "id" : 398 + }, + { + "id" : 332 + }, + { + "id" : 359 + }, + { + "id" : 259 + }, + { + "id" : 420 + }, + { + "id" : 347 + }, + { + "id" : 345 + }, + { + "id" : 395 + }, + { + "id" : 395, "damage" : 2 }, { - "id" : 416, + "id" : 329 + }, + { + "id" : 416 + }, + { + "id" : 417 + }, + { + "id" : 418 + }, + { + "id" : 419 + }, + { + "id" : 455 + }, + { + "id" : 469 + }, + { + "id" : 444 + }, + { + "id" : 450 + }, + { + "id" : 374 + }, + { + "id" : 384 + }, + { + "id" : 373 + }, + { + "id" : 373, + "damage" : 1 + }, + { + "id" : 373, + "damage" : 2 + }, + { + "id" : 373, + "damage" : 3 + }, + { + "id" : 373, + "damage" : 4 + }, + { + "id" : 373, + "damage" : 5 + }, + { + "id" : 373, + "damage" : 6 + }, + { + "id" : 373, + "damage" : 7 + }, + { + "id" : 373, + "damage" : 8 + }, + { + "id" : 373, + "damage" : 9 + }, + { + "id" : 373, + "damage" : 10 + }, + { + "id" : 373, + "damage" : 11 + }, + { + "id" : 373, + "damage" : 12 + }, + { + "id" : 373, + "damage" : 13 + }, + { + "id" : 373, + "damage" : 14 + }, + { + "id" : 373, + "damage" : 15 + }, + { + "id" : 373, + "damage" : 16 + }, + { + "id" : 373, + "damage" : 17 + }, + { + "id" : 373, + "damage" : 18 + }, + { + "id" : 373, + "damage" : 19 + }, + { + "id" : 373, + "damage" : 20 + }, + { + "id" : 373, + "damage" : 21 + }, + { + "id" : 373, + "damage" : 22 + }, + { + "id" : 373, + "damage" : 23 + }, + { + "id" : 373, + "damage" : 24 + }, + { + "id" : 373, + "damage" : 25 + }, + { + "id" : 373, + "damage" : 26 + }, + { + "id" : 373, + "damage" : 27 + }, + { + "id" : 373, + "damage" : 28 + }, + { + "id" : 373, + "damage" : 29 + }, + { + "id" : 373, + "damage" : 30 + }, + { + "id" : 373, + "damage" : 31 + }, + { + "id" : 373, + "damage" : 32 + }, + { + "id" : 373, + "damage" : 33 + }, + { + "id" : 373, + "damage" : 34 + }, + { + "id" : 373, + "damage" : 35 + }, + { + "id" : 373, + "damage" : 36 + }, + { + "id" : 373, + "damage" : 37 + }, + { + "id" : 373, + "damage" : 38 + }, + { + "id" : 373, + "damage" : 39 + }, + { + "id" : 373, + "damage" : 40 + }, + { + "id" : 373, + "damage" : 41 + }, + { + "id" : 438 + }, + { + "id" : 438, + "damage" : 1 + }, + { + "id" : 438, + "damage" : 2 + }, + { + "id" : 438, + "damage" : 3 + }, + { + "id" : 438, + "damage" : 4 + }, + { + "id" : 438, + "damage" : 5 + }, + { + "id" : 438, + "damage" : 6 + }, + { + "id" : 438, + "damage" : 7 + }, + { + "id" : 438, + "damage" : 8 + }, + { + "id" : 438, + "damage" : 9 + }, + { + "id" : 438, + "damage" : 10 + }, + { + "id" : 438, + "damage" : 11 + }, + { + "id" : 438, + "damage" : 12 + }, + { + "id" : 438, + "damage" : 13 + }, + { + "id" : 438, + "damage" : 14 + }, + { + "id" : 438, + "damage" : 15 + }, + { + "id" : 438, + "damage" : 16 + }, + { + "id" : 438, + "damage" : 17 + }, + { + "id" : 438, + "damage" : 18 + }, + { + "id" : 438, + "damage" : 19 + }, + { + "id" : 438, + "damage" : 20 + }, + { + "id" : 438, + "damage" : 21 + }, + { + "id" : 438, + "damage" : 22 + }, + { + "id" : 438, + "damage" : 23 + }, + { + "id" : 438, + "damage" : 24 + }, + { + "id" : 438, + "damage" : 25 + }, + { + "id" : 438, + "damage" : 26 + }, + { + "id" : 438, + "damage" : 27 + }, + { + "id" : 438, + "damage" : 28 + }, + { + "id" : 438, + "damage" : 29 + }, + { + "id" : 438, + "damage" : 30 + }, + { + "id" : 438, + "damage" : 31 + }, + { + "id" : 438, + "damage" : 32 + }, + { + "id" : 438, + "damage" : 33 + }, + { + "id" : 438, + "damage" : 34 + }, + { + "id" : 438, + "damage" : 35 + }, + { + "id" : 438, + "damage" : 36 + }, + { + "id" : 438, + "damage" : 37 + }, + { + "id" : 438, + "damage" : 38 + }, + { + "id" : 438, + "damage" : 39 + }, + { + "id" : 438, + "damage" : 40 + }, + { + "id" : 438, + "damage" : 41 + }, + { + "id" : 441 + }, + { + "id" : 441, + "damage" : 1 + }, + { + "id" : 441, + "damage" : 2 + }, + { + "id" : 441, + "damage" : 3 + }, + { + "id" : 441, + "damage" : 4 + }, + { + "id" : 441, + "damage" : 5 + }, + { + "id" : 441, + "damage" : 6 + }, + { + "id" : 441, + "damage" : 7 + }, + { + "id" : 441, + "damage" : 8 + }, + { + "id" : 441, + "damage" : 9 + }, + { + "id" : 441, + "damage" : 10 + }, + { + "id" : 441, + "damage" : 11 + }, + { + "id" : 441, + "damage" : 12 + }, + { + "id" : 441, + "damage" : 13 + }, + { + "id" : 441, + "damage" : 14 + }, + { + "id" : 441, + "damage" : 15 + }, + { + "id" : 441, + "damage" : 16 + }, + { + "id" : 441, + "damage" : 17 + }, + { + "id" : 441, + "damage" : 18 + }, + { + "id" : 441, + "damage" : 19 + }, + { + "id" : 441, + "damage" : 20 + }, + { + "id" : 441, + "damage" : 21 + }, + { + "id" : 441, + "damage" : 22 + }, + { + "id" : 441, + "damage" : 23 + }, + { + "id" : 441, + "damage" : 24 + }, + { + "id" : 441, + "damage" : 25 + }, + { + "id" : 441, + "damage" : 26 + }, + { + "id" : 441, + "damage" : 27 + }, + { + "id" : 441, + "damage" : 28 + }, + { + "id" : 441, + "damage" : 29 + }, + { + "id" : 441, + "damage" : 30 + }, + { + "id" : 441, + "damage" : 31 + }, + { + "id" : 441, + "damage" : 32 + }, + { + "id" : 441, + "damage" : 33 + }, + { + "id" : 441, + "damage" : 34 + }, + { + "id" : 441, + "damage" : 35 + }, + { + "id" : 441, + "damage" : 36 + }, + { + "id" : 441, + "damage" : 37 + }, + { + "id" : 441, + "damage" : 38 + }, + { + "id" : 441, + "damage" : 39 + }, + { + "id" : 441, + "damage" : 40 + }, + { + "id" : 441, + "damage" : 41 + }, + { + "id" : 280 + }, + { + "id" : 355 + }, + { + "id" : 355, + "damage" : 8 + }, + { + "id" : 355, + "damage" : 7 + }, + { + "id" : 355, + "damage" : 15 + }, + { + "id" : 355, + "damage" : 12 + }, + { + "id" : 355, + "damage" : 14 + }, + { + "id" : 355, + "damage" : 1 + }, + { + "id" : 355, + "damage" : 4 + }, + { + "id" : 355, + "damage" : 5 + }, + { + "id" : 355, + "damage" : 13 + }, + { + "id" : 355, + "damage" : 9 + }, + { + "id" : 355, + "damage" : 3 + }, + { + "id" : 355, + "damage" : 11 + }, + { + "id" : 355, + "damage" : 10 + }, + { + "id" : 355, + "damage" : 2 + }, + { + "id" : 355, "damage" : 6 }, { "id" : 50 }, - { - "id" : -268 - }, { "id" : -156 }, { "id" : -208 }, - { - "id" : -269 - }, { "id" : 58 }, @@ -3167,10 +2997,7 @@ "id" : -219 }, { - "id" : 578 - }, - { - "id" : 610 + "id" : 720 }, { "id" : 61 @@ -3182,10 +3009,7 @@ "id" : -198 }, { - "id" : -272 - }, - { - "id" : 429 + "id" : 379 }, { "id" : 145 @@ -3211,7 +3035,7 @@ "id" : -194 }, { - "id" : 430 + "id" : 380 }, { "id" : -213 @@ -3295,7 +3119,7 @@ "damage" : 6 }, { - "id" : 542 + "id" : 425 }, { "id" : 25 @@ -3304,46 +3128,43 @@ "id" : 84 }, { - "id" : 524 + "id" : 500 }, { - "id" : 525 + "id" : 501 }, { - "id" : 526 + "id" : 502 }, { - "id" : 527 + "id" : 503 }, { - "id" : 528 + "id" : 504 }, { - "id" : 529 + "id" : 505 }, { - "id" : 530 + "id" : 506 }, { - "id" : 531 + "id" : 507 }, { - "id" : 532 + "id" : 508 }, { - "id" : 533 + "id" : 509 }, { - "id" : 534 + "id" : 510 }, { - "id" : 535 + "id" : 511 }, { - "id" : 608 - }, - { - "id" : 392 + "id" : 348 }, { "id" : 89 @@ -3355,89 +3176,90 @@ "id" : 169 }, { - "id" : 358 + "id" : 323 }, { - "id" : 566 + "id" : 472 }, { - "id" : 567 + "id" : 473 }, { - "id" : 568 + "id" : 474 }, { - "id" : 569 + "id" : 475 }, { - "id" : 570 - }, - { - "id" : 602 - }, - { - "id" : 603 - }, - { - "id" : 357 - }, - { - "id" : 503 - }, - { - "id" : 581 - }, - { - "id" : 504 + "id" : 476 }, { "id" : 321 }, { - "id" : 360 + "id" : 389 }, { - "id" : 361 + "id" : 737 }, { - "id" : 362 + "id" : 390 }, { - "id" : 363 + "id" : 281 }, { - "id" : 364 + "id" : 325 }, { - "id" : 365 + "id" : 325, + "damage" : 1 }, { - "id" : 366 + "id" : 325, + "damage" : 8 }, { - "id" : 367 + "id" : 325, + "damage" : 10 }, { - "id" : 506, - "damage" : 3 - }, - { - "id" : 506, + "id" : 325, "damage" : 2 }, { - "id" : 506, + "id" : 325, + "damage" : 3 + }, + { + "id" : 325, "damage" : 4 }, { - "id" : 506, + "id" : 325, "damage" : 5 }, { - "id" : 506 + "id" : 397, + "damage" : 3 }, { - "id" : 506, + "id" : 397, + "damage" : 2 + }, + { + "id" : 397, + "damage" : 4 + }, + { + "id" : 397, + "damage" : 5 + }, + { + "id" : 397 + }, + { + "id" : 397, "damage" : 1 }, { @@ -3456,576 +3278,86 @@ "id" : 120 }, { - "id" : 302 + "id" : 263 }, { - "id" : 303 + "id" : 263, + "damage" : 1 }, { - "id" : 304 + "id" : 264 }, { - "id" : 559 + "id" : 452 }, { - "id" : 305 + "id" : 265 }, { - "id" : 601 + "id" : 371 }, { - "id" : 591 + "id" : 266 }, { - "id" : 423 + "id" : 388 }, { - "id" : 306 + "id" : 406 }, { - "id" : 502 + "id" : 337 }, { - "id" : 514 + "id" : 336 }, { - "id" : 382 + "id" : 405 }, { - "id" : 381 - }, - { - "id" : 513 - }, - { - "id" : 555 - }, - { - "id" : 539 - }, - { - "id" : 560 - }, - { - "id" : 561 - }, - { - "id" : 562 - }, - { - "id" : 564 - }, - { - "id" : 326 - }, - { - "id" : 327 - }, - { - "id" : 356 - }, - { - "id" : 328 - }, - { - "id" : 379 - }, - { - "id" : 519 - }, - { - "id" : 518 - }, - { - "id" : 499 - }, - { - "id" : 421 - }, - { - "id" : 427 - }, - { - "id" : 428 - }, - { - "id" : 426 - }, - { - "id" : 550 - }, - { - "id" : 556 + "id" : 409 }, { "id" : 422 }, { - "id" : 386 + "id" : 465 }, { - "id" : 420 + "id" : 467 }, { - "id" : 431 + "id" : 468 }, { - "id" : 508 + "id" : 470 }, { - "id" : 208 + "id" : 287 }, { - "id" : 615 + "id" : 288 }, { - "id" : 384 + "id" : 318 + }, + { + "id" : 289 + }, + { + "id" : 334 + }, + { + "id" : 415 + }, + { + "id" : 414 }, { "id" : 385 }, { - "id" : 500 - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQAAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQBAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQCAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQDAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQEAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQFAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQGAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQHAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQIAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQJAAIDAGx2bAUAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQKAAIDAGx2bAUAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQLAAIDAGx2bAUAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQMAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQNAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQOAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQPAAIDAGx2bAUAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQQAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQRAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQSAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQTAAIDAGx2bAUAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQUAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQVAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQWAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQXAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQYAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQZAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQaAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQbAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQcAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQdAAIDAGx2bAUAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQeAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQfAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQgAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQhAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQiAAIDAGx2bAQAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQjAAIDAGx2bAMAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAEAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAIAAAA=" - }, - { - "id" : 511, - "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgIAaWQkAAIDAGx2bAMAAAA=" - }, - { - "id" : 373 - }, - { - "id" : 376 - }, - { - "id" : 374 - }, - { - "id" : 375 + "id" : 369 }, { "id" : 377 @@ -4033,6 +3365,476 @@ { "id" : 378 }, + { + "id" : 376 + }, + { + "id" : 437 + }, + { + "id" : 445 + }, + { + "id" : 370 + }, + { + "id" : 341 + }, + { + "id" : 368 + }, + { + "id" : 381 + }, + { + "id" : 399 + }, + { + "id" : 208 + }, + { + "id" : 426 + }, + { + "id" : 339 + }, + { + "id" : 340 + }, + { + "id" : 386 + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAAAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAAAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAAAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAAAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAUAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAUAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAUAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAYAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAYAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAYAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAcAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAcAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAcAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAgAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBQACAgBpZAkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAoAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAoAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAoAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAoAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBQACAgBpZAoAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAsAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAsAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZAsAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZAsAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBQACAgBpZAsAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZAwAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZAwAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZA0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZA0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZA4AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZA4AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZA4AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZA8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZA8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZA8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZA8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBQACAgBpZA8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBAAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZBEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZBIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZBMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZBMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBQACAgBpZBMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBUAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBYAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBcAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBcAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZBcAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBgAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBgAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZBgAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZBkAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBoAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZB0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZB0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZB0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZB0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBQACAgBpZB0AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZB4AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZB4AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZB4AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZB8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZB8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZB8AAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZCAAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZCEAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZCIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZCIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZCIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsBAACAgBpZCIAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZCMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZCMAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZCMAAAA=" + }, + { + "id" : 333 + }, + { + "id" : 333, + "damage" : 1 + }, + { + "id" : 333, + "damage" : 2 + }, + { + "id" : 333, + "damage" : 3 + }, + { + "id" : 333, + "damage" : 4 + }, + { + "id" : 333, + "damage" : 5 + }, { "id" : 66 }, @@ -4046,19 +3848,19 @@ "id" : 126 }, { - "id" : 368 + "id" : 328 }, { - "id" : 387 + "id" : 342 }, { - "id" : 516 + "id" : 408 }, { - "id" : 515 + "id" : 407 }, { - "id" : 371 + "id" : 331 }, { "id" : 152 @@ -4090,15 +3892,6 @@ { "id" : 77 }, - { - "id" : -260 - }, - { - "id" : -261 - }, - { - "id" : -296 - }, { "id" : 131 }, @@ -4120,12 +3913,6 @@ { "id" : -152 }, - { - "id" : -262 - }, - { - "id" : -263 - }, { "id" : 70 }, @@ -4135,9 +3922,6 @@ { "id" : 148 }, - { - "id" : -295 - }, { "id" : 251 }, @@ -4145,13 +3929,13 @@ "id" : 151 }, { - "id" : 417 + "id" : 356 }, { - "id" : 512 + "id" : 404 }, { - "id" : 517 + "id" : 410 }, { "id" : 125, @@ -4173,255 +3957,248 @@ "id" : 46 }, { - "id" : 538 + "id" : 421 }, { "id" : -204 }, { - "id" : 557 + "id" : 446 }, { - "id" : 557, + "id" : 446, "damage" : 8 }, { - "id" : 557, + "id" : 446, "damage" : 7 }, { - "id" : 557, + "id" : 446, "damage" : 15 }, { - "id" : 557, + "id" : 446, "damage" : 12 }, { - "id" : 557, + "id" : 446, "damage" : 14 }, { - "id" : 557, + "id" : 446, "damage" : 1 }, { - "id" : 557, + "id" : 446, "damage" : 4 }, { - "id" : 557, + "id" : 446, "damage" : 5 }, { - "id" : 557, + "id" : 446, "damage" : 13 }, { - "id" : 557, + "id" : 446, "damage" : 9 }, { - "id" : 557, + "id" : 446, "damage" : 3 }, { - "id" : 557, + "id" : 446, "damage" : 11 }, { - "id" : 557, + "id" : 446, "damage" : 10 }, { - "id" : 557, + "id" : 446, "damage" : 2 }, { - "id" : 557, + "id" : 446, "damage" : 6 }, { - "id" : 557, + "id" : 446, "damage" : 15, "nbt_b64" : "CgAAAwQAVHlwZQEAAAAA" }, { - "id" : 572 + "id" : 434 }, { - "id" : 573 + "id" : 434, + "damage" : 1 }, { - "id" : 571 + "id" : 434, + "damage" : 2 }, { - "id" : 574 + "id" : 434, + "damage" : 3 }, { - "id" : 575 + "id" : 434, + "damage" : 4 }, { - "id" : 576 + "id" : 434, + "damage" : 5 }, { - "id" : 577 + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMAAAAAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 402, + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3IhHR3/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" - }, - { - "id" : 510, + "id" : 402, "damage" : 8, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yUk9H/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3JST0f/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 7, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yl52d/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3KXnZ3/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 15, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y8PDw/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3Lw8PD/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 12, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9y2rM6/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3Laszr/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 14, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yHYD5/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3IdgPn/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 1, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yJi6w/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3ImLrD/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 4, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqkQ8/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3KqRDz/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 5, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yuDKJ/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3K4Mon/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 13, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yvU7H/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3K9Tsf/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAADQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 9, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yqovz/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3Kqi/P/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 3, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yMlSD/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3IyVIP/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 11, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yPdj+/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3I92P7/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 10, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yH8eA/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3Ifx4D/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAACgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 2, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yFnxe/wA=" + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3IWfF7/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "id" : 510, + "id" : 402, "damage" : 6, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9ynJwW/wA=" - }, - { - "id" : 607 - }, - { - "id" : -239 - }, - { - "id" : 590 + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3KcnBb/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAABgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" } ] } \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/entity_identifiers.dat b/connector/src/main/resources/bedrock/entity_identifiers.dat index c9477ba8..cb8f0481 100644 Binary files a/connector/src/main/resources/bedrock/entity_identifiers.dat and b/connector/src/main/resources/bedrock/entity_identifiers.dat differ diff --git a/connector/src/main/resources/bedrock/items.json b/connector/src/main/resources/bedrock/items.json new file mode 100644 index 00000000..87f85187 --- /dev/null +++ b/connector/src/main/resources/bedrock/items.json @@ -0,0 +1,2810 @@ +[ + { + "name" : "minecraft:item.reeds", + "id" : 83 + }, + { + "name" : "minecraft:air", + "id" : -158 + }, + { + "name" : "minecraft:item.birch_door", + "id" : 194 + }, + { + "name" : "minecraft:apple", + "id" : 260 + }, + { + "name" : "minecraft:cooked_porkchop", + "id" : 320 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:appleenchanted", + "id" : 466 + }, + { + "name" : "minecraft:tripwire", + "id" : 132 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 300 + }, + { + "name" : "minecraft:bread", + "id" : 297 + }, + { + "name" : "minecraft:light_block", + "id" : -215 + }, + { + "name" : "minecraft:porkchop", + "id" : 319 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:fish", + "id" : 349 + }, + { + "name" : "minecraft:element_52", + "id" : -63 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 276 + }, + { + "name" : "minecraft:element_38", + "id" : -49 + }, + { + "name" : "minecraft:sandstone_stairs", + "id" : 128 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 475 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 413 + }, + { + "name" : "minecraft:birch_sign", + "id" : 473 + }, + { + "name" : "minecraft:horsearmorgold", + "id" : 418 + }, + { + "name" : "minecraft:element_74", + "id" : -85 + }, + { + "name" : "minecraft:pufferfish", + "id" : 462 + }, + { + "name" : "minecraft:redstone_block", + "id" : 152 + }, + { + "name" : "minecraft:golden_apple", + "id" : 322 + }, + { + "name" : "minecraft:item.wooden_door", + "id" : 64 + }, + { + "name" : "minecraft:emerald", + "id" : 388 + }, + { + "name" : "minecraft:element_47", + "id" : -58 + }, + { + "name" : "minecraft:mushroom_stew", + "id" : 282 + }, + { + "name" : "minecraft:stone_axe", + "id" : 275 + }, + { + "name" : "minecraft:salmon", + "id" : 460 + }, + { + "name" : "minecraft:feather", + "id" : 288 + }, + { + "name" : "minecraft:clownfish", + "id" : 461 + }, + { + "name" : "minecraft:diamond", + "id" : 264 + }, + { + "name" : "minecraft:cooked_fish", + "id" : 350 + }, + { + "name" : "minecraft:element_32", + "id" : -43 + }, + { + "name" : "minecraft:double_stone_slab4", + "id" : -166 + }, + { + "name" : "minecraft:element_5", + "id" : -16 + }, + { + "name" : "minecraft:element_25", + "id" : -36 + }, + { + "name" : "minecraft:polished_granite_stairs", + "id" : -172 + }, + { + "name" : "minecraft:bowl", + "id" : 281 + }, + { + "name" : "minecraft:red_mushroom_block", + "id" : 100 + }, + { + "name" : "minecraft:mossy_stone_brick_stairs", + "id" : -175 + }, + { + "name" : "minecraft:cooked_salmon", + "id" : 463 + }, + { + "name" : "minecraft:element_87", + "id" : -98 + }, + { + "name" : "minecraft:pumpkin_seeds", + "id" : 361 + }, + { + "name" : "minecraft:element_53", + "id" : -64 + }, + { + "name" : "minecraft:dried_kelp", + "id" : 464 + }, + { + "name" : "minecraft:brewingstandblock", + "id" : 117 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 270 + }, + { + "name" : "minecraft:cookie", + "id" : 357 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 266 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 477 + }, + { + "name" : "minecraft:melon", + "id" : 360 + }, + { + "name" : "minecraft:iron_pickaxe", + "id" : 257 + }, + { + "name" : "minecraft:glow_stick", + "id" : 166 + }, + { + "name" : "minecraft:beef", + "id" : 363 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 291 + }, + { + "name" : "minecraft:cooked_beef", + "id" : 364 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:chicken", + "id" : 365 + }, + { + "name" : "minecraft:element_31", + "id" : -42 + }, + { + "name" : "minecraft:cooked_chicken", + "id" : 366 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 367 + }, + { + "name" : "minecraft:darkoak_sign", + "id" : 476 + }, + { + "name" : "minecraft:stone_sword", + "id" : 272 + }, + { + "name" : "minecraft:spider_eye", + "id" : 375 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 279 + }, + { + "name" : "minecraft:element_105", + "id" : -116 + }, + { + "name" : "minecraft:carrot", + "id" : 391 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "name" : "minecraft:potato", + "id" : 392 + }, + { + "name" : "minecraft:baked_potato", + "id" : 393 + }, + { + "name" : "minecraft:element_15", + "id" : -26 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 394 + }, + { + "name" : "minecraft:beetroot_seeds", + "id" : 458 + }, + { + "name" : "minecraft:noteblock", + "id" : 25 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 396 + }, + { + "name" : "minecraft:pumpkin_pie", + "id" : 400 + }, + { + "name" : "minecraft:beetroot", + "id" : 457 + }, + { + "name" : "minecraft:coral_fan_dead", + "id" : -134 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 265 + }, + { + "name" : "minecraft:beetroot_soup", + "id" : 459 + }, + { + "name" : "minecraft:rabbit", + "id" : 411 + }, + { + "name" : "minecraft:cooked_rabbit", + "id" : 412 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 306 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 295 + }, + { + "name" : "minecraft:melon_seeds", + "id" : 362 + }, + { + "name" : "minecraft:nether_wart", + "id" : 372 + }, + { + "name" : "minecraft:record_strad", + "id" : 508 + }, + { + "name" : "minecraft:iron_sword", + "id" : 267 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 256 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 274 + }, + { + "name" : "minecraft:leather", + "id" : 334 + }, + { + "name" : "minecraft:command_block_minecart", + "id" : 443 + }, + { + "name" : "minecraft:stone_shovel", + "id" : 273 + }, + { + "name" : "minecraft:written_book", + "id" : 387 + }, + { + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:arrow", + "id" : 262 + }, + { + "name" : "minecraft:element_97", + "id" : -108 + }, + { + "name" : "minecraft:campfire", + "id" : 720 + }, + { + "name" : "minecraft:polished_andesite_stairs", + "id" : -174 + }, + { + "name" : "minecraft:acacia_stairs", + "id" : 163 + }, + { + "name" : "minecraft:iron_axe", + "id" : 258 + }, + { + "name" : "minecraft:flint_and_steel", + "id" : 259 + }, + { + "name" : "minecraft:bow", + "id" : 261 + }, + { + "name" : "minecraft:nautilus_shell", + "id" : 465 + }, + { + "name" : "minecraft:coal", + "id" : 263 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 268 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 278 + }, + { + "name" : "minecraft:deadbush", + "id" : 32 + }, + { + "name" : "minecraft:ender_chest", + "id" : 130 + }, + { + "name" : "minecraft:record_stal", + "id" : 507 + }, + { + "name" : "minecraft:wooden_shovel", + "id" : 269 + }, + { + "name" : "minecraft:dark_oak_trapdoor", + "id" : -147 + }, + { + "name" : "minecraft:record_mall", + "id" : 505 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 271 + }, + { + "name" : "minecraft:powered_comparator", + "id" : 150 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 277 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, + { + "name" : "minecraft:lit_furnace", + "id" : 62 + }, + { + "name" : "minecraft:stick", + "id" : 280 + }, + { + "name" : "minecraft:slime_ball", + "id" : 341 + }, + { + "name" : "minecraft:element_58", + "id" : -69 + }, + { + "name" : "minecraft:golden_sword", + "id" : 283 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 284 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 285 + }, + { + "name" : "minecraft:golden_axe", + "id" : 286 + }, + { + "name" : "minecraft:element_62", + "id" : -73 + }, + { + "name" : "minecraft:string", + "id" : 287 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 348 + }, + { + "name" : "minecraft:gunpowder", + "id" : 289 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 383 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 290 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 445 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 292 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 293 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 294 + }, + { + "name" : "minecraft:turtle_shell_piece", + "id" : 468 + }, + { + "name" : "minecraft:sweet_berry_bush", + "id" : -207 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:muttoncooked", + "id" : 424 + }, + { + "name" : "minecraft:wheat", + "id" : 296 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 431 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:element_46", + "id" : -57 + }, + { + "name" : "minecraft:potion", + "id" : 373 + }, + { + "name" : "minecraft:wither_rose", + "id" : -216 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 298 + }, + { + "name" : "minecraft:element_48", + "id" : -59 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 299 + }, + { + "name" : "minecraft:leather_boots", + "id" : 301 + }, + { + "name" : "minecraft:lectern", + "id" : -194 + }, + { + "name" : "minecraft:smithing_table", + "id" : -202 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 302 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:stickypistonarmcollision", + "id" : -217 + }, + { + "name" : "minecraft:structure_void", + "id" : 217 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 303 + }, + { + "name" : "minecraft:lit_blast_furnace", + "id" : -214 + }, + { + "name" : "minecraft:element_11", + "id" : -22 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 304 + }, + { + "name" : "minecraft:saddle", + "id" : 329 + }, + { + "name" : "minecraft:purpur_block", + "id" : 201 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 305 + }, + { + "name" : "minecraft:ladder", + "id" : 65 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 307 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 310 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 308 + }, + { + "name" : "minecraft:iron_boots", + "id" : 309 + }, + { + "name" : "minecraft:element_104", + "id" : -115 + }, + { + "name" : "minecraft:chorus_fruit_popped", + "id" : 433 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 311 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 312 + }, + { + "name" : "minecraft:element_75", + "id" : -86 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 313 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 314 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 315 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 316 + }, + { + "name" : "minecraft:golden_boots", + "id" : 317 + }, + { + "name" : "minecraft:item.hopper", + "id" : 154 + }, + { + "name" : "minecraft:shield", + "id" : 513 + }, + { + "name" : "minecraft:flint", + "id" : 318 + }, + { + "name" : "minecraft:painting", + "id" : 321 + }, + { + "name" : "minecraft:sign", + "id" : 323 + }, + { + "name" : "minecraft:wooden_door", + "id" : 324 + }, + { + "name" : "minecraft:bucket", + "id" : 325 + }, + { + "name" : "minecraft:minecart", + "id" : 328 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:iron_door", + "id" : 330 + }, + { + "name" : "minecraft:tripwire_hook", + "id" : 131 + }, + { + "name" : "minecraft:redstone", + "id" : 331 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:snowball", + "id" : 332 + }, + { + "name" : "minecraft:boat", + "id" : 333 + }, + { + "name" : "minecraft:item.dark_oak_door", + "id" : 197 + }, + { + "name" : "minecraft:kelp", + "id" : 335 + }, + { + "name" : "minecraft:brick", + "id" : 336 + }, + { + "name" : "minecraft:clay_ball", + "id" : 337 + }, + { + "name" : "minecraft:real_double_stone_slab", + "id" : 43 + }, + { + "name" : "minecraft:reeds", + "id" : 338 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:red_mushroom", + "id" : 40 + }, + { + "name" : "minecraft:paper", + "id" : 339 + }, + { + "name" : "minecraft:book", + "id" : 340 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 342 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:element_86", + "id" : -97 + }, + { + "name" : "minecraft:red_glazed_terracotta", + "id" : 234 + }, + { + "name" : "minecraft:crafting_table", + "id" : 58 + }, + { + "name" : "minecraft:egg", + "id" : 344 + }, + { + "name" : "minecraft:real_double_stone_slab4", + "id" : -168 + }, + { + "name" : "minecraft:end_gateway", + "id" : 209 + }, + { + "name" : "minecraft:compass", + "id" : 345 + }, + { + "name" : "minecraft:horsearmordiamond", + "id" : 419 + }, + { + "name" : "minecraft:sapling", + "id" : 6 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 346 + }, + { + "name" : "minecraft:name_tag", + "id" : 421 + }, + { + "name" : "minecraft:clock", + "id" : 347 + }, + { + "name" : "minecraft:element_96", + "id" : -107 + }, + { + "name" : "minecraft:dye", + "id" : 351 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:conduit", + "id" : -157 + }, + { + "name" : "minecraft:bone", + "id" : 352 + }, + { + "name" : "minecraft:soul_sand", + "id" : 88 + }, + { + "name" : "minecraft:sugar", + "id" : 353 + }, + { + "name" : "minecraft:cake", + "id" : 354 + }, + { + "name" : "minecraft:element_113", + "id" : -124 + }, + { + "name" : "minecraft:mossy_cobblestone", + "id" : 48 + }, + { + "name" : "minecraft:bed", + "id" : 355 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:item.frame", + "id" : 199 + }, + { + "name" : "minecraft:repeater", + "id" : 356 + }, + { + "name" : "minecraft:map", + "id" : 358 + }, + { + "name" : "minecraft:shears", + "id" : 359 + }, + { + "name" : "minecraft:double_stone_slab2", + "id" : 182 + }, + { + "name" : "minecraft:element_3", + "id" : -14 + }, + { + "name" : "minecraft:element_23", + "id" : -34 + }, + { + "name" : "minecraft:skull", + "id" : 397 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 368 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 369 + }, + { + "name" : "minecraft:lit_pumpkin", + "id" : 91 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 370 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 371 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 374 + }, + { + "name" : "minecraft:emptymap", + "id" : 395 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 376 + }, + { + "name" : "minecraft:element_81", + "id" : -92 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 377 + }, + { + "name" : "minecraft:armor_stand", + "id" : 425 + }, + { + "name" : "minecraft:magma_cream", + "id" : 378 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 379 + }, + { + "name" : "minecraft:darkoak_standing_sign", + "id" : -192 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:cauldron", + "id" : 380 + }, + { + "name" : "minecraft:nether_brick", + "id" : 112 + }, + { + "name" : "minecraft:ender_eye", + "id" : 381 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 384 + }, + { + "name" : "minecraft:speckled_melon", + "id" : 382 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "name" : "minecraft:fireball", + "id" : 385 + }, + { + "name" : "minecraft:writable_book", + "id" : 386 + }, + { + "name" : "minecraft:frame", + "id" : 389 + }, + { + "name" : "minecraft:smoker", + "id" : -198 + }, + { + "name" : "minecraft:flower_pot", + "id" : 390 + }, + { + "name" : "minecraft:carrotonastick", + "id" : 398 + }, + { + "name" : "minecraft:netherstar", + "id" : 399 + }, + { + "name" : "minecraft:element_16", + "id" : -27 + }, + { + "name" : "minecraft:fireworks", + "id" : 401 + }, + { + "name" : "minecraft:element_30", + "id" : -41 + }, + { + "name" : "minecraft:fireworkscharge", + "id" : 402 + }, + { + "name" : "minecraft:trident", + "id" : 455 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 403 + }, + { + "name" : "minecraft:comparator", + "id" : 404 + }, + { + "name" : "minecraft:netherbrick", + "id" : 405 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:element_73", + "id" : -84 + }, + { + "name" : "minecraft:quartz", + "id" : 406 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 407 + }, + { + "name" : "minecraft:leaves2", + "id" : 161 + }, + { + "name" : "minecraft:element_102", + "id" : -113 + }, + { + "name" : "minecraft:coral_fan_hang2", + "id" : -136 + }, + { + "name" : "minecraft:element_67", + "id" : -78 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 408 + }, + { + "name" : "minecraft:lead", + "id" : 420 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:hopper", + "id" : 410 + }, + { + "name" : "minecraft:rabbit_foot", + "id" : 414 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 415 + }, + { + "name" : "minecraft:acacia_standing_sign", + "id" : -190 + }, + { + "name" : "minecraft:horsearmorleather", + "id" : 416 + }, + { + "name" : "minecraft:item.wheat", + "id" : 59 + }, + { + "name" : "minecraft:horsearmoriron", + "id" : 417 + }, + { + "name" : "minecraft:record_13", + "id" : 500 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:record_cat", + "id" : 501 + }, + { + "name" : "minecraft:element_89", + "id" : -100 + }, + { + "name" : "minecraft:record_blocks", + "id" : 502 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:element_72", + "id" : -83 + }, + { + "name" : "minecraft:record_chirp", + "id" : 503 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:record_far", + "id" : 504 + }, + { + "name" : "minecraft:record_wait", + "id" : 511 + }, + { + "name" : "minecraft:spruce_door", + "id" : 427 + }, + { + "name" : "minecraft:record_mellohi", + "id" : 506 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:record_ward", + "id" : 509 + }, + { + "name" : "minecraft:jungle_stairs", + "id" : 136 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 453 + }, + { + "name" : "minecraft:record_11", + "id" : 510 + }, + { + "name" : "minecraft:prismarine_crystals", + "id" : 422 + }, + { + "name" : "minecraft:banner", + "id" : 446 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:muttonraw", + "id" : 423 + }, + { + "name" : "minecraft:end_crystal", + "id" : 426 + }, + { + "name" : "minecraft:element_55", + "id" : -66 + }, + { + "name" : "minecraft:birch_door", + "id" : 428 + }, + { + "name" : "minecraft:darkoak_wall_sign", + "id" : -193 + }, + { + "name" : "minecraft:jungle_door", + "id" : 429 + }, + { + "name" : "minecraft:acacia_door", + "id" : 430 + }, + { + "name" : "minecraft:element_116", + "id" : -127 + }, + { + "name" : "minecraft:chorus_fruit", + "id" : 432 + }, + { + "name" : "minecraft:cobblestone_wall", + "id" : 139 + }, + { + "name" : "minecraft:cobblestone", + "id" : 4 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 437 + }, + { + "name" : "minecraft:cactus", + "id" : 81 + }, + { + "name" : "minecraft:splash_potion", + "id" : 438 + }, + { + "name" : "minecraft:spruce_stairs", + "id" : 134 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:powered_repeater", + "id" : 94 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 441 + }, + { + "name" : "minecraft:elytra", + "id" : 444 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 409 + }, + { + "name" : "minecraft:element_112", + "id" : -123 + }, + { + "name" : "minecraft:totem", + "id" : 450 + }, + { + "name" : "minecraft:iron_nugget", + "id" : 452 + }, + { + "name" : "minecraft:pumpkin_stem", + "id" : 104 + }, + { + "name" : "minecraft:element_50", + "id" : -61 + }, + { + "name" : "minecraft:lever", + "id" : 69 + }, + { + "name" : "minecraft:heart_of_the_sea", + "id" : 467 + }, + { + "name" : "minecraft:element_92", + "id" : -103 + }, + { + "name" : "minecraft:grass", + "id" : 2 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 469 + }, + { + "name" : "minecraft:wall_banner", + "id" : 177 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 470 + }, + { + "name" : "minecraft:crossbow", + "id" : 471 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 472 + }, + { + "name" : "minecraft:quartz_stairs", + "id" : 156 + }, + { + "name" : "minecraft:daylight_detector_inverted", + "id" : 178 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 474 + }, + { + "name" : "minecraft:red_flower", + "id" : 38 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 434 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 734 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:honeycomb", + "id" : 736 + }, + { + "name" : "minecraft:element_115", + "id" : -126 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 737 + }, + { + "name" : "minecraft:element_4", + "id" : -15 + }, + { + "name" : "minecraft:element_24", + "id" : -35 + }, + { + "name" : "minecraft:camera", + "id" : 498 + }, + { + "name" : "minecraft:compound", + "id" : 499 + }, + { + "name" : "minecraft:bleach", + "id" : 451 + }, + { + "name" : "minecraft:element_40", + "id" : -51 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 449 + }, + { + "name" : "minecraft:balloon", + "id" : 448 + }, + { + "name" : "minecraft:redstone_ore", + "id" : 73 + }, + { + "name" : "minecraft:stonecutter_block", + "id" : -197 + }, + { + "name" : "minecraft:medicine", + "id" : 447 + }, + { + "name" : "minecraft:gold_block", + "id" : 41 + }, + { + "name" : "minecraft:stripped_oak_log", + "id" : -10 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, + { + "name" : "minecraft:sparkler", + "id" : 442 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:sand", + "id" : 12 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:unpowered_comparator", + "id" : 149 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:item.kelp", + "id" : -138 + }, + { + "name" : "minecraft:coral_block", + "id" : -132 + }, + { + "name" : "minecraft:element_54", + "id" : -65 + }, + { + "name" : "minecraft:double_stone_slab", + "id" : 44 + }, + { + "name" : "minecraft:double_stone_slab3", + "id" : -162 + }, + { + "name" : "minecraft:element_2", + "id" : -13 + }, + { + "name" : "minecraft:element_22", + "id" : -33 + }, + { + "name" : "minecraft:real_double_stone_slab2", + "id" : 181 + }, + { + "name" : "minecraft:real_double_stone_slab3", + "id" : -167 + }, + { + "name" : "minecraft:coral_fan", + "id" : -133 + }, + { + "name" : "minecraft:leaves", + "id" : 18 + }, + { + "name" : "minecraft:element_10", + "id" : -21 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:sandstone", + "id" : 24 + }, + { + "name" : "minecraft:red_sandstone", + "id" : 179 + }, + { + "name" : "minecraft:element_91", + "id" : -102 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:end_stone", + "id" : 121 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:waterlily", + "id" : 111 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:black_glazed_terracotta", + "id" : 235 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:quartz_block", + "id" : 155 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:end_portal_frame", + "id" : 120 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:prismarine", + "id" : 168 + }, + { + "name" : "minecraft:sealantern", + "id" : 169 + }, + { + "name" : "minecraft:hard_stained_glass", + "id" : 254 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:element_82", + "id" : -93 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:quartz_ore", + "id" : 153 + }, + { + "name" : "minecraft:undyed_shulker_box", + "id" : 205 + }, + { + "name" : "minecraft:element_107", + "id" : -118 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:colored_torch_bp", + "id" : 204 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:scaffolding", + "id" : -165 + }, + { + "name" : "minecraft:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:item.cauldron", + "id" : 118 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:bell", + "id" : -206 + }, + { + "name" : "minecraft:element_42", + "id" : -53 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:end_rod", + "id" : 208 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:element_70", + "id" : -81 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:hard_stained_glass_pane", + "id" : 191 + }, + { + "name" : "minecraft:colored_torch_rg", + "id" : 202 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:element_0", + "id" : 36 + }, + { + "name" : "minecraft:element_20", + "id" : -31 + }, + { + "name" : "minecraft:element_1", + "id" : -12 + }, + { + "name" : "minecraft:element_21", + "id" : -32 + }, + { + "name" : "minecraft:element_6", + "id" : -17 + }, + { + "name" : "minecraft:element_26", + "id" : -37 + }, + { + "name" : "minecraft:element_7", + "id" : -18 + }, + { + "name" : "minecraft:element_27", + "id" : -38 + }, + { + "name" : "minecraft:element_8", + "id" : -19 + }, + { + "name" : "minecraft:element_28", + "id" : -39 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:element_9", + "id" : -20 + }, + { + "name" : "minecraft:element_29", + "id" : -40 + }, + { + "name" : "minecraft:item.spruce_door", + "id" : 193 + }, + { + "name" : "minecraft:element_12", + "id" : -23 + }, + { + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 + }, + { + "name" : "minecraft:element_13", + "id" : -24 + }, + { + "name" : "minecraft:element_14", + "id" : -25 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:element_17", + "id" : -28 + }, + { + "name" : "minecraft:element_18", + "id" : -29 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:element_19", + "id" : -30 + }, + { + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 + }, + { + "name" : "minecraft:element_33", + "id" : -44 + }, + { + "name" : "minecraft:element_34", + "id" : -45 + }, + { + "name" : "minecraft:element_35", + "id" : -46 + }, + { + "name" : "minecraft:composter", + "id" : -213 + }, + { + "name" : "minecraft:element_36", + "id" : -47 + }, + { + "name" : "minecraft:element_37", + "id" : -48 + }, + { + "name" : "minecraft:element_39", + "id" : -50 + }, + { + "name" : "minecraft:element_41", + "id" : -52 + }, + { + "name" : "minecraft:hay_block", + "id" : 170 + }, + { + "name" : "minecraft:element_43", + "id" : -54 + }, + { + "name" : "minecraft:lit_redstone_lamp", + "id" : 124 + }, + { + "name" : "minecraft:element_44", + "id" : -55 + }, + { + "name" : "minecraft:element_45", + "id" : -56 + }, + { + "name" : "minecraft:element_49", + "id" : -60 + }, + { + "name" : "minecraft:element_51", + "id" : -62 + }, + { + "name" : "minecraft:element_56", + "id" : -67 + }, + { + "name" : "minecraft:element_57", + "id" : -68 + }, + { + "name" : "minecraft:element_59", + "id" : -70 + }, + { + "name" : "minecraft:element_60", + "id" : -71 + }, + { + "name" : "minecraft:dropper", + "id" : 125 + }, + { + "name" : "minecraft:element_61", + "id" : -72 + }, + { + "name" : "minecraft:element_63", + "id" : -74 + }, + { + "name" : "minecraft:element_64", + "id" : -75 + }, + { + "name" : "minecraft:element_65", + "id" : -76 + }, + { + "name" : "minecraft:coral_fan_hang3", + "id" : -137 + }, + { + "name" : "minecraft:element_66", + "id" : -77 + }, + { + "name" : "minecraft:redstone_lamp", + "id" : 123 + }, + { + "name" : "minecraft:element_68", + "id" : -79 + }, + { + "name" : "minecraft:spruce_trapdoor", + "id" : -149 + }, + { + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 + }, + { + "name" : "minecraft:element_69", + "id" : -80 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:element_71", + "id" : -82 + }, + { + "name" : "minecraft:element_76", + "id" : -87 + }, + { + "name" : "minecraft:element_77", + "id" : -88 + }, + { + "name" : "minecraft:water", + "id" : 9 + }, + { + "name" : "minecraft:element_78", + "id" : -89 + }, + { + "name" : "minecraft:element_79", + "id" : -90 + }, + { + "name" : "minecraft:element_80", + "id" : -91 + }, + { + "name" : "minecraft:netherreactor", + "id" : 247 + }, + { + "name" : "minecraft:element_83", + "id" : -94 + }, + { + "name" : "minecraft:element_84", + "id" : -95 + }, + { + "name" : "minecraft:jungle_wall_sign", + "id" : -189 + }, + { + "name" : "minecraft:end_brick_stairs", + "id" : -178 + }, + { + "name" : "minecraft:element_85", + "id" : -96 + }, + { + "name" : "minecraft:element_88", + "id" : -99 + }, + { + "name" : "minecraft:element_90", + "id" : -101 + }, + { + "name" : "minecraft:birch_standing_sign", + "id" : -186 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 + }, + { + "name" : "minecraft:element_93", + "id" : -104 + }, + { + "name" : "minecraft:element_94", + "id" : -105 + }, + { + "name" : "minecraft:element_95", + "id" : -106 + }, + { + "name" : "minecraft:glass", + "id" : 20 + }, + { + "name" : "minecraft:red_nether_brick", + "id" : 215 + }, + { + "name" : "minecraft:element_98", + "id" : -109 + }, + { + "name" : "minecraft:element_99", + "id" : -110 + }, + { + "name" : "minecraft:element_100", + "id" : -111 + }, + { + "name" : "minecraft:element_101", + "id" : -112 + }, + { + "name" : "minecraft:element_103", + "id" : -114 + }, + { + "name" : "minecraft:element_106", + "id" : -117 + }, + { + "name" : "minecraft:element_108", + "id" : -119 + }, + { + "name" : "minecraft:element_109", + "id" : -120 + }, + { + "name" : "minecraft:element_110", + "id" : -121 + }, + { + "name" : "minecraft:element_111", + "id" : -122 + }, + { + "name" : "minecraft:element_114", + "id" : -125 + }, + { + "name" : "minecraft:element_117", + "id" : -128 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:spruce_standing_sign", + "id" : -181 + }, + { + "name" : "minecraft:element_118", + "id" : -129 + }, + { + "name" : "minecraft:gravel", + "id" : 13 + }, + { + "name" : "minecraft:detector_rail", + "id" : 28 + }, + { + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "name" : "minecraft:diamond_block", + "id" : 57 + }, + { + "name" : "minecraft:item.cake", + "id" : 92 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:furnace", + "id" : 61 + }, + { + "name" : "minecraft:underwater_torch", + "id" : 239 + }, + { + "name" : "minecraft:web", + "id" : 30 + }, + { + "name" : "minecraft:jungle_standing_sign", + "id" : -188 + }, + { + "name" : "minecraft:standing_sign", + "id" : 63 + }, + { + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:beehive", + "id" : -219 + }, + { + "name" : "minecraft:item.bed", + "id" : 26 + }, + { + "name" : "minecraft:lapis_block", + "id" : 22 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:brick_block", + "id" : 45 + }, + { + "name" : "minecraft:dried_kelp_block", + "id" : -139 + }, + { + "name" : "minecraft:structure_block", + "id" : 252 + }, + { + "name" : "minecraft:pistonarmcollision", + "id" : 34 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:acacia_trapdoor", + "id" : -145 + }, + { + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:redstone_wire", + "id" : 55 + }, + { + "name" : "minecraft:farmland", + "id" : 60 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:red_sandstone_stairs", + "id" : 180 + }, + { + "name" : "minecraft:item.iron_door", + "id" : 71 + }, + { + "name" : "minecraft:lit_redstone_ore", + "id" : 74 + }, + { + "name" : "minecraft:stripped_jungle_log", + "id" : -7 + }, + { + "name" : "minecraft:unlit_redstone_torch", + "id" : 75 + }, + { + "name" : "minecraft:red_nether_brick_stairs", + "id" : -184 + }, + { + "name" : "minecraft:redstone_torch", + "id" : 76 + }, + { + "name" : "minecraft:ice", + "id" : 79 + }, + { + "name" : "minecraft:snow", + "id" : 80 + }, + { + "name" : "minecraft:command_block", + "id" : 137 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:jukebox", + "id" : 84 + }, + { + "name" : "minecraft:pumpkin", + "id" : 86 + }, + { + "name" : "minecraft:item.acacia_door", + "id" : 196 + }, + { + "name" : "minecraft:nether_brick_stairs", + "id" : 114 + }, + { + "name" : "minecraft:netherrack", + "id" : 87 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:hard_glass", + "id" : 253 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:item.beetroot", + "id" : 244 + }, + { + "name" : "minecraft:unpowered_repeater", + "id" : 93 + }, + { + "name" : "minecraft:invisiblebedrock", + "id" : 95 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:item.jungle_door", + "id" : 195 + }, + { + "name" : "minecraft:iron_bars", + "id" : 101 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:melon_block", + "id" : 103 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:melon_stem", + "id" : 105 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:brick_stairs", + "id" : 108 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:smooth_stone", + "id" : -183 + }, + { + "name" : "minecraft:nether_brick_fence", + "id" : 113 + }, + { + "name" : "minecraft:item.nether_wart", + "id" : 115 + }, + { + "name" : "minecraft:enchanting_table", + "id" : 116 + }, + { + "name" : "minecraft:end_portal", + "id" : 119 + }, + { + "name" : "minecraft:dragon_egg", + "id" : 122 + }, + { + "name" : "minecraft:granite_stairs", + "id" : -169 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:activator_rail", + "id" : 126 + }, + { + "name" : "minecraft:cocoa", + "id" : 127 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:birch_stairs", + "id" : 135 + }, + { + "name" : "minecraft:coral_fan_hang", + "id" : -135 + }, + { + "name" : "minecraft:packed_ice", + "id" : 174 + }, + { + "name" : "minecraft:item.flower_pot", + "id" : 140 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 + }, + { + "name" : "minecraft:wooden_button", + "id" : 143 + }, + { + "name" : "minecraft:item.skull", + "id" : 144 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:light_weighted_pressure_plate", + "id" : 147 + }, + { + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 + }, + { + "name" : "minecraft:daylight_detector", + "id" : 151 + }, + { + "name" : "minecraft:smooth_sandstone_stairs", + "id" : -177 + }, + { + "name" : "minecraft:repeating_command_block", + "id" : 188 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:dark_oak_stairs", + "id" : 164 + }, + { + "name" : "minecraft:iron_trapdoor", + "id" : 167 + }, + { + "name" : "minecraft:hardened_clay", + "id" : 172 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:purpur_stairs", + "id" : 203 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:grass_path", + "id" : 198 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:normal_stone_stairs", + "id" : -180 + }, + { + "name" : "minecraft:chorus_flower", + "id" : 200 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:end_bricks", + "id" : 206 + }, + { + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 + }, + { + "name" : "minecraft:movingblock", + "id" : 250 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:chorus_plant", + "id" : 240 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:item.camera", + "id" : 242 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:dark_prismarine_stairs", + "id" : -3 + }, + { + "name" : "minecraft:prismarine_bricks_stairs", + "id" : -4 + }, + { + "name" : "minecraft:stripped_spruce_log", + "id" : -5 + }, + { + "name" : "minecraft:stripped_dark_oak_log", + "id" : -9 + }, + { + "name" : "minecraft:hard_glass_pane", + "id" : 190 + }, + { + "name" : "minecraft:mossy_cobblestone_stairs", + "id" : -179 + }, + { + "name" : "minecraft:smooth_red_sandstone_stairs", + "id" : -176 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:birch_wall_sign", + "id" : -187 + }, + { + "name" : "minecraft:spruce_wall_sign", + "id" : -182 + }, + { + "name" : "minecraft:jungle_trapdoor", + "id" : -148 + }, + { + "name" : "minecraft:dark_oak_button", + "id" : -142 + }, + { + "name" : "minecraft:birch_trapdoor", + "id" : -146 + }, + { + "name" : "minecraft:jigsaw", + "id" : -211 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:polished_diorite_stairs", + "id" : -173 + }, + { + "name" : "minecraft:smooth_quartz_stairs", + "id" : -185 + }, + { + "name" : "minecraft:acacia_wall_sign", + "id" : -191 + }, + { + "name" : "minecraft:lit_smoker", + "id" : -199 + }, + { + "name" : "minecraft:item.campfire", + "id" : -209 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + } +] \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/legacy_block_ids.json b/connector/src/main/resources/bedrock/legacy_block_ids.json new file mode 100644 index 00000000..e5347d87 --- /dev/null +++ b/connector/src/main/resources/bedrock/legacy_block_ids.json @@ -0,0 +1,462 @@ +{ + "minecraft:air": 0, + "minecraft:stone": 1, + "minecraft:grass": 2, + "minecraft:dirt": 3, + "minecraft:cobblestone": 4, + "minecraft:planks": 5, + "minecraft:sapling": 6, + "minecraft:bedrock": 7, + "minecraft:flowing_water": 8, + "minecraft:water": 9, + "minecraft:flowing_lava": 10, + "minecraft:lava": 11, + "minecraft:sand": 12, + "minecraft:gravel": 13, + "minecraft:gold_ore": 14, + "minecraft:iron_ore": 15, + "minecraft:coal_ore": 16, + "minecraft:log": 17, + "minecraft:leaves": 18, + "minecraft:sponge": 19, + "minecraft:glass": 20, + "minecraft:lapis_ore": 21, + "minecraft:lapis_block": 22, + "minecraft:dispenser": 23, + "minecraft:sandstone": 24, + "minecraft:noteblock": 25, + "minecraft:bed": 26, + "minecraft:golden_rail": 27, + "minecraft:detector_rail": 28, + "minecraft:sticky_piston": 29, + "minecraft:web": 30, + "minecraft:tallgrass": 31, + "minecraft:deadbush": 32, + "minecraft:piston": 33, + "minecraft:pistonArmCollision": 34, + "minecraft:wool": 35, + "minecraft:element_0": 36, + "minecraft:yellow_flower": 37, + "minecraft:red_flower": 38, + "minecraft:brown_mushroom": 39, + "minecraft:red_mushroom": 40, + "minecraft:gold_block": 41, + "minecraft:iron_block": 42, + "minecraft:double_stone_slab": 43, + "minecraft:stone_slab": 44, + "minecraft:brick_block": 45, + "minecraft:tnt": 46, + "minecraft:bookshelf": 47, + "minecraft:mossy_cobblestone": 48, + "minecraft:obsidian": 49, + "minecraft:torch": 50, + "minecraft:fire": 51, + "minecraft:mob_spawner": 52, + "minecraft:oak_stairs": 53, + "minecraft:chest": 54, + "minecraft:redstone_wire": 55, + "minecraft:diamond_ore": 56, + "minecraft:diamond_block": 57, + "minecraft:crafting_table": 58, + "minecraft:wheat": 59, + "minecraft:farmland": 60, + "minecraft:furnace": 61, + "minecraft:lit_furnace": 62, + "minecraft:standing_sign": 63, + "minecraft:wooden_door": 64, + "minecraft:ladder": 65, + "minecraft:rail": 66, + "minecraft:stone_stairs": 67, + "minecraft:wall_sign": 68, + "minecraft:lever": 69, + "minecraft:stone_pressure_plate": 70, + "minecraft:iron_door": 71, + "minecraft:wooden_pressure_plate": 72, + "minecraft:redstone_ore": 73, + "minecraft:lit_redstone_ore": 74, + "minecraft:unlit_redstone_torch": 75, + "minecraft:redstone_torch": 76, + "minecraft:stone_button": 77, + "minecraft:snow_layer": 78, + "minecraft:ice": 79, + "minecraft:snow": 80, + "minecraft:cactus": 81, + "minecraft:clay": 82, + "minecraft:reeds": 83, + "minecraft:jukebox": 84, + "minecraft:fence": 85, + "minecraft:pumpkin": 86, + "minecraft:netherrack": 87, + "minecraft:soul_sand": 88, + "minecraft:glowstone": 89, + "minecraft:portal": 90, + "minecraft:lit_pumpkin": 91, + "minecraft:cake": 92, + "minecraft:unpowered_repeater": 93, + "minecraft:powered_repeater": 94, + "minecraft:invisibleBedrock": 95, + "minecraft:trapdoor": 96, + "minecraft:monster_egg": 97, + "minecraft:stonebrick": 98, + "minecraft:brown_mushroom_block": 99, + "minecraft:red_mushroom_block": 100, + "minecraft:iron_bars": 101, + "minecraft:glass_pane": 102, + "minecraft:melon_block": 103, + "minecraft:pumpkin_stem": 104, + "minecraft:melon_stem": 105, + "minecraft:vine": 106, + "minecraft:fence_gate": 107, + "minecraft:brick_stairs": 108, + "minecraft:stone_brick_stairs": 109, + "minecraft:mycelium": 110, + "minecraft:waterlily": 111, + "minecraft:nether_brick": 112, + "minecraft:nether_brick_fence": 113, + "minecraft:nether_brick_stairs": 114, + "minecraft:nether_wart": 115, + "minecraft:enchanting_table": 116, + "minecraft:brewing_stand": 117, + "minecraft:cauldron": 118, + "minecraft:end_portal": 119, + "minecraft:end_portal_frame": 120, + "minecraft:end_stone": 121, + "minecraft:dragon_egg": 122, + "minecraft:redstone_lamp": 123, + "minecraft:lit_redstone_lamp": 124, + "minecraft:dropper": 125, + "minecraft:activator_rail": 126, + "minecraft:cocoa": 127, + "minecraft:sandstone_stairs": 128, + "minecraft:emerald_ore": 129, + "minecraft:ender_chest": 130, + "minecraft:tripwire_hook": 131, + "minecraft:tripWire": 132, + "minecraft:emerald_block": 133, + "minecraft:spruce_stairs": 134, + "minecraft:birch_stairs": 135, + "minecraft:jungle_stairs": 136, + "minecraft:command_block": 137, + "minecraft:beacon": 138, + "minecraft:cobblestone_wall": 139, + "minecraft:flower_pot": 140, + "minecraft:carrots": 141, + "minecraft:potatoes": 142, + "minecraft:wooden_button": 143, + "minecraft:skull": 144, + "minecraft:anvil": 145, + "minecraft:trapped_chest": 146, + "minecraft:light_weighted_pressure_plate": 147, + "minecraft:heavy_weighted_pressure_plate": 148, + "minecraft:unpowered_comparator": 149, + "minecraft:powered_comparator": 150, + "minecraft:daylight_detector": 151, + "minecraft:redstone_block": 152, + "minecraft:quartz_ore": 153, + "minecraft:hopper": 154, + "minecraft:quartz_block": 155, + "minecraft:quartz_stairs": 156, + "minecraft:double_wooden_slab": 157, + "minecraft:wooden_slab": 158, + "minecraft:stained_hardened_clay": 159, + "minecraft:stained_glass_pane": 160, + "minecraft:leaves2": 161, + "minecraft:log2": 162, + "minecraft:acacia_stairs": 163, + "minecraft:dark_oak_stairs": 164, + "minecraft:slime": 165, + "minecraft:iron_trapdoor": 167, + "minecraft:prismarine": 168, + "minecraft:seaLantern": 169, + "minecraft:hay_block": 170, + "minecraft:carpet": 171, + "minecraft:hardened_clay": 172, + "minecraft:coal_block": 173, + "minecraft:packed_ice": 174, + "minecraft:double_plant": 175, + "minecraft:standing_banner": 176, + "minecraft:wall_banner": 177, + "minecraft:daylight_detector_inverted": 178, + "minecraft:red_sandstone": 179, + "minecraft:red_sandstone_stairs": 180, + "minecraft:double_stone_slab2": 181, + "minecraft:stone_slab2": 182, + "minecraft:spruce_fence_gate": 183, + "minecraft:birch_fence_gate": 184, + "minecraft:jungle_fence_gate": 185, + "minecraft:dark_oak_fence_gate": 186, + "minecraft:acacia_fence_gate": 187, + "minecraft:repeating_command_block": 188, + "minecraft:chain_command_block": 189, + "minecraft:hard_glass_pane": 190, + "minecraft:hard_stained_glass_pane": 191, + "minecraft:chemical_heat": 192, + "minecraft:spruce_door": 193, + "minecraft:birch_door": 194, + "minecraft:jungle_door": 195, + "minecraft:acacia_door": 196, + "minecraft:dark_oak_door": 197, + "minecraft:grass_path": 198, + "minecraft:frame": 199, + "minecraft:chorus_flower": 200, + "minecraft:purpur_block": 201, + "minecraft:colored_torch_rg": 202, + "minecraft:purpur_stairs": 203, + "minecraft:colored_torch_bp": 204, + "minecraft:undyed_shulker_box": 205, + "minecraft:end_bricks": 206, + "minecraft:frosted_ice": 207, + "minecraft:end_rod": 208, + "minecraft:end_gateway": 209, + "minecraft:magma": 213, + "minecraft:nether_wart_block": 214, + "minecraft:red_nether_brick": 215, + "minecraft:bone_block": 216, + "minecraft:shulker_box": 218, + "minecraft:purple_glazed_terracotta": 219, + "minecraft:white_glazed_terracotta": 220, + "minecraft:orange_glazed_terracotta": 221, + "minecraft:magenta_glazed_terracotta": 222, + "minecraft:light_blue_glazed_terracotta": 223, + "minecraft:yellow_glazed_terracotta": 224, + "minecraft:lime_glazed_terracotta": 225, + "minecraft:pink_glazed_terracotta": 226, + "minecraft:gray_glazed_terracotta": 227, + "minecraft:silver_glazed_terracotta": 228, + "minecraft:cyan_glazed_terracotta": 229, + "minecraft:blue_glazed_terracotta": 231, + "minecraft:brown_glazed_terracotta": 232, + "minecraft:green_glazed_terracotta": 233, + "minecraft:red_glazed_terracotta": 234, + "minecraft:black_glazed_terracotta": 235, + "minecraft:concrete": 236, + "minecraft:concretePowder": 237, + "minecraft:chemistry_table": 238, + "minecraft:underwater_torch": 239, + "minecraft:chorus_plant": 240, + "minecraft:stained_glass": 241, + "minecraft:podzol": 243, + "minecraft:beetroot": 244, + "minecraft:stonecutter": 245, + "minecraft:glowingobsidian": 246, + "minecraft:netherreactor": 247, + "minecraft:info_update": 248, + "minecraft:info_update2": 249, + "minecraft:movingBlock": 250, + "minecraft:observer": 251, + "minecraft:structure_block": 252, + "minecraft:hard_glass": 253, + "minecraft:hard_stained_glass": 254, + "minecraft:reserved6": 255, + "minecraft:prismarine_stairs": 257, + "minecraft:dark_prismarine_stairs": 258, + "minecraft:prismarine_bricks_stairs": 259, + "minecraft:stripped_spruce_log": 260, + "minecraft:stripped_birch_log": 261, + "minecraft:stripped_jungle_log": 262, + "minecraft:stripped_acacia_log": 263, + "minecraft:stripped_dark_oak_log": 264, + "minecraft:stripped_oak_log": 265, + "minecraft:blue_ice": 266, + "minecraft:element_1": 267, + "minecraft:element_2": 268, + "minecraft:element_3": 269, + "minecraft:element_4": 270, + "minecraft:element_5": 271, + "minecraft:element_6": 272, + "minecraft:element_7": 273, + "minecraft:element_8": 274, + "minecraft:element_9": 275, + "minecraft:element_10": 276, + "minecraft:element_11": 277, + "minecraft:element_12": 278, + "minecraft:element_13": 279, + "minecraft:element_14": 280, + "minecraft:element_15": 281, + "minecraft:element_16": 282, + "minecraft:element_17": 283, + "minecraft:element_18": 284, + "minecraft:element_19": 285, + "minecraft:element_20": 286, + "minecraft:element_21": 287, + "minecraft:element_22": 288, + "minecraft:element_23": 289, + "minecraft:element_24": 290, + "minecraft:element_25": 291, + "minecraft:element_26": 292, + "minecraft:element_27": 293, + "minecraft:element_28": 294, + "minecraft:element_29": 295, + "minecraft:element_30": 296, + "minecraft:element_31": 297, + "minecraft:element_32": 298, + "minecraft:element_33": 299, + "minecraft:element_34": 300, + "minecraft:element_35": 301, + "minecraft:element_36": 302, + "minecraft:element_37": 303, + "minecraft:element_38": 304, + "minecraft:element_39": 305, + "minecraft:element_40": 306, + "minecraft:element_41": 307, + "minecraft:element_42": 308, + "minecraft:element_43": 309, + "minecraft:element_44": 310, + "minecraft:element_45": 311, + "minecraft:element_46": 312, + "minecraft:element_47": 313, + "minecraft:element_48": 314, + "minecraft:element_49": 315, + "minecraft:element_50": 316, + "minecraft:element_51": 317, + "minecraft:element_52": 318, + "minecraft:element_53": 319, + "minecraft:element_54": 320, + "minecraft:element_55": 321, + "minecraft:element_56": 322, + "minecraft:element_57": 323, + "minecraft:element_58": 324, + "minecraft:element_59": 325, + "minecraft:element_60": 326, + "minecraft:element_61": 327, + "minecraft:element_62": 328, + "minecraft:element_63": 329, + "minecraft:element_64": 330, + "minecraft:element_65": 331, + "minecraft:element_66": 332, + "minecraft:element_67": 333, + "minecraft:element_68": 334, + "minecraft:element_69": 335, + "minecraft:element_70": 336, + "minecraft:element_71": 337, + "minecraft:element_72": 338, + "minecraft:element_73": 339, + "minecraft:element_74": 340, + "minecraft:element_75": 341, + "minecraft:element_76": 342, + "minecraft:element_77": 343, + "minecraft:element_78": 344, + "minecraft:element_79": 345, + "minecraft:element_80": 346, + "minecraft:element_81": 347, + "minecraft:element_82": 348, + "minecraft:element_83": 349, + "minecraft:element_84": 350, + "minecraft:element_85": 351, + "minecraft:element_86": 352, + "minecraft:element_87": 353, + "minecraft:element_88": 354, + "minecraft:element_89": 355, + "minecraft:element_90": 356, + "minecraft:element_91": 357, + "minecraft:element_92": 358, + "minecraft:element_93": 359, + "minecraft:element_94": 360, + "minecraft:element_95": 361, + "minecraft:element_96": 362, + "minecraft:element_97": 363, + "minecraft:element_98": 364, + "minecraft:element_99": 365, + "minecraft:element_100": 366, + "minecraft:element_101": 367, + "minecraft:element_102": 368, + "minecraft:element_103": 369, + "minecraft:element_104": 370, + "minecraft:element_105": 371, + "minecraft:element_106": 372, + "minecraft:element_107": 373, + "minecraft:element_108": 374, + "minecraft:element_109": 375, + "minecraft:element_110": 376, + "minecraft:element_111": 377, + "minecraft:element_112": 378, + "minecraft:element_113": 379, + "minecraft:element_114": 380, + "minecraft:element_115": 381, + "minecraft:element_116": 382, + "minecraft:element_117": 383, + "minecraft:element_118": 384, + "minecraft:seagrass": 385, + "minecraft:coral": 386, + "minecraft:coral_block": 387, + "minecraft:coral_fan": 388, + "minecraft:coral_fan_dead": 389, + "minecraft:coral_fan_hang": 390, + "minecraft:coral_fan_hang2": 391, + "minecraft:coral_fan_hang3": 392, + "minecraft:kelp": 393, + "minecraft:dried_kelp_block": 394, + "minecraft:acacia_button": 395, + "minecraft:birch_button": 396, + "minecraft:dark_oak_button": 397, + "minecraft:jungle_button": 398, + "minecraft:spruce_button": 399, + "minecraft:acacia_trapdoor": 400, + "minecraft:birch_trapdoor": 401, + "minecraft:dark_oak_trapdoor": 402, + "minecraft:jungle_trapdoor": 403, + "minecraft:spruce_trapdoor": 404, + "minecraft:acacia_pressure_plate": 405, + "minecraft:birch_pressure_plate": 406, + "minecraft:dark_oak_pressure_plate": 407, + "minecraft:jungle_pressure_plate": 408, + "minecraft:spruce_pressure_plate": 409, + "minecraft:carved_pumpkin": 410, + "minecraft:sea_pickle": 411, + "minecraft:conduit": 412, + "minecraft:turtle_egg": 414, + "minecraft:bubble_column": 415, + "minecraft:barrier": 416, + "minecraft:stone_slab3": 417, + "minecraft:bamboo": 418, + "minecraft:bamboo_sapling": 419, + "minecraft:scaffolding": 420, + "minecraft:stone_slab4": 421, + "minecraft:double_stone_slab3": 422, + "minecraft:double_stone_slab4": 423, + "minecraft:granite_stairs": 424, + "minecraft:diorite_stairs": 425, + "minecraft:andesite_stairs": 426, + "minecraft:polished_granite_stairs": 427, + "minecraft:polished_diorite_stairs": 428, + "minecraft:polished_andesite_stairs": 429, + "minecraft:mossy_stone_brick_stairs": 430, + "minecraft:smooth_red_sandstone_stairs": 431, + "minecraft:smooth_sandstone_stairs": 432, + "minecraft:end_brick_stairs": 433, + "minecraft:mossy_cobblestone_stairs": 434, + "minecraft:normal_stone_stairs": 435, + "minecraft:spruce_standing_sign": 436, + "minecraft:spruce_wall_sign": 437, + "minecraft:smooth_stone": 438, + "minecraft:red_nether_brick_stairs": 439, + "minecraft:smooth_quartz_stairs": 440, + "minecraft:birch_standing_sign": 441, + "minecraft:birch_wall_sign": 442, + "minecraft:jungle_standing_sign": 443, + "minecraft:jungle_wall_sign": 444, + "minecraft:acacia_standing_sign": 445, + "minecraft:acacia_wall_sign": 446, + "minecraft:darkoak_standing_sign": 447, + "minecraft:darkoak_wall_sign": 448, + "minecraft:lectern": 449, + "minecraft:grindstone": 450, + "minecraft:blast_furnace": 451, + "minecraft:stonecutter_block": 452, + "minecraft:smoker": 453, + "minecraft:lit_smoker": 454, + "minecraft:cartography_table": 455, + "minecraft:fletching_table": 456, + "minecraft:smithing_table": 457, + "minecraft:barrel": 458, + "minecraft:loom": 459, + "minecraft:bell": 461, + "minecraft:sweet_berry_bush": 462, + "minecraft:lantern": 463, + "minecraft:campfire": 464, + "minecraft:lava_cauldron": 465, + "minecraft:jigsaw": 466, + "minecraft:wood": 467, + "minecraft:composter": 468, + "minecraft:lit_blast_furnace": 469 +} \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/legacy_item_ids.json b/connector/src/main/resources/bedrock/legacy_item_ids.json new file mode 100644 index 00000000..21989249 --- /dev/null +++ b/connector/src/main/resources/bedrock/legacy_item_ids.json @@ -0,0 +1,229 @@ +{ + "minecraft:iron_shovel": 256, + "minecraft:iron_pickaxe": 257, + "minecraft:iron_axe": 258, + "minecraft:flint_and_steel": 259, + "minecraft:apple": 260, + "minecraft:bow": 261, + "minecraft:arrow": 262, + "minecraft:coal": 263, + "minecraft:diamond": 264, + "minecraft:iron_ingot": 265, + "minecraft:gold_ingot": 266, + "minecraft:iron_sword": 267, + "minecraft:wooden_sword": 268, + "minecraft:wooden_shovel": 269, + "minecraft:wooden_pickaxe": 270, + "minecraft:wooden_axe": 271, + "minecraft:stone_sword": 272, + "minecraft:stone_shovel": 273, + "minecraft:stone_pickaxe": 274, + "minecraft:stone_axe": 275, + "minecraft:diamond_sword": 276, + "minecraft:diamond_shovel": 277, + "minecraft:diamond_pickaxe": 278, + "minecraft:diamond_axe": 279, + "minecraft:stick": 280, + "minecraft:bowl": 281, + "minecraft:mushroom_stew": 282, + "minecraft:golden_sword": 283, + "minecraft:golden_shovel": 284, + "minecraft:golden_pickaxe": 285, + "minecraft:golden_axe": 286, + "minecraft:string": 287, + "minecraft:feather": 288, + "minecraft:gunpowder": 289, + "minecraft:wooden_hoe": 290, + "minecraft:stone_hoe": 291, + "minecraft:iron_hoe": 292, + "minecraft:diamond_hoe": 293, + "minecraft:golden_hoe": 294, + "minecraft:wheat_seeds": 295, + "minecraft:wheat": 296, + "minecraft:bread": 297, + "minecraft:leather_helmet": 298, + "minecraft:leather_chestplate": 299, + "minecraft:leather_leggings": 300, + "minecraft:leather_boots": 301, + "minecraft:chainmail_helmet": 302, + "minecraft:chainmail_chestplate": 303, + "minecraft:chainmail_leggings": 304, + "minecraft:chainmail_boots": 305, + "minecraft:iron_helmet": 306, + "minecraft:iron_chestplate": 307, + "minecraft:iron_leggings": 308, + "minecraft:iron_boots": 309, + "minecraft:diamond_helmet": 310, + "minecraft:diamond_chestplate": 311, + "minecraft:diamond_leggings": 312, + "minecraft:diamond_boots": 313, + "minecraft:golden_helmet": 314, + "minecraft:golden_chestplate": 315, + "minecraft:golden_leggings": 316, + "minecraft:golden_boots": 317, + "minecraft:flint": 318, + "minecraft:porkchop": 319, + "minecraft:cooked_porkchop": 320, + "minecraft:painting": 321, + "minecraft:golden_apple": 322, + "minecraft:sign": 323, + "minecraft:wooden_door": 324, + "minecraft:bucket": 325, + "minecraft:minecart": 328, + "minecraft:saddle": 329, + "minecraft:iron_door": 330, + "minecraft:redstone": 331, + "minecraft:snowball": 332, + "minecraft:boat": 333, + "minecraft:leather": 334, + "minecraft:kelp": 335, + "minecraft:brick": 336, + "minecraft:clay_ball": 337, + "minecraft:reeds": 338, + "minecraft:paper": 339, + "minecraft:book": 340, + "minecraft:slime_ball": 341, + "minecraft:chest_minecart": 342, + "minecraft:egg": 344, + "minecraft:compass": 345, + "minecraft:fishing_rod": 346, + "minecraft:clock": 347, + "minecraft:glowstone_dust": 348, + "minecraft:fish": 349, + "minecraft:cooked_fish": 350, + "minecraft:dye": 351, + "minecraft:bone": 352, + "minecraft:sugar": 353, + "minecraft:cake": 354, + "minecraft:bed": 355, + "minecraft:repeater": 356, + "minecraft:cookie": 357, + "minecraft:map": 358, + "minecraft:shears": 359, + "minecraft:melon": 360, + "minecraft:pumpkin_seeds": 361, + "minecraft:melon_seeds": 362, + "minecraft:beef": 363, + "minecraft:cooked_beef": 364, + "minecraft:chicken": 365, + "minecraft:cooked_chicken": 366, + "minecraft:rotten_flesh": 367, + "minecraft:ender_pearl": 368, + "minecraft:blaze_rod": 369, + "minecraft:ghast_tear": 370, + "minecraft:gold_nugget": 371, + "minecraft:nether_wart": 372, + "minecraft:potion": 373, + "minecraft:glass_bottle": 374, + "minecraft:spider_eye": 375, + "minecraft:fermented_spider_eye": 376, + "minecraft:blaze_powder": 377, + "minecraft:magma_cream": 378, + "minecraft:brewing_stand": 379, + "minecraft:cauldron": 380, + "minecraft:composter": 381, + "minecraft:speckled_melon": 382, + "minecraft:spawn_egg": 383, + "minecraft:experience_bottle": 384, + "minecraft:fireball": 385, + "minecraft:writable_book": 386, + "minecraft:written_book": 387, + "minecraft:emerald": 388, + "minecraft:frame": 389, + "minecraft:flower_pot": 390, + "minecraft:carrot": 391, + "minecraft:potato": 392, + "minecraft:baked_potato": 393, + "minecraft:poisonous_potato": 394, + "minecraft:emptyMap": 395, + "minecraft:golden_carrot": 396, + "minecraft:skull": 397, + "minecraft:carrotOnAStick": 398, + "minecraft:netherStar": 399, + "minecraft:pumpkin_pie": 400, + "minecraft:fireworks": 401, + "minecraft:fireworksCharge": 402, + "minecraft:enchanted_book": 403, + "minecraft:comparator": 404, + "minecraft:netherbrick": 405, + "minecraft:quartz": 406, + "minecraft:tnt_minecart": 407, + "minecraft:hopper_minecart": 408, + "minecraft:prismarine_shard": 409, + "minecraft:hopper": 410, + "minecraft:rabbit": 411, + "minecraft:cooked_rabbit": 412, + "minecraft:rabbit_stew": 413, + "minecraft:rabbit_foot": 414, + "minecraft:rabbit_hide": 415, + "minecraft:horsearmorleather": 416, + "minecraft:horsearmoriron": 417, + "minecraft:horsearmorgold": 418, + "minecraft:horsearmordiamond": 419, + "minecraft:lead": 420, + "minecraft:nametag": 422, + "minecraft:muttonRaw": 423, + "minecraft:muttonCooked": 424, + "minecraft:armor_stand": 425, + "minecraft:end_crystal": 426, + "minecraft:spruce_door": 427, + "minecraft:birch_door": 428, + "minecraft:jungle_door": 429, + "minecraft:acacia_door": 430, + "minecraft:dark_oak_door": 431, + "minecraft:chorus_fruit": 432, + "minecraft:chorus_fruit_popped": 433, + "minecraft:banner_pattern": 434, + "minecraft:dragon_breath": 437, + "minecraft:splash_potion": 438, + "minecraft:lingering_potion": 441, + "minecraft:sparkler": 442, + "minecraft:command_block_minecart": 443, + "minecraft:elytra": 444, + "minecraft:shulker_shell": 445, + "minecraft:banner": 446, + "minecraft:medicine": 447, + "minecraft:balloon": 448, + "minecraft:rapid_fertilizer": 449, + "minecraft:totem": 450, + "minecraft:bleach": 451, + "minecraft:iron_nugget": 452, + "minecraft:ice_bomb": 453, + "minecraft:trident": 455, + "minecraft:beetroot": 457, + "minecraft:beetroot_seeds": 458, + "minecraft:beetroot_soup": 459, + "minecraft:salmon": 460, + "minecraft:clownfish": 461, + "minecraft:pufferfish": 462, + "minecraft:cooked_salmon": 463, + "minecraft:dried_kelp": 464, + "minecraft:nautilus_shell": 465, + "minecraft:appleEnchanted": 466, + "minecraft:heart_of_the_sea": 467, + "minecraft:turtle_shell_piece": 468, + "minecraft:turtle_helmet": 469, + "minecraft:phantom_membrane": 470, + "minecraft:crossbow": 471, + "minecraft:spruce_sign": 472, + "minecraft:birch_sign": 473, + "minecraft:jungle_sign": 474, + "minecraft:acacia_sign": 475, + "minecraft:darkoak_sign": 476, + "minecraft:sweet_berries": 477, + "minecraft:compound": 499, + "minecraft:record_13": 500, + "minecraft:record_cat": 501, + "minecraft:record_blocks": 502, + "minecraft:record_chirp": 503, + "minecraft:record_far": 504, + "minecraft:record_mall": 505, + "minecraft:record_mellohi": 506, + "minecraft:record_stal": 507, + "minecraft:record_strad": 508, + "minecraft:record_ward": 509, + "minecraft:record_11": 510, + "minecraft:record_wait": 511, + "minecraft:shield": 513, + "minecraft:campfire": 720 +} diff --git a/connector/src/main/resources/bedrock/runtime_block_states.dat b/connector/src/main/resources/bedrock/runtime_block_states.dat new file mode 100644 index 00000000..0c79ab2f Binary files /dev/null and b/connector/src/main/resources/bedrock/runtime_block_states.dat differ diff --git a/connector/src/main/resources/bedrock/runtime_item_states.json b/connector/src/main/resources/bedrock/runtime_item_states.json deleted file mode 100644 index eaf6656b..00000000 --- a/connector/src/main/resources/bedrock/runtime_item_states.json +++ /dev/null @@ -1,3658 +0,0 @@ -[ - { - "name" : "minecraft:acacia_boat", - "id" : 377 - }, - { - "name" : "minecraft:acacia_button", - "id" : -140 - }, - { - "name" : "minecraft:acacia_door", - "id" : 546 - }, - { - "name" : "minecraft:acacia_fence_gate", - "id" : 187 - }, - { - "name" : "minecraft:acacia_pressure_plate", - "id" : -150 - }, - { - "name" : "minecraft:acacia_sign", - "id" : 569 - }, - { - "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" : 485 - }, - { - "name" : "minecraft:air", - "id" : -158 - }, - { - "name" : "minecraft:allow", - "id" : 210 - }, - { - "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" : 542 - }, - { - "name" : "minecraft:arrow", - "id" : 301 - }, - { - "name" : "minecraft:baked_potato", - "id" : 281 - }, - { - "name" : "minecraft:balloon", - "id" : 587 - }, - { - "name" : "minecraft:bamboo", - "id" : -163 - }, - { - "name" : "minecraft:bamboo_sapling", - "id" : -164 - }, - { - "name" : "minecraft:banner", - "id" : 557 - }, - { - "name" : "minecraft:banner_pattern", - "id" : 613 - }, - { - "name" : "minecraft:barrel", - "id" : -203 - }, - { - "name" : "minecraft:barrier", - "id" : -161 - }, - { - "name" : "minecraft:basalt", - "id" : -234 - }, - { - "name" : "minecraft:bat_spawn_egg", - "id" : 451 - }, - { - "name" : "minecraft:beacon", - "id" : 138 - }, - { - "name" : "minecraft:bed", - "id" : 416 - }, - { - "name" : "minecraft:bedrock", - "id" : 7 - }, - { - "name" : "minecraft:bee_nest", - "id" : -218 - }, - { - "name" : "minecraft:bee_spawn_egg", - "id" : 492 - }, - { - "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:birch_boat", - "id" : 374 - }, - { - "name" : "minecraft:birch_button", - "id" : -141 - }, - { - "name" : "minecraft:birch_door", - "id" : 544 - }, - { - "name" : "minecraft:birch_fence_gate", - "id" : 184 - }, - { - "name" : "minecraft:birch_pressure_plate", - "id" : -151 - }, - { - "name" : "minecraft:birch_sign", - "id" : 567 - }, - { - "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_dye", - "id" : 393 - }, - { - "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" : 427 - }, - { - "name" : "minecraft:blaze_rod", - "id" : 421 - }, - { - "name" : "minecraft:blaze_spawn_egg", - "id" : 454 - }, - { - "name" : "minecraft:bleach", - "id" : 585 - }, - { - "name" : "minecraft:blue_dye", - "id" : 397 - }, - { - "name" : "minecraft:blue_glazed_terracotta", - "id" : 231 - }, - { - "name" : "minecraft:blue_ice", - "id" : -11 - }, - { - "name" : "minecraft:boat", - "id" : 611 - }, - { - "name" : "minecraft:bone", - "id" : 413 - }, - { - "name" : "minecraft:bone_block", - "id" : 216 - }, - { - "name" : "minecraft:bone_meal", - "id" : 409 - }, - { - "name" : "minecraft:book", - "id" : 385 - }, - { - "name" : "minecraft:bookshelf", - "id" : 47 - }, - { - "name" : "minecraft:border_block", - "id" : 212 - }, - { - "name" : "minecraft:bordure_indented_banner_pattern", - "id" : 576 - }, - { - "name" : "minecraft:bow", - "id" : 300 - }, - { - "name" : "minecraft:bowl", - "id" : 321 - }, - { - "name" : "minecraft:bread", - "id" : 261 - }, - { - "name" : "minecraft:brewing_stand", - "id" : 429 - }, - { - "name" : "minecraft:brewingstandblock", - "id" : 117 - }, - { - "name" : "minecraft:brick", - "id" : 381 - }, - { - "name" : "minecraft:brick_block", - "id" : 45 - }, - { - "name" : "minecraft:brick_stairs", - "id" : 108 - }, - { - "name" : "minecraft:brown_dye", - "id" : 396 - }, - { - "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:cactus", - "id" : 81 - }, - { - "name" : "minecraft:cake", - "id" : 415 - }, - { - "name" : "minecraft:camera", - "id" : 582 - }, - { - "name" : "minecraft:campfire", - "id" : 578 - }, - { - "name" : "minecraft:carpet", - "id" : 171 - }, - { - "name" : "minecraft:carrot", - "id" : 279 - }, - { - "name" : "minecraft:carrot_on_a_stick", - "id" : 507 - }, - { - "name" : "minecraft:carrots", - "id" : 141 - }, - { - "name" : "minecraft:cartography_table", - "id" : -200 - }, - { - "name" : "minecraft:carved_pumpkin", - "id" : -155 - }, - { - "name" : "minecraft:cat_spawn_egg", - "id" : 486 - }, - { - "name" : "minecraft:cauldron", - "id" : 430 - }, - { - "name" : "minecraft:cave_spider_spawn_egg", - "id" : 455 - }, - { - "name" : "minecraft:chain", - "id" : 607 - }, - { - "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" : 387 - }, - { - "name" : "minecraft:chicken", - "id" : 275 - }, - { - "name" : "minecraft:chicken_spawn_egg", - "id" : 433 - }, - { - "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" : 548 - }, - { - "name" : "minecraft:chorus_plant", - "id" : 240 - }, - { - "name" : "minecraft:clay", - "id" : 82 - }, - { - "name" : "minecraft:clay_ball", - "id" : 382 - }, - { - "name" : "minecraft:clock", - "id" : 391 - }, - { - "name" : "minecraft:coal", - "id" : 302 - }, - { - "name" : "minecraft:coal_block", - "id" : 173 - }, - { - "name" : "minecraft:coal_ore", - "id" : 16 - }, - { - "name" : "minecraft:cobblestone", - "id" : 4 - }, - { - "name" : "minecraft:cobblestone_wall", - "id" : 139 - }, - { - "name" : "minecraft:cocoa", - "id" : 127 - }, - { - "name" : "minecraft:cocoa_beans", - "id" : 410 - }, - { - "name" : "minecraft:cod", - "id" : 264 - }, - { - "name" : "minecraft:cod_bucket", - "id" : 364 - }, - { - "name" : "minecraft:cod_spawn_egg", - "id" : 478 - }, - { - "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" : 553 - }, - { - "name" : "minecraft:comparator", - "id" : 512 - }, - { - "name" : "minecraft:compass", - "id" : 389 - }, - { - "name" : "minecraft:composter", - "id" : -213 - }, - { - "name" : "minecraft:compound", - "id" : 583 - }, - { - "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" : 541 - }, - { - "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: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" : 434 - }, - { - "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" : 572 - }, - { - "name" : "minecraft:creeper_spawn_egg", - "id" : 439 - }, - { - "name" : "minecraft:crimson_button", - "id" : -260 - }, - { - "name" : "minecraft:crimson_door", - "id" : 604 - }, - { - "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" : 602 - }, - { - "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" : 565 - }, - { - "name" : "minecraft:crying_obsidian", - "id" : -289 - }, - { - "name" : "minecraft:cyan_dye", - "id" : 399 - }, - { - "name" : "minecraft:cyan_glazed_terracotta", - "id" : 229 - }, - { - "name" : "minecraft:dark_oak_boat", - "id" : 378 - }, - { - "name" : "minecraft:dark_oak_button", - "id" : -142 - }, - { - "name" : "minecraft:dark_oak_door", - "id" : 547 - }, - { - "name" : "minecraft:dark_oak_fence_gate", - "id" : 186 - }, - { - "name" : "minecraft:dark_oak_pressure_plate", - "id" : -152 - }, - { - "name" : "minecraft:dark_oak_sign", - "id" : 570 - }, - { - "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: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" : 523 - }, - { - "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:dispenser", - "id" : 23 - }, - { - "name" : "minecraft:dolphin_spawn_egg", - "id" : 482 - }, - { - "name" : "minecraft:donkey_spawn_egg", - "id" : 463 - }, - { - "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" : 550 - }, - { - "name" : "minecraft:dragon_egg", - "id" : 122 - }, - { - "name" : "minecraft:dried_kelp", - "id" : 270 - }, - { - "name" : "minecraft:dried_kelp_block", - "id" : -139 - }, - { - "name" : "minecraft:dropper", - "id" : 125 - }, - { - "name" : "minecraft:drowned_spawn_egg", - "id" : 481 - }, - { - "name" : "minecraft:dye", - "id" : 612 - }, - { - "name" : "minecraft:egg", - "id" : 388 - }, - { - "name" : "minecraft:elder_guardian_spawn_egg", - "id" : 469 - }, - { - "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" : 554 - }, - { - "name" : "minecraft:emerald", - "id" : 502 - }, - { - "name" : "minecraft:emerald_block", - "id" : 133 - }, - { - "name" : "minecraft:emerald_ore", - "id" : 129 - }, - { - "name" : "minecraft:empty_map", - "id" : 505 - }, - { - "name" : "minecraft:enchanted_book", - "id" : 511 - }, - { - "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" : 615 - }, - { - "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" : 431 - }, - { - "name" : "minecraft:ender_pearl", - "id" : 420 - }, - { - "name" : "minecraft:enderman_spawn_egg", - "id" : 440 - }, - { - "name" : "minecraft:endermite_spawn_egg", - "id" : 458 - }, - { - "name" : "minecraft:evoker_spawn_egg", - "id" : 473 - }, - { - "name" : "minecraft:experience_bottle", - "id" : 498 - }, - { - "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" : 426 - }, - { - "name" : "minecraft:field_masoned_banner_pattern", - "id" : 575 - }, - { - "name" : "minecraft:filled_map", - "id" : 418 - }, - { - "name" : "minecraft:fire", - "id" : 51 - }, - { - "name" : "minecraft:fire_charge", - "id" : 499 - }, - { - "name" : "minecraft:firework_rocket", - "id" : 509 - }, - { - "name" : "minecraft:firework_star", - "id" : 510 - }, - { - "name" : "minecraft:fishing_rod", - "id" : 390 - }, - { - "name" : "minecraft:fletching_table", - "id" : -201 - }, - { - "name" : "minecraft:flint", - "id" : 356 - }, - { - "name" : "minecraft:flint_and_steel", - "id" : 299 - }, - { - "name" : "minecraft:flower_banner_pattern", - "id" : 571 - }, - { - "name" : "minecraft:flower_pot", - "id" : 504 - }, - { - "name" : "minecraft:flowing_lava", - "id" : 10 - }, - { - "name" : "minecraft:flowing_water", - "id" : 8 - }, - { - "name" : "minecraft:fox_spawn_egg", - "id" : 488 - }, - { - "name" : "minecraft:frame", - "id" : 503 - }, - { - "name" : "minecraft:frosted_ice", - "id" : 207 - }, - { - "name" : "minecraft:furnace", - "id" : 61 - }, - { - "name" : "minecraft:ghast_spawn_egg", - "id" : 452 - }, - { - "name" : "minecraft:ghast_tear", - "id" : 422 - }, - { - "name" : "minecraft:gilded_blackstone", - "id" : -281 - }, - { - "name" : "minecraft:glass", - "id" : 20 - }, - { - "name" : "minecraft:glass_bottle", - "id" : 425 - }, - { - "name" : "minecraft:glass_pane", - "id" : 102 - }, - { - "name" : "minecraft:glistering_melon_slice", - "id" : 432 - }, - { - "name" : "minecraft:glow_stick", - "id" : 166 - }, - { - "name" : "minecraft:glowingobsidian", - "id" : 246 - }, - { - "name" : "minecraft:glowstone", - "id" : 89 - }, - { - "name" : "minecraft:glowstone_dust", - "id" : 392 - }, - { - "name" : "minecraft:gold_block", - "id" : 41 - }, - { - "name" : "minecraft:gold_ingot", - "id" : 306 - }, - { - "name" : "minecraft:gold_nugget", - "id" : 423 - }, - { - "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" : 522 - }, - { - "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_dye", - "id" : 401 - }, - { - "name" : "minecraft:gray_glazed_terracotta", - "id" : 227 - }, - { - "name" : "minecraft:green_dye", - "id" : 395 - }, - { - "name" : "minecraft:green_glazed_terracotta", - "id" : 233 - }, - { - "name" : "minecraft:grindstone", - "id" : -195 - }, - { - "name" : "minecraft:guardian_spawn_egg", - "id" : 459 - }, - { - "name" : "minecraft:gunpowder", - "id" : 328 - }, - { - "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" : 561 - }, - { - "name" : "minecraft:heavy_weighted_pressure_plate", - "id" : 148 - }, - { - "name" : "minecraft:hoglin_spawn_egg", - "id" : 494 - }, - { - "name" : "minecraft:honey_block", - "id" : -220 - }, - { - "name" : "minecraft:honey_bottle", - "id" : 581 - }, - { - "name" : "minecraft:honeycomb", - "id" : 580 - }, - { - "name" : "minecraft:honeycomb_block", - "id" : -221 - }, - { - "name" : "minecraft:hopper", - "id" : 517 - }, - { - "name" : "minecraft:hopper_minecart", - "id" : 516 - }, - { - "name" : "minecraft:horse_spawn_egg", - "id" : 456 - }, - { - "name" : "minecraft:husk_spawn_egg", - "id" : 461 - }, - { - "name" : "minecraft:ice", - "id" : 79 - }, - { - "name" : "minecraft:ice_bomb", - "id" : 584 - }, - { - "name" : "minecraft:info_update", - "id" : 248 - }, - { - "name" : "minecraft:info_update2", - "id" : 249 - }, - { - "name" : "minecraft:ink_sac", - "id" : 411 - }, - { - "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" : 370 - }, - { - "name" : "minecraft:iron_helmet", - "id" : 343 - }, - { - "name" : "minecraft:iron_hoe", - "id" : 331 - }, - { - "name" : "minecraft:iron_horse_armor", - "id" : 521 - }, - { - "name" : "minecraft:iron_ingot", - "id" : 305 - }, - { - "name" : "minecraft:iron_leggings", - "id" : 345 - }, - { - "name" : "minecraft:iron_nugget", - "id" : 559 - }, - { - "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.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:nether_brick", - "id" : 112 - }, - { - "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" : 375 - }, - { - "name" : "minecraft:jungle_button", - "id" : -143 - }, - { - "name" : "minecraft:jungle_door", - "id" : 545 - }, - { - "name" : "minecraft:jungle_fence_gate", - "id" : 185 - }, - { - "name" : "minecraft:jungle_pressure_plate", - "id" : -153 - }, - { - "name" : "minecraft:jungle_sign", - "id" : 568 - }, - { - "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" : 380 - }, - { - "name" : "minecraft:ladder", - "id" : 65 - }, - { - "name" : "minecraft:lantern", - "id" : -208 - }, - { - "name" : "minecraft:lapis_block", - "id" : 22 - }, - { - "name" : "minecraft:lapis_lazuli", - "id" : 412 - }, - { - "name" : "minecraft:lapis_ore", - "id" : 21 - }, - { - "name" : "minecraft:lava", - "id" : 11 - }, - { - "name" : "minecraft:lava_bucket", - "id" : 363 - }, - { - "name" : "minecraft:lava_cauldron", - "id" : -210 - }, - { - "name" : "minecraft:lead", - "id" : 537 - }, - { - "name" : "minecraft:leather", - "id" : 379 - }, - { - "name" : "minecraft:leather_boots", - "id" : 338 - }, - { - "name" : "minecraft:leather_chestplate", - "id" : 336 - }, - { - "name" : "minecraft:leather_helmet", - "id" : 335 - }, - { - "name" : "minecraft:leather_horse_armor", - "id" : 520 - }, - { - "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_dye", - "id" : 405 - }, - { - "name" : "minecraft:light_blue_glazed_terracotta", - "id" : 223 - }, - { - "name" : "minecraft:light_gray_dye", - "id" : 400 - }, - { - "name" : "minecraft:light_weighted_pressure_plate", - "id" : 147 - }, - { - "name" : "minecraft:lime_dye", - "id" : 403 - }, - { - "name" : "minecraft:lime_glazed_terracotta", - "id" : 225 - }, - { - "name" : "minecraft:lingering_potion", - "id" : 552 - }, - { - "name" : "minecraft:lit_blast_furnace", - "id" : -214 - }, - { - "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" : 471 - }, - { - "name" : "minecraft:lodestone", - "id" : -222 - }, - { - "name" : "minecraft:lodestone_compass", - "id" : 590 - }, - { - "name" : "minecraft:log", - "id" : 17 - }, - { - "name" : "minecraft:log2", - "id" : 162 - }, - { - "name" : "minecraft:loom", - "id" : -204 - }, - { - "name" : "minecraft:magenta_dye", - "id" : 406 - }, - { - "name" : "minecraft:magenta_glazed_terracotta", - "id" : 222 - }, - { - "name" : "minecraft:magma", - "id" : 213 - }, - { - "name" : "minecraft:magma_cream", - "id" : 428 - }, - { - "name" : "minecraft:magma_cube_spawn_egg", - "id" : 453 - }, - { - "name" : "minecraft:medicine", - "id" : 588 - }, - { - "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" : 368 - }, - { - "name" : "minecraft:mob_spawner", - "id" : 52 - }, - { - "name" : "minecraft:mojang_banner_pattern", - "id" : 574 - }, - { - "name" : "minecraft:monster_egg", - "id" : 97 - }, - { - "name" : "minecraft:mooshroom_spawn_egg", - "id" : 438 - }, - { - "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" : 464 - }, - { - "name" : "minecraft:mushroom_stew", - "id" : 260 - }, - { - "name" : "minecraft:music_disc_11", - "id" : 534 - }, - { - "name" : "minecraft:music_disc_13", - "id" : 524 - }, - { - "name" : "minecraft:music_disc_blocks", - "id" : 526 - }, - { - "name" : "minecraft:music_disc_cat", - "id" : 525 - }, - { - "name" : "minecraft:music_disc_chirp", - "id" : 527 - }, - { - "name" : "minecraft:music_disc_far", - "id" : 528 - }, - { - "name" : "minecraft:music_disc_mall", - "id" : 529 - }, - { - "name" : "minecraft:music_disc_mellohi", - "id" : 530 - }, - { - "name" : "minecraft:music_disc_pigstep", - "id" : 608 - }, - { - "name" : "minecraft:music_disc_stal", - "id" : 531 - }, - { - "name" : "minecraft:music_disc_strad", - "id" : 532 - }, - { - "name" : "minecraft:music_disc_wait", - "id" : 535 - }, - { - "name" : "minecraft:music_disc_ward", - "id" : 533 - }, - { - "name" : "minecraft:mutton", - "id" : 540 - }, - { - "name" : "minecraft:mycelium", - "id" : 110 - }, - { - "name" : "minecraft:name_tag", - "id" : 538 - }, - { - "name" : "minecraft:nautilus_shell", - "id" : 560 - }, - { - "name" : "minecraft:netherbrick", - "id" : 513 - }, - { - "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" : 609 - }, - { - "name" : "minecraft:nether_star", - "id" : 508 - }, - { - "name" : "minecraft:nether_wart", - "id" : 294 - }, - { - "name" : "minecraft:nether_wart_block", - "id" : 214 - }, - { - "name" : "minecraft:netherite_axe", - "id" : 595 - }, - { - "name" : "minecraft:netherite_block", - "id" : -270 - }, - { - "name" : "minecraft:netherite_boots", - "id" : 600 - }, - { - "name" : "minecraft:netherite_chestplate", - "id" : 598 - }, - { - "name" : "minecraft:netherite_helmet", - "id" : 597 - }, - { - "name" : "minecraft:netherite_hoe", - "id" : 596 - }, - { - "name" : "minecraft:netherite_ingot", - "id" : 591 - }, - { - "name" : "minecraft:netherite_leggings", - "id" : 599 - }, - { - "name" : "minecraft:netherite_pickaxe", - "id" : 594 - }, - { - "name" : "minecraft:netherite_scrap", - "id" : 601 - }, - { - "name" : "minecraft:netherite_shovel", - "id" : 593 - }, - { - "name" : "minecraft:netherite_sword", - "id" : 592 - }, - { - "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" : 468 - }, - { - "name" : "minecraft:oak_boat", - "id" : 373 - }, - { - "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" : 449 - }, - { - "name" : "minecraft:orange_dye", - "id" : 407 - }, - { - "name" : "minecraft:orange_glazed_terracotta", - "id" : 221 - }, - { - "name" : "minecraft:packed_ice", - "id" : 174 - }, - { - "name" : "minecraft:painting", - "id" : 357 - }, - { - "name" : "minecraft:panda_spawn_egg", - "id" : 487 - }, - { - "name" : "minecraft:paper", - "id" : 384 - }, - { - "name" : "minecraft:parrot_spawn_egg", - "id" : 476 - }, - { - "name" : "minecraft:phantom_membrane", - "id" : 564 - }, - { - "name" : "minecraft:phantom_spawn_egg", - "id" : 484 - }, - { - "name" : "minecraft:pig_spawn_egg", - "id" : 435 - }, - { - "name" : "minecraft:piglin_banner_pattern", - "id" : 577 - }, - { - "name" : "minecraft:piglin_brute_spawn_egg", - "id" : 497 - }, - { - "name" : "minecraft:piglin_spawn_egg", - "id" : 495 - }, - { - "name" : "minecraft:pillager_spawn_egg", - "id" : 489 - }, - { - "name" : "minecraft:pink_dye", - "id" : 402 - }, - { - "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:poisonous_potato", - "id" : 282 - }, - { - "name" : "minecraft:polar_bear_spawn_egg", - "id" : 470 - }, - { - "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_diorite_stairs", - "id" : -173 - }, - { - "name" : "minecraft:polished_granite_stairs", - "id" : -172 - }, - { - "name" : "minecraft:popped_chorus_fruit", - "id" : 549 - }, - { - "name" : "minecraft:porkchop", - "id" : 262 - }, - { - "name" : "minecraft:portal", - "id" : 90 - }, - { - "name" : "minecraft:potato", - "id" : 280 - }, - { - "name" : "minecraft:potatoes", - "id" : 142 - }, - { - "name" : "minecraft:potion", - "id" : 424 - }, - { - "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" : 539 - }, - { - "name" : "minecraft:prismarine_shard", - "id" : 555 - }, - { - "name" : "minecraft:prismarine_stairs", - "id" : -2 - }, - { - "name" : "minecraft:pufferfish", - "id" : 267 - }, - { - "name" : "minecraft:pufferfish_bucket", - "id" : 367 - }, - { - "name" : "minecraft:pufferfish_spawn_egg", - "id" : 479 - }, - { - "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_dye", - "id" : 398 - }, - { - "name" : "minecraft:purple_glazed_terracotta", - "id" : 219 - }, - { - "name" : "minecraft:purpur_block", - "id" : 201 - }, - { - "name" : "minecraft:purpur_stairs", - "id" : 203 - }, - { - "name" : "minecraft:quartz", - "id" : 514 - }, - { - "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" : 518 - }, - { - "name" : "minecraft:rabbit_hide", - "id" : 519 - }, - { - "name" : "minecraft:rabbit_spawn_egg", - "id" : 457 - }, - { - "name" : "minecraft:rabbit_stew", - "id" : 290 - }, - { - "name" : "minecraft:rail", - "id" : 66 - }, - { - "name" : "minecraft:rapid_fertilizer", - "id" : 586 - }, - { - "name" : "minecraft:ravager_spawn_egg", - "id" : 491 - }, - { - "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_dye", - "id" : 394 - }, - { - "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" : 371 - }, - { - "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" : 417 - }, - { - "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" : 369 - }, - { - "name" : "minecraft:salmon", - "id" : 265 - }, - { - "name" : "minecraft:salmon_bucket", - "id" : 365 - }, - { - "name" : "minecraft:salmon_spawn_egg", - "id" : 480 - }, - { - "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:scute", - "id" : 562 - }, - { - "name" : "minecraft:sea_pickle", - "id" : -156 - }, - { - "name" : "minecraft:seagrass", - "id" : -130 - }, - { - "name" : "minecraft:sealantern", - "id" : 169 - }, - { - "name" : "minecraft:shears", - "id" : 419 - }, - { - "name" : "minecraft:sheep_spawn_egg", - "id" : 436 - }, - { - "name" : "minecraft:shield", - "id" : 355 - }, - { - "name" : "minecraft:shroomlight", - "id" : -230 - }, - { - "name" : "minecraft:shulker_box", - "id" : 218 - }, - { - "name" : "minecraft:shulker_shell", - "id" : 556 - }, - { - "name" : "minecraft:shulker_spawn_egg", - "id" : 467 - }, - { - "name" : "minecraft:silver_glazed_terracotta", - "id" : 228 - }, - { - "name" : "minecraft:silverfish_spawn_egg", - "id" : 441 - }, - { - "name" : "minecraft:skeleton_horse_spawn_egg", - "id" : 465 - }, - { - "name" : "minecraft:skeleton_spawn_egg", - "id" : 442 - }, - { - "name" : "minecraft:skull", - "id" : 506 - }, - { - "name" : "minecraft:skull_banner_pattern", - "id" : 573 - }, - { - "name" : "minecraft:slime", - "id" : 165 - }, - { - "name" : "minecraft:slime_ball", - "id" : 386 - }, - { - "name" : "minecraft:slime_spawn_egg", - "id" : 443 - }, - { - "name" : "minecraft:smithing_table", - "id" : -202 - }, - { - "name" : "minecraft:smoker", - "id" : -198 - }, - { - "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" : 372 - }, - { - "name" : "minecraft:soul_campfire", - "id" : 610 - }, - { - "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" : 589 - }, - { - "name" : "minecraft:spawn_egg", - "id" : 614 - }, - { - "name" : "minecraft:spider_eye", - "id" : 278 - }, - { - "name" : "minecraft:spider_spawn_egg", - "id" : 444 - }, - { - "name" : "minecraft:splash_potion", - "id" : 551 - }, - { - "name" : "minecraft:sponge", - "id" : 19 - }, - { - "name" : "minecraft:spruce_boat", - "id" : 376 - }, - { - "name" : "minecraft:spruce_button", - "id" : -144 - }, - { - "name" : "minecraft:spruce_door", - "id" : 543 - }, - { - "name" : "minecraft:spruce_fence_gate", - "id" : 183 - }, - { - "name" : "minecraft:spruce_pressure_plate", - "id" : -154 - }, - { - "name" : "minecraft:spruce_sign", - "id" : 566 - }, - { - "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:squid_spawn_egg", - "id" : 448 - }, - { - "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" : 460 - }, - { - "name" : "minecraft:strider_spawn_egg", - "id" : 493 - }, - { - "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" : 414 - }, - { - "name" : "minecraft:sugar_cane", - "id" : 383 - }, - { - "name" : "minecraft:suspicious_stew", - "id" : 579 - }, - { - "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:tnt", - "id" : 46 - }, - { - "name" : "minecraft:tnt_minecart", - "id" : 515 - }, - { - "name" : "minecraft:torch", - "id" : 50 - }, - { - "name" : "minecraft:totem_of_undying", - "id" : 558 - }, - { - "name" : "minecraft:trapdoor", - "id" : 96 - }, - { - "name" : "minecraft:trapped_chest", - "id" : 146 - }, - { - "name" : "minecraft:trident", - "id" : 536 - }, - { - "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" : 477 - }, - { - "name" : "minecraft:turtle_egg", - "id" : -159 - }, - { - "name" : "minecraft:turtle_helmet", - "id" : 563 - }, - { - "name" : "minecraft:turtle_spawn_egg", - "id" : 483 - }, - { - "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" : 474 - }, - { - "name" : "minecraft:villager_spawn_egg", - "id" : 447 - }, - { - "name" : "minecraft:vindicator_spawn_egg", - "id" : 472 - }, - { - "name" : "minecraft:vine", - "id" : 106 - }, - { - "name" : "minecraft:wall_banner", - "id" : 177 - }, - { - "name" : "minecraft:wall_sign", - "id" : 68 - }, - { - "name" : "minecraft:wandering_trader_spawn_egg", - "id" : 490 - }, - { - "name" : "minecraft:warped_button", - "id" : -261 - }, - { - "name" : "minecraft:warped_door", - "id" : 605 - }, - { - "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" : 606 - }, - { - "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" : 603 - }, - { - "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:web", - "id" : 30 - }, - { - "name" : "minecraft:weeping_vines", - "id" : -231 - }, - { - "name" : "minecraft:wheat", - "id" : 334 - }, - { - "name" : "minecraft:wheat_seeds", - "id" : 291 - }, - { - "name" : "minecraft:white_dye", - "id" : 408 - }, - { - "name" : "minecraft:white_glazed_terracotta", - "id" : 220 - }, - { - "name" : "minecraft:witch_spawn_egg", - "id" : 450 - }, - { - "name" : "minecraft:wither_rose", - "id" : -216 - }, - { - "name" : "minecraft:wither_skeleton_spawn_egg", - "id" : 462 - }, - { - "name" : "minecraft:wolf_spawn_egg", - "id" : 437 - }, - { - "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" : 500 - }, - { - "name" : "minecraft:written_book", - "id" : 501 - }, - { - "name" : "minecraft:yellow_dye", - "id" : 404 - }, - { - "name" : "minecraft:yellow_flower", - "id" : 37 - }, - { - "name" : "minecraft:yellow_glazed_terracotta", - "id" : 224 - }, - { - "name" : "minecraft:zoglin_spawn_egg", - "id" : 496 - }, - { - "name" : "minecraft:zombie_horse_spawn_egg", - "id" : 466 - }, - { - "name" : "minecraft:zombie_pigman_spawn_egg", - "id" : 446 - }, - { - "name" : "minecraft:zombie_spawn_egg", - "id" : 445 - }, - { - "name" : "minecraft:zombie_villager_spawn_egg", - "id" : 475 - } -] \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/skin/geometry.humanoid.customskull.json b/connector/src/main/resources/bedrock/skin/geometry.humanoid.customskull.json deleted file mode 100644 index 88cf65ad..00000000 --- a/connector/src/main/resources/bedrock/skin/geometry.humanoid.customskull.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "format_version": "1.10.0", - "geometry.humanoid.customskull": { - "texturewidth": 64, - "textureheight": 64, - "visible_bounds_width": 2, - "visible_bounds_height": 1, - "visible_bounds_offset": [0, 0, 0], - "bones": [ - { - "name": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [0, 0]} - ] - }, - { - "name": "hat", - "parent": "head", - "pivot": [0, 24, 0], - "cubes": [ - {"origin": [-4, 0, -4], "size": [8, 8, 8], "uv": [32, 0], "inflate": 0.5} - ] - } - ] - } -} \ No newline at end of file diff --git a/connector/src/main/resources/config.yml b/connector/src/main/resources/config.yml index 07b73173..931e0a8d 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -8,70 +8,46 @@ # -------------------------------- bedrock: - # The IP address that will listen for connections. - # There is no reason to change this unless you want to limit what IPs can connect to your server. + # The IP address that will listen for connections address: 0.0.0.0 # The port that will listen for connections port: 19132 - # Some hosting services change your Java port everytime you start the server and require the same port to be used for Bedrock. - # This option makes the Bedrock port the same as the Java port every time you start the server. - # This option is for the plugin version only. - clone-remote-port: false - # The MOTD that will be broadcasted to Minecraft: Bedrock Edition clients. This is irrelevant if "passthrough-motd" is set to true + # The MOTD that will be broadcasted to Minecraft: Bedrock Edition clients. Irrelevant if "passthrough-motd" is set to true motd1: "GeyserMC" motd2: "Another GeyserMC forced host." - # The Server Name that will be sent to Minecraft: Bedrock Edition clients. This is visible in both the pause menu and the settings menu. - server-name: "Geyser" remote: # The IP address of the remote (Java Edition) server - # If it is "auto", for standalone version the remote address will be set to 127.0.0.1, - # for plugin versions, Geyser will attempt to find the best address to connect to. - address: auto + address: 127.0.0.1 # The port of the remote (Java Edition) server - # For plugin versions, if address has been set to "auto", the port will also follow the server's listening port. port: 25565 # Authentication type. Can be offline, online, or floodgate (see https://github.com/GeyserMC/Geyser/wiki/Floodgate). auth-type: online - # Allow for password-based authentication methods through Geyser. Only useful in online mode. - # If this is false, users must authenticate to Microsoft using a code provided by Geyser on their desktop. - allow-password-authentication: true - # Whether to enable PROXY protocol or not while connecting to the server. - # This is useful only when: - # 1) Your server supports PROXY protocol (it probably doesn't) - # 2) You run Velocity or BungeeCord with the option enabled in the proxy's main config. - # IF YOU DON'T KNOW WHAT THIS IS, DON'T TOUCH IT! - use-proxy-protocol: false # Floodgate uses encryption to ensure use from authorised sources. # This should point to the public key generated by Floodgate (Bungee or CraftBukkit) # You can ignore this when not using Floodgate. floodgate-key-file: public-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. +## the Xbox/MCPE username is the key for the Java server auth-info +## this allows automatic configuration/login to the remote Java server +## if you are brave/stupid enough to put your Mojang account info into +## a config file #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 +# bluerkelp2: # MCPE/Xbox username +# email: not_really_my_email_address_mr_minecrafter53267@gmail.com # Mojang account email address # password: "this isn't really my password" -# microsoft-account: false +# +# herpderp40300499303040503030300500293858393589: +# email: herpderp@derpherp.com +# password: dooooo # 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. command-suggestions: true -# The following three options enable "ping passthrough" - the MOTD, player count and/or protocol name gets retrieved from the Java server. +# The following two options enable "ping passthrough" - the MOTD and/or player count gets retrieved from the Java server. # Relay the MOTD from the remote server to Bedrock players. passthrough-motd: false -# Relay the protocol name (e.g. BungeeCord [X.X], Paper 1.X) - only really useful when using a custom protocol name! -# This will also show up on sites like MCSrvStatus. -passthrough-protocol-name: false # Relay the player count and max players from the remote server to Bedrock players. passthrough-player-counts: false # Enable LEGACY ping passthrough. There is no need to enable this unless your MOTD or player count does not appear properly. @@ -98,33 +74,17 @@ allow-third-party-capes: true # MinecraftCapes allow-third-party-ears: false -# Allow a fake cooldown indicator to be sent. Bedrock players do not see a cooldown as they still use 1.8 combat -show-cooldown: true - -# Controls if coordinates are shown to players. -show-coordinates: true - -# The default locale if we dont have the one the client requested. Uncomment to not use the default system language. -# default-locale: en_us +# The default locale if we dont have the one the client requested +default-locale: en_us # Configures if chunk caching should be enabled or not. This keeps an individual -# record of each block the client loads in. This feature does allow for a few things -# such as more accurate movement that causes less problems with anticheat (meaning -# you're less likely to be banned) and allows block break animations to show up in -# creative mode (and other features). Although this increases RAM usage, it likely -# won't have much of an effect for the vast majority of people. However, if you're -# running out of RAM or are in a RAM-sensitive environment, you may want to disable -# this. When using the Spigot version of Geyser, support for features or -# implementations this allows is automatically enabled without the additional caching -# as Geyser has direct access to the server itself. -cache-chunks: true - -# Specify how many days images will be cached to disk to save downloading them from the internet. -# A value of 0 is disabled. (Default: 0) -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 +# record of each block the client loads in. While this feature does allow for a few +# things such as block break animations to show up in creative mode and among others, +# it is HIGHLY recommended you disable this on a production environment as it can eat +# up a lot of RAM. However, when using the Bukkit version of Geyser, support for features +# or implementations this allows is automatically enabled without the additional caching as +# Geyser has direct access to the server itself. +cache-chunks: false # Bedrock prevents building and displaying blocks above Y127 in the Nether - # enabling this config option works around that by changing the Nether dimension ID @@ -132,15 +92,6 @@ allow-custom-skulls: true # the end sky in the nether, but ultimately it's the only way for this feature to work. above-bedrock-nether-building: false -# Force clients to load all resource packs if there are any. -# If set to false, it allows the user to connect to the server even if they don't -# want to download the resource packs. -force-resource-packs: true - -# Allows Xbox achievements to be unlocked. -# THIS DISABLES ALL COMMANDS FROM SUCCESSFULLY RUNNING FOR BEDROCK IN-GAME, as otherwise Bedrock thinks you are cheating. -xbox-achievements-enabled: false - # bStats is a stat tracker that is entirely anonymous and tracks only basic information # about Geyser, such as how many people are online, how many servers are using Geyser, # what OS is being used, etc. You can learn more about bStats here: https://bstats.org/. @@ -151,24 +102,5 @@ metrics: # UUID of server, don't change! uuid: generateduuid -# ADVANCED OPTIONS - DO NOT TOUCH UNLESS YOU KNOW WHAT YOU ARE DOING! - -# Geyser updates the Scoreboard after every Scoreboard packet, but when Geyser tries to handle -# a lot of scoreboard packets per second can cause serious lag. -# This option allows you to specify after how many Scoreboard packets per seconds -# the Scoreboard updates will be limited to four updates per second. -scoreboard-packet-threshold: 20 - -# Allow connections from ProxyPass and Waterdog. -# See https://www.spigotmc.org/wiki/firewall-guide/ for assistance - use UDP instead of TCP. -enable-proxy-connections: false - -# The internet supports a maximum MTU of 1492 but could cause issues with packet fragmentation. -# 1400 is the default. -# mtu: 1400 - -# Whether to use direct server methods to retrieve information such as block states. -# Turning this off for Spigot will stop NMS from being used but will have a performance impact. -use-adapters: true - -config-version: 4 +# DO NOT TOUCH! +config-version: 3 diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages deleted file mode 160000 index 8141bc6a..00000000 --- a/connector/src/main/resources/languages +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 8141bc6aed878a95ed9ee3ca83a2381f9906c4b4 diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index dd0347bd..a67cc940 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit dd0347bd51e00e42ea58faaf68b562526c4d2817 +Subproject commit a67cc940c0d47874c833ffeb58f38e33eabfcc33 diff --git a/connector/src/test/java/org/geysermc/connector/network/translators/chat/MessageTranslatorTest.java b/connector/src/test/java/org/geysermc/connector/network/translators/chat/MessageTranslatorTest.java deleted file mode 100644 index bbad2394..00000000 --- a/connector/src/test/java/org/geysermc/connector/network/translators/chat/MessageTranslatorTest.java +++ /dev/null @@ -1,77 +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.connector.network.translators.chat; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import java.util.HashMap; -import java.util.Map; - -public class MessageTranslatorTest { - - private Map messages = new HashMap<>(); - - @Before - public void setUp() throws Exception { - messages.put("{\"text\":\"\",\"extra\":[{\"text\":\"DoctorMad9952 joined the game\",\"color\":\"yellow\"}]}", - "§r§eDoctorMad9952 joined the game"); - - messages.put("{\"text\":\"\",\"extra\":[\"Plugins (3): \",{\"text\":\"WorldEdit\",\"color\":\"green\"},{\"text\":\", \",\"color\":\"white\"},{\"text\":\"ViaVersion\",\"color\":\"green\"},{\"text\":\", \",\"color\":\"white\"},{\"text\":\"Geyser-Spigot\",\"color\":\"green\"}]}", - "Plugins (3): §r§aWorldEdit§r§f, §r§aViaVersion§r§f, §r§aGeyser-Spigot"); - - // RGB downgrade test - messages.put("{\"extra\":[{\"text\":\" \"},{\"color\":\"gold\",\"text\":\"The \"},{\"color\":\"#E14248\",\"obfuscated\":true,\"text\":\"||\"},{\"color\":\"#3AA9FF\",\"bold\":true,\"text\":\"CubeCraft\"},{\"color\":\"#E14248\",\"obfuscated\":true,\"text\":\"||\"},{\"color\":\"gold\",\"text\":\" Network \"},{\"color\":\"green\",\"text\":\"[1.8/1.9+]\\n \"},{\"color\":\"#f5e342\",\"text\":\"✦ \"},{\"color\":\"#b042f5\",\"bold\":true,\"text\":\"N\"},{\"color\":\"#c142f5\",\"bold\":true,\"text\":\"E\"},{\"color\":\"#d342f5\",\"bold\":true,\"text\":\"W\"},{\"color\":\"#e442f5\",\"bold\":true,\"text\":\":\"},{\"color\":\"#f542f5\",\"bold\":true,\"text\":\" \"},{\"color\":\"#bcf542\",\"bold\":true,\"text\":\"A\"},{\"color\":\"#acee3f\",\"bold\":true,\"text\":\"M\"},{\"color\":\"#9ce73c\",\"bold\":true,\"text\":\"O\"},{\"color\":\"#8ce039\",\"bold\":true,\"text\":\"N\"},{\"color\":\"#7cd936\",\"bold\":true,\"text\":\"G\"},{\"color\":\"#6cd233\",\"bold\":true,\"text\":\" \"},{\"color\":\"#5ccb30\",\"bold\":true,\"text\":\"S\"},{\"color\":\"#4cc42d\",\"bold\":true,\"text\":\"L\"},{\"color\":\"#3cbd2a\",\"bold\":true,\"text\":\"I\"},{\"color\":\"#2cb627\",\"bold\":true,\"text\":\"M\"},{\"color\":\"#1caf24\",\"bold\":true,\"text\":\"E\"},{\"color\":\"#0ca821\",\"bold\":true,\"text\":\"S\"},{\"color\":\"#f5e342\",\"text\":\" \"},{\"color\":\"#6d7c87\",\"text\":\"(kinda sus) \"},{\"color\":\"#f5e342\",\"text\":\"✦\"}],\"text\":\"\"}", - " §r§6The §r§c§k||§r§3§lCubeCraft§r§c§k||§r§6 Network §r§a[1.8/1.9+]\n" + - " §r§e✦ §r§d§lN§r§d§lE§r§d§lW§r§d§l:§r§d§l §r§e§lA§r§e§lM§r§a§lO§r§a§lN§r§a§lG§r§a§l §r§a§lS§r§a§lL§r§2§lI§r§2§lM§r§2§lE§r§2§lS§r§e §r§8(kinda sus) §r§e✦"); - - // Color code format resetting - messages.put("{\"text\":\"\",\"extra\":[{\"text\":\"\",\"extra\":[{\"text\":\"[\",\"color\":\"gray\"},{\"text\":\"H\",\"color\":\"yellow\"},{\"text\":\"]\",\"color\":\"gray\"},{\"text\":\" \",\"color\":\"white\"},{\"text\":\"GUEST\",\"color\":\"#b7b7b7\",\"bold\":true}]},{\"text\":\"\",\"extra\":[{\"text\":\" \",\"bold\":true},{\"text\":\"»\",\"color\":\"blue\"},{\"text\":\" \",\"color\":\"gray\"}]},{\"text\":\"\",\"extra\":[{\"text\":\"rtm516\",\"color\":\"white\"},{\"text\":\": \",\"color\":\"gray\"},{\"text\":\"\",\"color\":\"white\"}]},{\"text\":\"\",\"extra\":[{\"text\":\"This is an amazing bedrock test message\",\"color\":\"white\"}]}]}\n", - "§r§7[§r§eH§r§7]§r§f §r§7§lGUEST§r§l §r§9»§r§7 §r§frtm516§r§7: §r§fThis is an amazing bedrock test message"); - - // Test translation and positional arguments - // Disabled due to not having an GeyserConnector instance, hence it fails - //messages.put("{\"translate\":\"death.attack.player\",\"with\":[{\"text\":\"rtm516\",\"insertion\":\"rtm516\"},{\"text\":\"*invincible_rt\",\"insertion\":\"*invincible_rt\"}]}", - // "rtm516 was slain by *invincible_rt"); - } - - @Test - public void convertMessage() { - for (Map.Entry entry : messages.entrySet()) { - String bedrockMessage = MessageTranslator.convertMessage(entry.getKey(), "en_US"); - Assert.assertEquals("Translation of messages is incorrect", entry.getValue(), bedrockMessage); - } - } - - @Test - public void convertMessageLenient() { - Assert.assertEquals("All newline message is not handled properly", "\n\n\n\n", MessageTranslator.convertMessageLenient("\n\n\n\n")); - Assert.assertEquals("Empty message is not handled properly", "", MessageTranslator.convertMessageLenient("")); - Assert.assertEquals("Reset before message is not handled properly", "§r§eGame Selector", MessageTranslator.convertMessageLenient("§r§eGame Selector")); - Assert.assertEquals("Unimplemented formatting chars not stripped", "Bold Underline", MessageTranslator.convertMessageLenient("§m§nBold Underline")); - } -} diff --git a/licenseheader.txt b/licenseheader.txt index 8ef205a3..c22c426c 100644 --- a/licenseheader.txt +++ b/licenseheader.txt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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 011b320f..3e119eb1 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.geysermc geyser-parent - 1.2.0-SNAPSHOT + parent pom Geyser Allows for players from Minecraft Bedrock Edition to join Minecraft Java Edition servers. @@ -42,8 +42,8 @@ https://jitpack.io - opencollab-release-repo - https://repo.opencollab.dev/maven-releases/ + nukkitx-release-repo + https://repo.nukkitx.com/maven-releases/ true @@ -52,8 +52,8 @@ - opencollab-snapshot-repo - https://repo.opencollab.dev/maven-snapshots/ + nukkitx-snapshot-repo + https://repo.nukkitx.com/maven-snapshots/ false @@ -65,12 +65,21 @@ viaversion-repo https://repo.viaversion.com - - sonatype - https://oss.sonatype.org/content/repositories/snapshots/ - + + + releases + nukkitx-releases + https://repo.nukkitx.com/maven-releases + + + snapshots + nukkitx-snapshots + https://repo.nukkitx.com/maven-snapshots + + + org.projectlombok