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..326a1ebd 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..9cb0726c 100644 --- a/.github/workflows/pullrequest.yml +++ b/.github/workflows/pullrequest.yml @@ -22,7 +22,7 @@ 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 if: success() diff --git a/.gitignore b/.gitignore index 85f8a6e9..c4c878af 100644 --- a/.gitignore +++ b/.gitignore @@ -241,6 +241,4 @@ config.yml logs/ public-key.pem locales/ -/cache/ -/packs/ -/dump.json \ No newline at end of file +cache/ \ No newline at end of file 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..ead5b3b7 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![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/) @@ -18,7 +18,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.16.x and Minecraft Java v1.16.2. ## Setting Up Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set up Geyser. @@ -31,29 +31,20 @@ Take a look [here](https://github.com/GeyserMC/Geyser/wiki#Setup) for how to set - 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 +- Test Server: test.geysermc.org port 25565 for Java and 19132 for Bedrock ## 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 (as a proper GUI) + - [ ] Beacon + - [ ] Cartography Table + - [ ] Stonecutter + - [ ] Command Block + - [ ] Structure Block + - [ ] Horse Inventory + - [ ] Loom + - [ ] Smithing Table +- Some Entity Flags ## Compiling 1. Clone the repo to your computer diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 54e0d56e..8497b968 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -6,15 +6,15 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.1.0 + ../ bootstrap-bungeecord - org.geysermc connector - 1.2.0-SNAPSHOT + 1.1.0 compile @@ -61,34 +61,14 @@ 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.reflections.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..d9b86a2e 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 @@ -29,22 +29,27 @@ 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 java.nio.file.Path; +import java.nio.file.Paths; @Getter @JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserBungeeConfiguration extends GeyserJacksonConfiguration { +public class GeyserBungeeConfiguration extends GeyserJacksonConfiguration { + @JsonIgnore - private Path floodgateKeyPath; + private Path floodgateKey; - public void loadFloodgate(GeyserBungeePlugin plugin) { + public void loadFloodgate(GeyserBungeePlugin plugin, Configuration configuration) { 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(plugin.getDataFolder().toString(), configuration.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 Path getFloodgateKeyFile() { + return floodgateKey; } } 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 index 12429d75..ce2b1fc3 100644 --- a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeDumpInfo.java +++ b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeeDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/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..3da1d093 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java b/bootstrap/bungeecord/src/main/java/org/geysermc/platform/bungeecord/GeyserBungeePingPassthrough.java index 6eea2591..15c8fa9e 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -47,12 +47,14 @@ 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); })); @@ -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..e80207d3 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,10 +27,13 @@ package org.geysermc.platform.bungeecord; import net.md_5.bungee.api.config.ListenerInfo; import net.md_5.bungee.api.plugin.Plugin; -import org.geysermc.common.PlatformType; +import net.md_5.bungee.config.Configuration; +import net.md_5.bungee.config.ConfigurationProvider; +import net.md_5.bungee.config.YamlConfiguration; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; @@ -61,11 +64,13 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { if (!getDataFolder().exists()) getDataFolder().mkdir(); + Configuration configuration = null; 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); + configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(new File(getDataFolder(), "config.yml")); } catch (IOException ex) { getLogger().log(Level.WARNING, LanguageUtils.getLocaleStringLog("geyser.config.failed"), ex); ex.printStackTrace(); @@ -103,7 +108,7 @@ public class GeyserBungeePlugin extends Plugin implements GeyserBootstrap { geyserConfig.getRemote().setAuthType("floodgate"); } - geyserConfig.loadFloodgate(this); + geyserConfig.loadFloodgate(this, configuration); this.connector = GeyserConnector.start(PlatformType.BUNGEECORD, this); 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..3b051c5c 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,10 +27,13 @@ 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.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; import java.util.ArrayList; @@ -38,7 +41,7 @@ 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 +54,27 @@ 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()); + String message = ""; + if (sender instanceof GeyserSession) { + message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode()); + } else { + message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail"); + } - commandSender.sendMessage(ChatColor.RED + message); + sender.sendMessage(TextComponent.fromLegacyText(ChatColor.RED + message)); 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..d9bac67d 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.1.0 pom - spigot-public diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 93eebc3d..422b2769 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -6,34 +6,29 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.1.0 + ../ bootstrap-spigot - org.geysermc connector - 1.2.0-SNAPSHOT + 1.1.0 compile org.spigotmc spigot-api - 1.15.2-R0.1-SNAPSHOT + 1.14-R0.1-SNAPSHOT provided us.myles viaversion - 3.2.0 + 3.1.0 provided - - org.geysermc.adapters - spigot-all - 1.0-SNAPSHOT - ${outputName}-Spigot @@ -81,25 +76,9 @@ org.geysermc.platform.spigot.shaded.jackson - org.reflections + org.reflections.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 - 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 index 2dbdbf83..380f7037 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotConfiguration.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ package org.geysermc.platform.spigot; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; @@ -34,19 +35,26 @@ import org.geysermc.connector.FloodgateKeyLoader; import org.geysermc.connector.configuration.GeyserJacksonConfiguration; import java.nio.file.Path; +import java.nio.file.Paths; @Getter @JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserSpigotConfiguration extends GeyserJacksonConfiguration { +public class GeyserSpigotConfiguration extends GeyserJacksonConfiguration { + + @JsonProperty("floodgate-key-file") + private String floodgateKeyFile; + @JsonIgnore - private Path floodgateKeyPath; + private Path floodgateKey; 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; + floodgateKey = FloodgateKeyLoader.getKey(plugin.getGeyserLogger(), this, Paths.get(plugin.getDataFolder().toString(), plugin.getConfig().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 Path getFloodgateKeyFile() { + return floodgateKey; } @Override 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 index 03fa0850..71134b6b 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotDumpInfo.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java index f760079f..252d6bbe 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 @@ package org.geysermc.platform.spigot; import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.Setter; + import org.geysermc.connector.GeyserLogger; import java.util.logging.Level; @@ -35,9 +34,9 @@ import java.util.logging.Logger; @AllArgsConstructor public class GeyserSpigotLogger implements GeyserLogger { - private final Logger logger; - @Getter @Setter - private boolean debug; + + 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/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java index 3e410f60..49c0339c 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java index 20bfecb6..7196f429 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.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; @@ -45,9 +44,9 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough { private final GeyserSpigotLogger logger; @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + public GeyserPingInfo getPingInformation() { try { - ServerListPingEvent event = new GeyserPingEvent(inetSocketAddress.getAddress(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); + ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers()); Bukkit.getPluginManager().callEvent(event); GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()), 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 index b85aa313..d51cf21a 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/GeyserSpigotPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 @@ 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.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.network.translators.world.WorldManager; @@ -42,29 +40,23 @@ 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 org.geysermc.platform.spigot.world.GeyserSpigotWorldManager; 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 GeyserSpigotBlockPlaceListener blockPlaceListener; private GeyserSpigotWorldManager geyserWorldManager; private GeyserConnector connector; @@ -129,68 +121,13 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { 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."); + geyserLogger.debug("Legacy version of Minecraft (1.12.2 or older) detected."); - 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); + this.geyserWorldManager = new GeyserSpigotWorldManager(isLegacy, isViaVersion); + this.blockPlaceListener = new GeyserSpigotBlockPlaceListener(connector, isLegacy, isViaVersion); Bukkit.getServer().getPluginManager().registerEvents(blockPlaceListener, this); @@ -199,9 +136,8 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { @Override public void onDisable() { - if (connector != null) { + if (connector != null) connector.shutdown(); - } } @Override @@ -234,11 +170,6 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { 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); @@ -266,43 +197,15 @@ public class GeyserSpigotPlugin extends JavaPlugin implements GeyserBootstrap { String t = stringArray[index].replaceAll("\\D", ""); try { temp[index] = Integer.parseInt(t); - } catch (NumberFormatException ex) { + } 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; + @Override + public BootstrapDumpInfo getDumpInfo() { + return new GeyserSpigotDumpInfo(); } } diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java index 1db86856..38187275 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 +32,7 @@ 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.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; import java.util.ArrayList; @@ -41,24 +42,28 @@ import java.util.List; @AllArgsConstructor public class GeyserSpigotCommandExecutor 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());; + String message = ""; + if (sender instanceof GeyserSession) { + message = LanguageUtils.getPlayerLocaleString("geyser.bootstrap.command.permission_fail", ((GeyserSession) sender).getClientData().getLanguageCode()); + } else { + message = LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail"); + } - commandSender.sendMessage(ChatColor.RED + message); + sender.sendMessage(ChatColor.RED + message); 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 SpigotCommandSender(sender), args); return true; } } else { - getCommand("help").execute(new SpigotCommandSender(sender), new String[0]); + getCommand("help").execute(new SpigotCommandSender(sender), args); return true; } return true; @@ -67,7 +72,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/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandManager.java index c0c239b0..2fbec156 100644 --- a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandManager.java +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/GeyserSpigotCommandManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/SpigotCommandSender.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/command/SpigotCommandSender.java index c1c2b2c7..55475a30 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,15 @@ package org.geysermc.platform.spigot.command; +import lombok.AllArgsConstructor; + 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; +@AllArgsConstructor 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); - } + private org.bukkit.command.CommandSender handle; @Override public String getName() { @@ -67,49 +49,4 @@ public class SpigotCommandSender implements CommandSender { 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 index 56fa7581..cb59e202 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -36,13 +36,13 @@ 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; + private final boolean isLegacy; + private final boolean isViaVersion; @EventHandler public void place(final BlockPlaceEvent event) { @@ -52,13 +52,14 @@ public class GeyserSpigotBlockPlaceListener implements Listener { 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()))); + String javaBlockId; + if (isLegacy) { + javaBlockId = BlockTranslator.getJavaIdBlockMap().inverse().get(GeyserSpigotWorldManager.getLegacyBlock(session, + event.getBlockPlaced().getX(), event.getBlockPlaced().getY(), event.getBlockPlaced().getZ(), isViaVersion)); } else { - String javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); - placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, BlockTranslator.JAVA_AIR_ID))); + javaBlockId = event.getBlockPlaced().getBlockData().getAsString(); } + placeBlockSoundPacket.setExtraData(BlockTranslator.getBedrockBlockId(BlockTranslator.getJavaIdBlockMap().getOrDefault(javaBlockId, 0))); placeBlockSoundPacket.setIdentifier(":"); session.sendUpstreamPacket(placeBlockSoundPacket); session.setLastBlockPlacePosition(null); diff --git a/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java new file mode 100644 index 00000000..4873a175 --- /dev/null +++ b/bootstrap/spigot/src/main/java/org/geysermc/platform/spigot/world/GeyserSpigotWorldManager.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to 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 lombok.AllArgsConstructor; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +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.GameRule; +import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13; +import us.myles.ViaVersion.protocols.protocol1_16_2to1_16_1.data.MappingData; + +@AllArgsConstructor +public class GeyserSpigotWorldManager extends GeyserWorldManager { + + 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 int getBlockAt(GeyserSession session, int x, int y, int z) { + if (session.getPlayerEntity() == null) { + return BlockTranslator.AIR; + } + if (Bukkit.getPlayer(session.getPlayerEntity().getUsername()) == null) { + return BlockTranslator.AIR; + } + if (isLegacy) { + return getLegacyBlock(session, x, y, z, isViaVersion); + } + //TODO possibly: detect server version for all versions and use ViaVersion for block state mappings like below + return BlockTranslator.getJavaIdBlockMap().getOrDefault(Bukkit.getPlayer(session.getPlayerEntity().getUsername()).getWorld().getBlockAt(x, y, z).getBlockData().getAsString(), 0); + } + + @SuppressWarnings("deprecation") + public static int 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 -> 1.16 -> 1.16.2 + 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); + int fifteenBlockId = us.myles.ViaVersion.protocols.protocol1_15to1_14_4.data.MappingData.blockStateMappings.getNewId(fourteenBlockId); + int sixteenBlockId = us.myles.ViaVersion.protocols.protocol1_16to1_15_2.data.MappingData.blockStateMappings.getNewId(fifteenBlockId); + return MappingData.blockStateMappings.getNewId(sixteenBlockId); + } else { + return BlockTranslator.AIR; + } + } + + @Override + 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); + } +} 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..f3c89808 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -6,15 +6,15 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.1.0 + ../ bootstrap-sponge - org.geysermc connector - 1.2.0-SNAPSHOT + 1.1.0 compile @@ -70,25 +70,9 @@ org.geysermc.platform.sponge.shaded.fastutil - org.reflections + org.reflections.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..ba416110 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,268 @@ package org.geysermc.platform.sponge; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; +import lombok.AllArgsConstructor; +import ninja.leaping.configurate.ConfigurationNode; +import org.geysermc.connector.configuration.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; + + /** + * If the config was originally 'auto' before the values changed + */ + private boolean autoconfiguredRemote = false; + + 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 void setAutoconfiguredRemote(boolean autoconfiguredRemote) { + this.autoconfiguredRemote = autoconfiguredRemote; + } -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 isPassthroughProtocolName() { + return node.getNode("passthrough-protocol-name").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 boolean isShowCooldown() { + return node.getNode("show-cooldown").getBoolean(true); + } + + @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 int getCacheImages() { + return node.getNode("cache-skins").getInt(0); + } + + @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 boolean isCloneRemotePort() { + return node.getNode("clone-remote-port").getBoolean(false); + } + + @Override + public String getMotd1() { + return node.getNode("motd1").getString("GeyserMC"); + } + + @Override + public String getMotd2() { + return node.getNode("motd2").getString("GeyserMC"); + } + + @Override + public String getServerName() { + return node.getNode("server-name").getString("Geyser"); + } + } + + @AllArgsConstructor + public class SpongeRemoteConfiguration implements IRemoteConfiguration { + + private ConfigurationNode node; + + @Override + public String getAddress() { + return node.getNode("address").getString("127.0.0.1"); + } + + @Override + public void setAddress(String address) { + node.getNode("address").setValue(address); + } + + @Override + public int getPort() { + return node.getNode("port").getInt(25565); + } + + @Override + public void setPort(int port) { + node.getNode("port").setValue(port); + } + + @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 boolean isEnableProxyConnections() { + return node.getNode("enable-proxy-connections").getBoolean(false); + } + + @Override + public int getMtu() { + return node.getNode("mtu").getInt(1400); + } + + @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 index d36ba311..0d292b37 100644 --- a/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeDumpInfo.java +++ b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongeDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..5b28fea2 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/GeyserSpongePingPassthrough.java b/bootstrap/sponge/src/main/java/org/geysermc/platform/sponge/GeyserSpongePingPassthrough.java index 8d63fca6..251b9703 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,29 +38,31 @@ 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); } @@ -74,7 +76,7 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { 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)) @@ -85,15 +87,11 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough { @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..0f1b7253 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,10 +26,13 @@ package org.geysermc.platform.sponge; import com.google.inject.Inject; -import org.geysermc.common.PlatformType; +import ninja.leaping.configurate.ConfigurationNode; +import ninja.leaping.configurate.loader.ConfigurationLoader; +import ninja.leaping.configurate.yaml.YAMLConfigurationLoader; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; import org.geysermc.connector.command.CommandManager; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; @@ -82,14 +85,20 @@ public class GeyserSpongePlugin implements GeyserBootstrap { 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")); 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(); @@ -97,12 +106,13 @@ public class GeyserSpongePlugin implements GeyserBootstrap { // 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()); + serverPort.setValue(javaAddr.getPort()); } } + ConfigurationNode bedrockPort = config.getNode("bedrock").getNode("port"); if (geyserConfig.getBedrock().isCloneRemotePort()){ - geyserConfig.getBedrock().setPort(geyserConfig.getRemote().getPort()); + bedrockPort.setValue(serverPort.getValue()); } this.geyserLogger = new GeyserSpongeLogger(logger, geyserConfig.isDebugMode()); 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..d37321ff 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 @@ -59,10 +59,10 @@ public class GeyserSpongeCommandExecutor implements CommandCallable { source.sendMessage(Text.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); 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 +70,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..07458f73 100644 --- a/bootstrap/standalone/pom.xml +++ b/bootstrap/standalone/pom.xml @@ -6,15 +6,15 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.1.0 + ../ bootstrap-standalone - org.geysermc connector - 1.2.0-SNAPSHOT + 1.1.0 compile 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..123a9a60 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,23 +25,17 @@ 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.common.PlatformType; 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.ping.IGeyserPingPassthrough; @@ -56,8 +50,7 @@ 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 { @@ -74,9 +67,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { 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(); @@ -84,8 +74,6 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { 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 @@ -103,11 +91,11 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { case "--config": case "-c": if (i >= args.length - 1) { - System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_not_specified"), "-c")); + System.err.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.confignotspecified"), "-c")); return; } configFilenameOpt = args[i+1]; i++; - System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.config_specified"), configFilenameOpt)); + System.out.println(MessageFormat.format(LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.configspecified"), configFilenameOpt)); break; case "--help": case "-h": @@ -118,43 +106,8 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { 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)); + String badArgMsg = LanguageUtils.getLocaleStringLog("geyser.bootstrap.args.unrecognised"); + System.err.println(MessageFormat.format(badArgMsg, arg)); return; } } @@ -195,21 +148,13 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { try { File configFile = FileUtils.fileOrCopiedFromResource(new File(configFilename), "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; - } + System.exit(0); } GeyserConfiguration.checkGeyserConfiguration(geyserConfig, geyserLogger); @@ -278,99 +223,4 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { 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..29e18d08 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,6 +26,7 @@ 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; @@ -34,9 +35,13 @@ import java.nio.file.Paths; @Getter @JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration { +public class GeyserStandaloneConfiguration extends GeyserJacksonConfiguration { + + @JsonProperty("floodgate-key-file") + private String floodgateKeyFile; + @Override - public Path getFloodgateKeyPath() { - return Paths.get(getFloodgateKeyFile()); + public Path getFloodgateKeyFile() { + return Paths.get(floodgateKeyFile); } } 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 index 2577ce03..5210c519 100644 --- a/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneDumpInfo.java +++ b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/GeyserStandaloneLogger.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneLogger.java index 64e5b5e8..0d9ced95 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 @@ 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.connector.GeyserConnector; -import org.geysermc.connector.GeyserLogger; -import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.common.ChatColor; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.command.CommandSender; @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 @@ -97,6 +99,10 @@ public class GeyserStandaloneLogger extends SimpleTerminalConsole implements Gey Configurator.setLevel(log.getName(), debug ? Level.DEBUG : Level.INFO); } + /** + * Used for setting debug mode in GUI mode + * @return if debug is enabled + */ public boolean isDebug() { return log.isDebugEnabled(); } 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..1619beb6 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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 index eb64a969..898b9474 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/ColorPane.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/ColorPane.java index 10309395..bab4ea99 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/GeyserStandaloneGUI.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/gui/GeyserStandaloneGUI.java index fb6a46f9..50deeb1b 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -261,30 +261,14 @@ public class GeyserStandaloneGUI { 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())) { + if ("offhand".equals(command.getValue().getName()) || 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()); + JMenuItem commandButton = 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); - } - } + commandButton.addActionListener(e -> command.getValue().execute(geyserStandaloneLogger, new String[]{ })); commandsMenu.add(commandButton); } @@ -307,7 +291,7 @@ public class GeyserStandaloneGUI { playerTableModel.getDataVector().removeAllElements(); for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) { - Vector row = new Vector<>(); + Vector row = new Vector(); row.add(player.getSocketAddress().getHostName()); row.add(player.getPlayerEntity().getUsername()); 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 index ebcc8f82..82c38e25 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index 5c0824de..b08e5cbc 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -6,21 +6,21 @@ org.geysermc bootstrap-parent - 1.2.0-SNAPSHOT + 1.1.0 + ../ bootstrap-velocity - org.geysermc connector - 1.2.0-SNAPSHOT + 1.1.0 compile com.velocitypowered velocity-api - 1.1.0 + 1.0.0-SNAPSHOT provided @@ -57,34 +57,14 @@ - - com.fasterxml.jackson - org.geysermc.platform.velocity.shaded.jackson - it.unimi.dsi.fastutil org.geysermc.platform.velocity.shaded.fastutil - org.reflections + org.reflections.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 +73,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..07580443 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 @@ -27,6 +27,7 @@ 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; @@ -36,15 +37,25 @@ import org.geysermc.connector.configuration.GeyserJacksonConfiguration; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; @Getter @JsonIgnoreProperties(ignoreUnknown = true) -public final class GeyserVelocityConfiguration extends GeyserJacksonConfiguration { +public class GeyserVelocityConfiguration extends GeyserJacksonConfiguration { + + @JsonProperty("floodgate-key-file") + private String floodgateKeyFile; + @JsonIgnore - private Path floodgateKeyPath; + private Path floodgateKey; + + @Override + public Path getFloodgateKeyFile() { + return 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/"))); } } 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 index 261e8fef..f44086c5 100644 --- a/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityDumpInfo.java +++ b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..cc6c93e8 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/GeyserVelocityPingPassthrough.java b/bootstrap/velocity/src/main/java/org/geysermc/platform/velocity/GeyserVelocityPingPassthrough.java index bab0e350..ff8376e4 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -43,13 +43,15 @@ 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) { @@ -72,15 +74,11 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough { 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..291d7a00 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 @@ -33,9 +33,9 @@ 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.GeyserConnector; import org.geysermc.connector.bootstrap.GeyserBootstrap; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.dump.BootstrapDumpInfo; import org.geysermc.connector.ping.GeyserLegacyPingPassthrough; @@ -121,7 +121,7 @@ public class GeyserVelocityPlugin implements GeyserBootstrap { 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 { 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..fa3aaa3c 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,39 @@ 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 net.kyori.text.TextComponent; + import org.geysermc.connector.common.ChatColor; +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 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())) { + // Not ideal to use log here but we dont get a session + source.sendMessage(TextComponent.of(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.bootstrap.command.permission_fail"))); 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..85dde12c 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -6,10 +6,11 @@ org.geysermc geyser-parent - 1.2.0-SNAPSHOT + parent + ../ common - + 1.1.0 com.google.code.gson 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..72579f7a 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 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..f972d590 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 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..9775ce9f 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java +++ b/common/src/main/java/org/geysermc/floodgate/util/BedrockData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/common/src/main/java/org/geysermc/floodgate/util/DeviceOS.java b/common/src/main/java/org/geysermc/floodgate/util/DeviceOS.java index 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..105309f9 100644 --- a/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java +++ b/common/src/main/java/org/geysermc/floodgate/util/EncryptionUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/pom.xml b/connector/pom.xml index a7001be0..a3748044 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -6,15 +6,16 @@ org.geysermc geyser-parent - 1.2.0-SNAPSHOT + parent + ../ connector - + 1.1.0 org.geysermc common - 1.2.0-SNAPSHOT + 1.1.0 compile @@ -30,28 +31,17 @@ compile - com.github.CloudburstMC.Protocol - bedrock-v422 - d41b84e86c + com.nukkitx.protocol + bedrock-v409 + 2.6.0-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 @@ -119,32 +109,12 @@ compile - com.github.steveice10 - mcprotocollib - 26201a4 + com.github.GeyserMC + MCProtocolLib + f37c98dc70 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 +126,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 + 4.0.0-SNAPSHOT compile net.kyori adventure-text-serializer-gson - 4.3.0 + 4.0.0-SNAPSHOT compile net.kyori adventure-text-serializer-legacy - 4.3.0 + 4.0.0-SNAPSHOT compile - - net.kyori - adventure-text-serializer-gson-legacy-impl - 4.3.0 - compile - - - junit - junit - 4.13.1 - test - - - com.github.GeyserMC - MCAuthLib - 0e48a094f2 - @@ -263,12 +205,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 +224,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..a30a5f4d 100644 --- a/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java +++ b/connector/src/main/java/org/geysermc/connector/FloodgateKeyLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 +25,17 @@ package org.geysermc.connector; -import org.geysermc.connector.configuration.GeyserJacksonConfiguration; import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.configuration.GeyserConfiguration; 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")); floodgateKey = autoKey; diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index d61500e0..ec332ed6 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,17 +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.BedrockServer; import lombok.Getter; import lombok.Setter; -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.common.PlatformType; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.metrics.Metrics; import org.geysermc.connector.network.ConnectorServerEventHandler; @@ -44,7 +43,6 @@ 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; @@ -55,11 +53,9 @@ 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.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.LocaleUtils; -import org.geysermc.connector.utils.ResourcePack; import javax.naming.directory.Attribute; import javax.naming.directory.InitialDirContext; @@ -67,7 +63,8 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.text.DecimalFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -76,21 +73,11 @@ 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 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<>(); @@ -106,8 +93,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; @@ -143,15 +130,12 @@ 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 { @@ -179,7 +163,7 @@ public class GeyserConnector { 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 + } catch (Exception ex) { 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 @@ -189,8 +173,8 @@ public class GeyserConnector { remoteServer = new RemoteServer(config.getRemote().getAddress(), remotePort); authType = AuthType.getByName(config.getRemote().getAuthType()); - DimensionUtils.changeBedrockNetherId(config.isAboveBedrockNetherBuilding()); // Apply End dimension ID workaround to Nether - SkullBlockEntityTranslator.ALLOW_CUSTOM_SKULLS = config.isAllowCustomSkulls(); + if (config.isAboveBedrockNetherBuilding()) + DimensionUtils.changeBedrockNetherId(); // Apply End dimension ID workaround to Nether // https://github.com/GeyserMC/Geyser/issues/957 RakNetConstants.MAXIMUM_MTU_SIZE = (short) config.getMtu(); @@ -209,40 +193,10 @@ public class GeyserConnector { 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; @@ -264,7 +218,7 @@ public class GeyserConnector { message += LanguageUtils.getLocaleStringLog("geyser.core.finish.console"); } logger.info(message); - + if (platformType == PlatformType.STANDALONE) { logger.warning(LanguageUtils.getLocaleStringLog("geyser.core.movement_warn")); } @@ -280,7 +234,7 @@ public class GeyserConnector { // 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())); + playerSession.disconnect(LanguageUtils.getPlayerLocaleString("geyser.core.shutdown.kick.message", playerSession.getClientData().getLanguageCode())); } CompletableFuture future = CompletableFuture.runAsync(new Runnable() { @@ -328,38 +282,6 @@ public class GeyserConnector { 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; - } - public static GeyserConnector start(PlatformType platformType, GeyserBootstrap bootstrap) { return new GeyserConnector(platformType, bootstrap); } @@ -385,19 +307,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..0ba2a689 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserLogger.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserLogger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -84,9 +84,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..b6a766a3 100644 --- a/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java +++ b/connector/src/main/java/org/geysermc/connector/bootstrap/GeyserBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/command/CommandManager.java b/connector/src/main/java/org/geysermc/connector/command/CommandManager.java index d31983eb..afa75503 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 @@ -31,28 +31,27 @@ 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", LanguageUtils.getLocaleStringLog("geyser.commands.help.desc"), "geyser.command.help")); + registerCommand(new ListCommand(connector, "list", LanguageUtils.getLocaleStringLog("geyser.commands.list.desc"), "geyser.command.list")); + registerCommand(new ReloadCommand(connector, "reload", LanguageUtils.getLocaleStringLog("geyser.commands.reload.desc"), "geyser.command.reload")); + registerCommand(new StopCommand(connector, "stop", LanguageUtils.getLocaleStringLog("geyser.commands.stop.desc"), "geyser.command.stop")); + registerCommand(new OffhandCommand(connector, "offhand", LanguageUtils.getLocaleStringLog("geyser.commands.offhand.desc"), "geyser.command.offhand")); + registerCommand(new DumpCommand(connector, "dump", LanguageUtils.getLocaleStringLog("geyser.commands.dump.desc"), "geyser.command.dump")); + registerCommand(new VersionCommand(connector, "version", LanguageUtils.getLocaleStringLog("geyser.commands.version.desc"), "geyser.command.version")); } public void registerCommand(GeyserCommand command) { @@ -92,13 +91,6 @@ public abstract class CommandManager { 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..be9e3430 100644 --- a/connector/src/main/java/org/geysermc/connector/command/CommandSender.java +++ b/connector/src/main/java/org/geysermc/connector/command/CommandSender.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 @@ 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 +37,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 index 5bc3efea..9ad0d23d 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/DumpCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 @@ package org.geysermc.connector.command.defaults; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter; +import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider; +import org.geysermc.connector.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.common.serializer.AsteriskSerializer; import org.geysermc.connector.dump.DumpInfo; import org.geysermc.connector.utils.LanguageUtils; @@ -38,8 +40,6 @@ 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 { @@ -73,7 +73,7 @@ public class DumpCommand extends GeyserCommand { AsteriskSerializer.showSensitive = showSensitive; - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collecting", sender.getLocale())); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collecting")); String dumpData = ""; try { if (offlineDump) { @@ -82,7 +82,7 @@ public class DumpCommand extends GeyserCommand { dumpData = MAPPER.writeValueAsString(new DumpInfo()); } } catch (IOException e) { - sender.sendMessage(ChatColor.RED + LanguageUtils.getPlayerLocaleString("geyser.commands.dump.collect_error", sender.getLocale())); + sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error")); connector.getLogger().error(LanguageUtils.getLocaleStringLog("geyser.commands.dump.collect_error_short"), e); return; } @@ -90,21 +90,21 @@ public class DumpCommand extends GeyserCommand { String uploadedDumpUrl = ""; if (offlineDump) { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.dump.writing", sender.getLocale())); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.writing")); 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())); + sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.write_error")); 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())); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.uploading")); String response; JsonNode responseNode; @@ -112,27 +112,22 @@ public class DumpCommand extends GeyserCommand { 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())); + sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error")); 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)); + sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.dump.upload_error_short") + ": " + (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); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.dump.message") + " " + 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..0407cf6e 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,10 +25,11 @@ package org.geysermc.connector.command.defaults; +import org.geysermc.connector.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.network.session.GeyserSession; import org.geysermc.connector.utils.LanguageUtils; import java.util.Collections; @@ -51,12 +52,17 @@ public class HelpCommand extends GeyserCommand { 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); + String header = ""; + + if (sender instanceof GeyserSession) { + header = LanguageUtils.getPlayerLocaleString("geyser.commands.help.header", ((GeyserSession) sender).getClientData().getLanguageCode(), page, maxPage); + } else { + header = LanguageUtils.getLocaleStringLog("geyser.commands.help.header", page, maxPage); + } sender.sendMessage(header); 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..3c78c554 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 @@ -35,7 +35,7 @@ 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); @@ -46,9 +46,11 @@ 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(" "))); + if (sender instanceof GeyserSession) { + message = LanguageUtils.getPlayerLocaleString("geyser.commands.list.message", ((GeyserSession) sender).getClientData().getLanguageCode(), connector.getPlayers().size(), connector.getPlayers().stream().map(GeyserSession::getName).collect(Collectors.joining(" "))); + } else { + message = LanguageUtils.getLocaleStringLog("geyser.commands.list.message", connector.getPlayers().size(), connector.getPlayers().stream().map(GeyserSession::getName).collect(Collectors.joining(" "))); + } sender.sendMessage(message); } 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..b1b60132 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,7 +58,7 @@ public class OffhandCommand extends GeyserCommand { session.sendDownstreamPacket(releaseItemPacket); return; } - // Needed for Spigot - sender is not an instance of GeyserSession + // Needed for Bukkit - sender is not an instance of GeyserSession for (GeyserSession session : connector.getPlayers()) { if (sender.getName().equals(session.getPlayerEntity().getUsername())) { ClientPlayerActionPacket releaseItemPacket = new ClientPlayerActionPacket(PlayerAction.SWAP_HANDS, new Position(0,0,0), @@ -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..9c24fa2b 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,7 +25,7 @@ package org.geysermc.connector.command.defaults; -import org.geysermc.common.PlatformType; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.GeyserCommand; @@ -47,12 +47,17 @@ public class ReloadCommand extends GeyserCommand { return; } - String message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", sender.getLocale()); + String message = ""; + if (sender instanceof GeyserSession) { + message = LanguageUtils.getPlayerLocaleString("geyser.commands.reload.message", ((GeyserSession) sender).getClientData().getLanguageCode()); + } else { + message = LanguageUtils.getLocaleStringLog("geyser.commands.reload.message"); + } sender.sendMessage(message); for (GeyserSession session : connector.getPlayers()) { - session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getLocale())); + session.disconnect(LanguageUtils.getPlayerLocaleString("geyser.commands.reload.kick", session.getClientData().getLanguageCode())); } 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..636058a0 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 @@ -25,7 +25,7 @@ package org.geysermc.connector.command.defaults; -import org.geysermc.common.PlatformType; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandSender; import org.geysermc.connector.command.GeyserCommand; @@ -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 index 1f807cf6..681474a9 100644 --- a/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java +++ b/connector/src/main/java/org/geysermc/connector/command/defaults/VersionCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.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; @@ -39,7 +38,6 @@ 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 { @@ -53,39 +51,31 @@ public class VersionCommand extends GeyserCommand { @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)); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.version", GeyserConnector.NAME, GeyserConnector.VERSION, MinecraftConstants.GAME_VERSION, BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion())); // 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())); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.checking")); 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"); + String buildXML = WebUtils.getBody("https://ci.nukkitx.com/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())); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.no_updates")); } else { - sender.sendMessage(LanguageUtils.getPlayerLocaleString("geyser.commands.version.outdated", sender.getLocale(), (latestBuildNum - buildNum), "https://ci.geysermc.org/")); + sender.sendMessage(LanguageUtils.getLocaleStringLog("geyser.commands.version.outdated", (latestBuildNum - buildNum), "http://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())); + sender.sendMessage(ChatColor.RED + LanguageUtils.getLocaleStringLog("geyser.commands.version.failed")); } } } diff --git a/connector/src/main/java/org/geysermc/connector/common/AuthType.java b/connector/src/main/java/org/geysermc/connector/common/AuthType.java index 253bd6a5..cf0c88b2 100644 --- a/connector/src/main/java/org/geysermc/connector/common/AuthType.java +++ b/connector/src/main/java/org/geysermc/connector/common/AuthType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/ChatColor.java b/connector/src/main/java/org/geysermc/connector/common/ChatColor.java index 946be39c..0728ecc7 100644 --- a/connector/src/main/java/org/geysermc/connector/common/ChatColor.java +++ b/connector/src/main/java/org/geysermc/connector/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 diff --git a/common/src/main/java/org/geysermc/common/PlatformType.java b/connector/src/main/java/org/geysermc/connector/common/PlatformType.java similarity index 89% rename from common/src/main/java/org/geysermc/common/PlatformType.java rename to connector/src/main/java/org/geysermc/connector/common/PlatformType.java index a1096f34..7c245c9b 100644 --- a/common/src/main/java/org/geysermc/common/PlatformType.java +++ b/connector/src/main/java/org/geysermc/connector/common/PlatformType.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.common; +package org.geysermc.connector.common; import lombok.AllArgsConstructor; import lombok.Getter; @@ -32,13 +32,11 @@ import lombok.Getter; @AllArgsConstructor public enum PlatformType { - ANDROID("Android"), BUNGEECORD("BungeeCord"), - FABRIC("Fabric"), SPIGOT("Spigot"), SPONGE("Sponge"), STANDALONE("Standalone"), VELOCITY("Velocity"); - private final String platformName; + private String platformName; } 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 index 3f674d7f..66d11079 100644 --- a/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java +++ b/connector/src/main/java/org/geysermc/connector/common/main/IGeyserMain.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/ping/GeyserPingInfo.java b/connector/src/main/java/org/geysermc/connector/common/ping/GeyserPingInfo.java index 4f86ddfb..eb2ee46c 100644 --- a/connector/src/main/java/org/geysermc/connector/common/ping/GeyserPingInfo.java +++ b/connector/src/main/java/org/geysermc/connector/common/ping/GeyserPingInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/common/serializer/AsteriskSerializer.java b/connector/src/main/java/org/geysermc/connector/common/serializer/AsteriskSerializer.java index 0b723817..d91034bd 100644 --- a/connector/src/main/java/org/geysermc/connector/common/serializer/AsteriskSerializer.java +++ b/connector/src/main/java/org/geysermc/connector/common/serializer/AsteriskSerializer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/configuration/GeyserConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java index e21aa6bb..5803ff13 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ package org.geysermc.connector.configuration; import com.fasterxml.jackson.annotation.JsonIgnore; import org.geysermc.connector.GeyserLogger; + import org.geysermc.connector.utils.LanguageUtils; import java.nio.file.Path; @@ -34,7 +35,7 @@ import java.util.Map; public interface GeyserConfiguration { - // Modify this when you introduce breaking changes into the config + // Modify this when you update the config int CURRENT_CONFIG_VERSION = 4; IBedrockConfiguration getBedrock(); @@ -71,24 +72,16 @@ public interface GeyserConfiguration { boolean isShowCooldown(); - boolean isShowCoordinates(); - String getDefaultLocale(); - Path getFloodgateKeyPath(); + Path getFloodgateKeyFile(); boolean isAboveBedrockNetherBuilding(); boolean isCacheChunks(); - boolean isForceResourcePacks(); - - boolean isXboxAchievementsEnabled(); - int getCacheImages(); - boolean isAllowCustomSkulls(); - IMetricsInfo getMetrics(); interface IBedrockConfiguration { @@ -111,28 +104,18 @@ public interface GeyserConfiguration { 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 { @@ -142,15 +125,11 @@ public interface GeyserConfiguration { 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) { diff --git a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java index 7c9532ff..378eba68 100644 --- a/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java +++ b/connector/src/main/java/org/geysermc/connector/configuration/GeyserJacksonConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 @@ import org.geysermc.connector.common.serializer.AsteriskSerializer; import java.nio.file.Path; import java.util.Map; -import java.util.UUID; @Getter @JsonIgnoreProperties(ignoreUnknown = true) @@ -46,91 +45,80 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @Setter private boolean autoconfiguredRemote = false; - private BedrockConfiguration bedrock = new BedrockConfiguration(); - private RemoteConfiguration remote = new RemoteConfiguration(); + private BedrockConfiguration bedrock; + private RemoteConfiguration remote; @JsonProperty("floodgate-key-file") - private String floodgateKeyFile = "public-key.pem"; + private String floodgateKeyFile; - public abstract Path getFloodgateKeyPath(); + public abstract Path getFloodgateKeyFile(); private Map userAuths; @JsonProperty("command-suggestions") - private boolean commandSuggestions = true; + private boolean commandSuggestions; @JsonProperty("passthrough-motd") - private boolean isPassthroughMotd = false; + private boolean isPassthroughMotd; @JsonProperty("passthrough-player-counts") - private boolean isPassthroughPlayerCounts = false; + private boolean isPassthroughPlayerCounts; @JsonProperty("passthrough-protocol-name") - private boolean isPassthroughProtocolName = false; + private boolean isPassthroughProtocolName; @JsonProperty("legacy-ping-passthrough") - private boolean isLegacyPingPassthrough = false; + private boolean isLegacyPingPassthrough; @JsonProperty("ping-passthrough-interval") - private int pingPassthroughInterval = 3; + private int pingPassthroughInterval; @JsonProperty("max-players") - private int maxPlayers = 100; + private int maxPlayers; @JsonProperty("debug-mode") - private boolean debugMode = false; + private boolean debugMode; @JsonProperty("general-thread-pool") - private int generalThreadPool = 32; + private int generalThreadPool; @JsonProperty("allow-third-party-capes") - private boolean allowThirdPartyCapes = true; + private boolean allowThirdPartyCapes; @JsonProperty("show-cooldown") private boolean showCooldown = true; - @JsonProperty("show-coordinates") - private boolean showCoordinates = true; - @JsonProperty("allow-third-party-ears") - private boolean allowThirdPartyEars = false; + private boolean allowThirdPartyEars; @JsonProperty("default-locale") - private String defaultLocale = null; // is null by default so system language takes priority + private String defaultLocale; @JsonProperty("cache-chunks") - private boolean cacheChunks = false; + private boolean cacheChunks; @JsonProperty("cache-images") private int cacheImages = 0; - @JsonProperty("allow-custom-skulls") - private boolean allowCustomSkulls = true; - @JsonProperty("above-bedrock-nether-building") - private boolean aboveBedrockNetherBuilding = false; + private boolean aboveBedrockNetherBuilding; - @JsonProperty("force-resource-packs") - private boolean forceResourcePacks = true; - - @JsonProperty("xbox-achievements-enabled") - private boolean xboxAchievementsEnabled = false; - - private MetricsInfo metrics = new MetricsInfo(); + private MetricsInfo metrics; @Getter public static class BedrockConfiguration implements IBedrockConfiguration { + @AsteriskSerializer.Asterisk(sensitive = true) - private String address = "0.0.0.0"; + private String address; @Setter - private int port = 19132; + private int port; @JsonProperty("clone-remote-port") - private boolean cloneRemotePort = false; + private boolean cloneRemotePort; - private String motd1 = "GeyserMC"; - private String motd2 = "Geyser"; + private String motd1; + private String motd2; @JsonProperty("server-name") private String serverName = GeyserConnector.NAME; @@ -138,57 +126,43 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration @Getter public static class RemoteConfiguration implements IRemoteConfiguration { - @Setter - @AsteriskSerializer.Asterisk(sensitive = true) - private String address = "auto"; @Setter - private int port = 25565; + @AsteriskSerializer.Asterisk(sensitive = true) + private String address; + + @Setter + private int port; @Setter @JsonProperty("auth-type") - private String authType = "online"; - - @JsonProperty("allow-password-authentication") - private boolean passwordAuthentication = true; - - @JsonProperty("use-proxy-protocol") - private boolean useProxyProtocol = false; + private String authType; } @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; + + private boolean enabled; @JsonProperty("uuid") - private String uniqueId = UUID.randomUUID().toString(); + private String uniqueId; } - @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; + private int configVersion; } diff --git a/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java b/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java index 4f16de90..9fbe82cc 100644 --- a/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java +++ b/connector/src/main/java/org/geysermc/connector/dump/BootstrapDumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.dump; import lombok.AllArgsConstructor; import lombok.Getter; -import org.geysermc.common.PlatformType; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.GeyserConnector; import java.util.List; diff --git a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java index 9af740d9..9d91cde6 100644 --- a/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java +++ b/connector/src/main/java/org/geysermc/connector/dump/DumpInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,6 @@ import 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; @@ -113,21 +112,16 @@ public class DumpInfo { 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 { - // 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 = "***"; + // Fallback to the normal way of getting the local IP + this.internalIP = InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException ignored) { } } this.dockerCheck = DockerCheck.checkBasic(); 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..f174747b 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 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..21861589 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 @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat 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 org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.effect.EffectRegistry; @@ -44,10 +43,6 @@ public class AreaEffectCloudEntity extends Entity { // 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); } @Override @@ -55,14 +50,11 @@ public class AreaEffectCloudEntity extends Entity { if (entityMetadata.getId() == 7) { metadata.put(EntityData.AREA_EFFECT_CLOUD_RADIUS, 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_AUX_VALUE, 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..c067416d 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 @@ -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; @@ -55,10 +45,6 @@ public class BoatEntity extends Entity { 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); } @Override 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..dda4577d 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 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..4b665683 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 @@ -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..5e825e89 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,9 +32,11 @@ 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.message.Message; 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.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.EntityDataMap; @@ -44,16 +46,15 @@ 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 +67,8 @@ public class Entity { protected long entityId; protected long geyserId; + protected String dimension; + protected Vector3f position; protected Vector3f motion; @@ -97,6 +100,7 @@ public class Entity { this.rotation = rotation; this.valid = false; + this.dimension = "minecraft:overworld"; setPosition(position); @@ -313,11 +317,11 @@ public class Entity { } break; case 2: // custom name - if (entityMetadata.getValue() instanceof Component) { - Component message = (Component) entityMetadata.getValue(); + if (entityMetadata.getValue() instanceof Message) { + Message message = (Message) 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 @@ -335,6 +339,18 @@ public class Entity { metadata.getFlags().setFlag(EntityFlag.SLEEPING, true); // Has to be a byte or it does not work metadata.put(EntityData.PLAYER_FLAGS, (byte) 2); + if (entityId == session.getPlayerEntity().getEntityId()) { + Vector3i lastInteractionPos = session.getLastInteractionPosition(); + metadata.put(EntityData.BED_POSITION, lastInteractionPos); + if (session.getConnector().getConfig().isCacheChunks()) { + int 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_POSITION, 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)) { 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..c830d259 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 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..f25162f5 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 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..b940b87b 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 @@ -36,7 +36,6 @@ import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.entity.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; @@ -73,10 +72,6 @@ public class FireworkEntity extends Entity { } CompoundTag fireworks = tag.get("Fireworks"); - if (fireworks == null) { - // Thank you Mineplex very cool - return; - } NbtMapBuilder fireworksBuilder = NbtMap.builder(); if (fireworks.get("Flight") != null) { 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..2949b573 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 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..8f0d97b0 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 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..392cec24 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 @@ -34,6 +34,7 @@ import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.BlockEntityDataPacket; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import com.nukkitx.protocol.bedrock.packet.UpdateBlockPacket; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; @@ -69,6 +70,7 @@ public class ItemFrameEntity extends Entity { public ItemFrameEntity(long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation, HangingDirection direction) { super(entityId, geyserId, entityType, position, motion, rotation); + NbtMapBuilder builder = NbtMap.builder(); NbtMapBuilder blockBuilder = NbtMap.builder() .putString("name", "minecraft:frame") .putInt("version", BlockTranslator.getBlockStateVersion()); @@ -76,7 +78,9 @@ public class ItemFrameEntity extends Entity { .putInt("facing_direction", direction.ordinal()) .putByte("item_frame_map_bit", (byte) 0) .build()); - bedrockRuntimeId = BlockTranslator.getItemFrame(blockBuilder.build()); + builder.put("block", blockBuilder.build()); + builder.putShort("id", (short) 199); + bedrockRuntimeId = BlockTranslator.getItemFrame(builder.build()); bedrockPosition = Vector3i.from(position.getFloorX(), position.getFloorY(), position.getFloorZ()); } @@ -98,12 +102,20 @@ public class ItemFrameEntity extends Entity { ItemEntry itemEntry = ItemRegistry.getItem((ItemStack) entityMetadata.getValue()); NbtMapBuilder builder = NbtMap.builder(); + String blockName = ""; + for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) { + if (startGamePacketItemEntry.getId() == (short) itemEntry.getBedrockId()) { + blockName = startGamePacketItemEntry.getIdentifier(); + break; + } + } + builder.putByte("Count", (byte) itemData.getCount()); if (itemData.getTag() != null) { builder.put("tag", itemData.getTag().toBuilder().build()); } builder.putShort("Damage", itemData.getDamage()); - builder.putString("Name", itemEntry.getBedrockIdentifier()); + builder.putString("Name", blockName); NbtMapBuilder tag = getDefaultTag().toBuilder(); tag.put("Item", builder.build()); tag.putFloat("ItemDropChance", 1.0f); @@ -136,7 +148,7 @@ 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.NEIGHBORS); @@ -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..1b6f208b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/LeashKnotEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/LivingEntity.java b/connector/src/main/java/org/geysermc/connector/entity/LivingEntity.java index f38f1e6b..ae9eaee5 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,9 +26,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.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; @@ -44,7 +42,6 @@ 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; @@ -77,9 +74,6 @@ public class LivingEntity extends Entity { 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()); @@ -90,17 +84,6 @@ public class LivingEntity extends Entity { 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); - } - } - break; } super.updateBedrockMetadata(entityMetadata, session); 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..72b5ee82 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 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..8db7554b 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 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 74% 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..52b27351 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,41 +23,32 @@ * @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.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.AdventureSetting; 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.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.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.session.cache.EntityEffectCache; 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 java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; import java.util.concurrent.TimeUnit; @Getter @Setter @@ -65,16 +56,12 @@ public class PlayerEntity extends LivingEntity { private GameProfile profile; private UUID uuid; private String username; + private long lastSkinUpdate = -1; private boolean playerList = true; // Player is in the player list + 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); @@ -114,7 +111,7 @@ public class PlayerEntity extends LivingEntity { } public void sendPlayer(GeyserSession session) { - if (session.getEntityCache().getPlayerEntity(uuid) == null) + if(session.getEntityCache().getPlayerEntity(uuid) == null) return; if (session.getUpstream().isInitialized() && session.getEntityCache().getEntityByGeyserId(geyserId) == null) { @@ -156,10 +153,6 @@ 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); MovePlayerPacket movePlayerPacket = new MovePlayerPacket(); @@ -168,17 +161,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); @@ -202,12 +184,6 @@ public class PlayerEntity extends LivingEntity { @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 @@ -221,28 +197,11 @@ public class PlayerEntity extends LivingEntity { 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 +209,20 @@ public class PlayerEntity extends LivingEntity { super.updateBedrockMetadata(entityMetadata, session); if (entityMetadata.getId() == 2) { + // System.out.println(session.getScoreboardCache().getScoreboard().getObjectives().keySet()); + for (Team team : session.getWorldCache().getScoreboard().getTeams().values()) { + // session.getConnector().getLogger().info("team name " + team.getName()); + // session.getConnector().getLogger().info("team entities " + team.getEntities()); + } String username = this.username; - Component name = (Component) entityMetadata.getValue(); + TextMessage name = (TextMessage) entityMetadata.getValue(); if (name != null) { - username = MessageTranslator.convertMessage(name); + username = MessageUtils.getBedrockMessage(name); } Team team = session.getWorldCache().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()); } } @@ -278,15 +238,11 @@ public class PlayerEntity extends LivingEntity { } // Parrot occupying shoulder - if (entityMetadata.getId() == 18 || entityMetadata.getId() == 19) { + if ((entityMetadata.getId() == 18 && leftParrot == null) || (entityMetadata.getId() == 19 && rightParrot == null)) { // null check since this code just creates the parrot 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()); 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..56341b3b 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 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..068cd2a1 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/TNTEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/TNTEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..4a9007ab 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 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..1d692e2a 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 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..9c3e2084 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 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..2175efcd 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 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..07496093 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 @@ -29,7 +29,6 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat 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 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..808eb3cb 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 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 index fb2726d1..456e082b 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/living/MagmaCubeEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/SlimeEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/SlimeEntity.java index da088410..faf99320 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..b0692eab 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 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..c46f00fe 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 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..88c30cbf 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 @@ -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..36a67dbb 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 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..7e555122 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 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..9b9701f8 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 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..2b09ca91 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 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..407708a5 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 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..0b61713a 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 @@ -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..464377ef 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 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 index 9ea97eb1..d1fdc63c 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/TropicalFishEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/animal/TropicalFishEntity.java index 8d5b476a..eadc3db0 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 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..e08f9adf 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,14 +27,10 @@ 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 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; public class AbstractHorseEntity extends AnimalEntity { @@ -51,30 +47,6 @@ public class AbstractHorseEntity extends AnimalEntity { 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 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..7343f5e8 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 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..da3ff349 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 @@ -28,6 +28,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.EntityData; +import com.nukkitx.protocol.bedrock.data.entity.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..ddac4a63 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 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..f0132673 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 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..067a360c 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 @@ -34,8 +34,6 @@ 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); } @@ -47,13 +45,6 @@ public class CatEntity extends TameableEntity { @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 +67,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..a867517a 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 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..2e8ab816 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 @@ -29,13 +29,10 @@ import com.github.steveice10.mc.protocol.data.game.entity.metadata.EntityMetadat 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.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..ab631ebe 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 @@ -34,8 +34,6 @@ 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); } @@ -59,18 +57,12 @@ public class WolfEntity extends TameableEntity { // 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..11028b79 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 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..7ada302c 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,26 @@ 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.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.packet.MoveEntityAbsolutePacket; +import com.nukkitx.protocol.bedrock.data.entity.EntityFlags; +import com.nukkitx.protocol.bedrock.packet.*; 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.WorldManager; 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 @@ -105,9 +99,9 @@ public class VillagerEntity extends AbstractMerchantEntity { 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); + if (session.getConnector().getConfig().isCacheChunks()) { + Position bedLocation = new Position((int) position.getFloorX(), (int) position.getFloorY(), (int) position.getFloorZ()); + bedId = session.getConnector().getWorldManager().getBlockAt(session, bedLocation); } String bedRotationZ = BlockTranslator.getJavaIdBlockMap().inverse().get(bedId); setRotation(rotation); 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..ff48d347 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 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 index 0dac9207..830c7ea3 100644 --- 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 @@ -1,50 +1,11 @@ -/* - * 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); - } -} +} \ No newline at end of file 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..75fec18f 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 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..3c3a76bd 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 @@ -33,12 +33,6 @@ 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..8786a5b3 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/EnderDragonEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/EnderDragonEntity.java index 62167979..aa2b4e02 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 @@ -28,334 +28,59 @@ 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.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 AttributeData("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..dfca0804 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 @@ -27,10 +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.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 org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.world.block.BlockTranslator; @@ -47,21 +45,11 @@ public class EndermanEntity extends MonsterEntity { if (entityMetadata.getId() == 15) { metadata.put(EntityData.CARRIED_BLOCK, BlockTranslator.getBedrockBlockId((int) 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..aa22d8d6 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 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..aa9ce4ca 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 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 index 79402391..7b0d71e1 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -41,7 +41,7 @@ public class PiglinEntity extends BasePiglinEntity { @Override public void updateBedrockMetadata(EntityMetadata entityMetadata, GeyserSession session) { - if (entityMetadata.getId() == 16) { + if (entityMetadata.getId() == 15) { boolean isBaby = (boolean) entityMetadata.getValue(); if (isBaby) { metadata.put(EntityData.SCALE, .55f); 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..a0bd5bc2 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 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..f0ad6f05 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 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..8b864525 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 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 index 585a1e2c..4ea84211 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/ZombieEntity.java b/connector/src/main/java/org/geysermc/connector/entity/living/monster/ZombieEntity.java index f3e0fdad..218a2ca0 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 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 index ad00145b..01693170 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..87f4c8b5 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), @@ -75,10 +73,10 @@ public enum EntityType { 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), + GHAST(FlyingEntity.class, 41, 4.0f), MAGMA_CUBE(MagmaCubeEntity.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), @@ -154,7 +152,7 @@ public enum EntityType { 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"), + HOGLIN(AnimalEntity.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"), @@ -167,12 +165,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 index fbc7849f..904f70a0 100644 --- a/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java +++ b/connector/src/main/java/org/geysermc/connector/network/BedrockProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,31 +26,30 @@ 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 com.nukkitx.protocol.bedrock.v407.Bedrock_v407; +import com.nukkitx.protocol.bedrock.v408.Bedrock_v408; +import com.nukkitx.protocol.bedrock.v409.Bedrock_v409; -import java.util.ArrayList; -import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; /** * 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. + * Default Bedrock codec that should act as a fallback and as the version shown in /geyser version */ - public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v422.V422_CODEC; + public static final BedrockPacketCodec DEFAULT_BEDROCK_CODEC = Bedrock_v408.V408_CODEC; /** * A list of all supported Bedrock versions that can join Geyser */ - public static final List SUPPORTED_BEDROCK_CODECS = new ArrayList<>(); + public static final Set SUPPORTED_BEDROCK_CODECS = ConcurrentHashMap.newKeySet(); 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); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v407.V407_CODEC); + SUPPORTED_BEDROCK_CODECS.add(Bedrock_v409.V409_CODEC); } /** 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..9fb4ad9e 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,21 @@ package org.geysermc.connector.network; +import com.github.steveice10.mc.protocol.data.message.MessageSerializer; import com.nukkitx.protocol.bedrock.BedrockPong; import com.nukkitx.protocol.bedrock.BedrockServerEventHandler; import com.nukkitx.protocol.bedrock.BedrockServerSession; 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.GeyserConnector; import org.geysermc.connector.configuration.GeyserConfiguration; import org.geysermc.connector.network.session.GeyserSession; -import org.geysermc.connector.network.translators.chat.MessageTranslator; import org.geysermc.connector.ping.IGeyserPingPassthrough; +import org.geysermc.connector.utils.MessageUtils; import org.geysermc.connector.utils.LanguageUtils; import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; public class ConnectorServerEventHandler implements BedrockServerEventHandler { @@ -64,7 +64,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { GeyserPingInfo pingInfo = null; if (config.isPassthroughMotd() || config.isPassthroughPlayerCounts()) { IGeyserPingPassthrough pingPassthrough = connector.getBootstrap().getGeyserPingPassthrough(); - pingInfo = pingPassthrough.getPingInformation(inetSocketAddress); + pingInfo = pingPassthrough.getPingInformation(); } BedrockPong pong = new BedrockPong(); @@ -76,7 +76,7 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { pong.setIpv4Port(config.getBedrock().getPort()); if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) { - String[] motd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n"); + String[] motd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).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. @@ -95,20 +95,6 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler { 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()) { 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..c41c64c7 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); @@ -821,43 +826,4 @@ public class LoggingPacketHandler implements BedrockPacketHandler { 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..7faf36bd 100644 --- a/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java +++ b/connector/src/main/java/org/geysermc/connector/network/QueryPacketHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,12 @@ package org.geysermc.connector.network; +import com.github.steveice10.mc.protocol.data.message.MessageSerializer; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import org.geysermc.connector.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; @@ -147,7 +148,7 @@ public class QueryPacketHandler { } if (connector.getConfig().isPassthroughMotd() && pingInfo != null) { - String[] javaMotd = MessageTranslator.convertMessageLenient(pingInfo.getDescription()).split("\n"); + String[] javaMotd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).split("\n"); motd = javaMotd[0].trim(); // First line of the motd. } else { motd = connector.getConfig().getBedrock().getMotd1(); @@ -174,7 +175,7 @@ public class QueryPacketHandler { 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", BedrockProtocol.DEFAULT_BEDROCK_CODEC.getMinecraftVersion()); gameData.put("plugins", ""); gameData.put("map", map); gameData.put("numplayers", currentPlayerCount); 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..f65b3ef1 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,16 @@ 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.connector.GeyserConnector; import org.geysermc.connector.common.AuthType; import org.geysermc.connector.configuration.GeyserConfiguration; +import org.geysermc.connector.GeyserConnector; 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; +import org.geysermc.connector.utils.LanguageUtils; +import org.geysermc.connector.utils.SettingsUtils; public class UpstreamPacketHandler extends LoggingPacketHandler { @@ -56,11 +53,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { 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; } @@ -75,13 +70,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; } @@ -93,42 +81,13 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { session.connect(connector.getRemoteServer()); connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.network.connect", 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,19 +98,8 @@ 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()); + if (packet.getFormId() == SettingsUtils.SETTINGS_FORM_ID) { + return SettingsUtils.handleSettingsForm(session, packet.getFormData()); } return LoginEncryptionUtils.authenticateFromForm(session, connector, packet.getFormId(), packet.getFormData()); @@ -163,7 +111,6 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { if (info != null) { connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().getName())); - session.setMicrosoftAccount(info.isMicrosoftAccount()); session.authenticate(info.getEmail(), info.getPassword()); // TODO send a message to bedrock user telling them they are connected (if nothing like a motd @@ -177,7 +124,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { @Override public boolean handle(SetLocalPlayerAsInitializedPacket packet) { - LanguageUtils.loadGeyserLocale(session.getLocale()); + LanguageUtils.loadGeyserLocale(session.getClientData().getLanguageCode()); 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) @@ -192,13 +139,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(LanguageUtils.getPlayerLocaleString("geyser.auth.login.wait", session.getClientData().getLanguageCode())); } return translateAndDefault(packet); @@ -208,30 +149,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..b208aaf3 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,24 +26,17 @@ 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.message.MessageSerializer; 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; @@ -55,26 +48,20 @@ 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.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.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; @@ -83,11 +70,9 @@ import org.geysermc.connector.network.session.cache.*; 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.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.*; import org.geysermc.floodgate.util.BedrockData; import org.geysermc.floodgate.util.EncryptionUtil; @@ -98,9 +83,7 @@ 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.concurrent.atomic.AtomicInteger; @Getter public class GeyserSession implements CommandSender { @@ -114,29 +97,18 @@ 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 WindowCache windowCache; - private final Int2ObjectMap teleportMap = new Int2ObjectOpenHashMap<>(); + @Setter + private TeleportCache teleportCache; - /** - * Stores session collision - */ - private final CollisionManager collisionManager; - - private final Map skullCache = new ConcurrentHashMap<>(); + @Getter private final Long2ObjectMap storedMaps = Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); /** @@ -145,6 +117,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 +133,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,13 +144,6 @@ 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; @@ -192,13 +156,11 @@ 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; + + private boolean manyDimPackets = false; + private ServerRespawnPacket lastDimPacket = null; @Setter private Entity ridingVehicleEntity; @@ -221,10 +183,9 @@ public class GeyserSession implements CommandSender { /** * 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; + private double attackSpeed; /** * 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. @@ -232,42 +193,6 @@ public class GeyserSession implements CommandSender { @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 @@ -315,63 +240,28 @@ public class GeyserSession implements CommandSender { @Setter private boolean thunder = false; - /** - * Stores the last text inputted into a sign. - * - * Bedrock sends packets every time you update the sign, Java only wants the final packet. - * Until we determine that the user has finished editing, we save the sign's current status. - */ - @Setter - private String lastSignMessage; - - /** - * Stores a map of all statistics sent from the server. - * The server only sends new statistics back to us, so in order to show all statistics we need to cache existing ones. - */ - 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.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)); @@ -384,9 +274,6 @@ public class GeyserSession implements CommandSender { 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(); @@ -414,15 +301,10 @@ public class GeyserSession implements CommandSender { 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 + GameRulesChangedPacket gamerulePacket = new GameRulesChangedPacket(); 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); } @@ -452,22 +334,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(); + boolean floodgate = connector.getAuthType() == AuthType.FLOODGATE; + final PublicKey publicKey; + + if (floodgate) { + PublicKey key = null; + try { + key = EncryptionUtil.getKeyFromFile( + connector.getConfig().getFloodgateKeyFile(), + 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")); + } + + 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(LanguageUtils.getLocaleStringLog("geyser.auth.floodgate.encrypt_fail"), e); + } + + 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("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(LanguageUtils.getLocaleStringLog("geyser.network.remote.disconnect", authData.getName(), remoteServer.getAddress(), event.getReason())); + if (event.getCause() != null) { + event.getCause().printStackTrace(); + } + + upstream.disconnect(MessageUtils.getBedrockMessage(MessageSerializer.fromString(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(LanguageUtils.getLocaleStringLog("geyser.network.downstream_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(LanguageUtils.getLocaleStringLog("geyser.auth.login.invalid", username)); disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode())); @@ -477,199 +477,6 @@ public class GeyserSession implements CommandSender { }).start(); } - /** - * 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 = ""; - 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); - } - - 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"); - } - - // Download and load the language for the player - LocaleUtils.downloadAndLoadLocale(locale); - } - - @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); - } - } - - PacketTranslatorRegistry.JAVA_TRANSLATOR.translate(event.getPacket().getClass(), event.getPacket(), GeyserSession.this); - } - } - - @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); - } - }); - - if (!daylightCycle) { - setDaylightCycle(true); - } - downstream.getSession().connect(); - connector.addPlayer(this); - } - public void disconnect(String reason) { if (!closed) { loggedIn = false; @@ -682,15 +489,8 @@ public class GeyserSession implements CommandSender { } } - 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.inventoryCache = null; this.windowCache = null; @@ -702,38 +502,10 @@ public class GeyserSession implements CommandSender { 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); - } - } - 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(); @@ -757,17 +529,13 @@ public class GeyserSession implements CommandSender { 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 + if (renderDistance > 32) renderDistance = 32; // <3 u ViaVersion but I don't like crashing clients x) this.renderDistance = renderDistance; ChunkRadiusUpdatedPacket chunkRadiusUpdatedPacket = new ChunkRadiusUpdatedPacket(); @@ -792,12 +560,12 @@ public class GeyserSession implements CommandSender { startGamePacket.setRotation(Vector2f.from(1, 1)); startGamePacket.setSeed(-1); - startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(dimension)); + startGamePacket.setDimensionId(DimensionUtils.javaToBedrock(playerEntity.getDimension())); startGamePacket.setGeneratorId(1); startGamePacket.setLevelGameType(GameType.SURVIVAL); startGamePacket.setDifficulty(1); startGamePacket.setDefaultSpawn(Vector3i.ZERO); - startGamePacket.setAchievementsDisabled(!connector.getConfig().isXboxAchievementsEnabled()); + startGamePacket.setAchievementsDisabled(true); startGamePacket.setCurrentTick(-1); startGamePacket.setEduEditionOffers(0); startGamePacket.setEduFeaturesEnabled(false); @@ -805,10 +573,10 @@ public class GeyserSession implements CommandSender { 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); @@ -830,91 +598,35 @@ public class GeyserSession implements CommandSender { // 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 +635,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"); @@ -958,18 +670,6 @@ public class GeyserSession implements CommandSender { 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 * @@ -998,16 +698,8 @@ public class GeyserSession implements CommandSender { 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; + adventureSettingsPacket.setCommandPermission(CommandPermission.NORMAL); + adventureSettingsPacket.setPlayerPermission(PlayerPermission.MEMBER); Set flags = new HashSet<>(); if (canFly) { @@ -1031,31 +723,4 @@ public class GeyserSession implements CommandSender { 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..a1245d90 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/auth/BedrockClientData.java b/connector/src/main/java/org/geysermc/connector/network/session/auth/BedrockClientData.java index 10075a9a..fb9948ea 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..68e8519c 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.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; @@ -58,7 +58,7 @@ public class BossBar { BossEventPacket bossEventPacket = new BossEventPacket(); bossEventPacket.setBossUniqueEntityId(entityId); bossEventPacket.setAction(BossEventPacket.Action.CREATE); - bossEventPacket.setTitle(MessageTranslator.convertMessage(title, session.getLocale())); + bossEventPacket.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode())); bossEventPacket.setHealthPercentage(health); bossEventPacket.setColor(color); //ignored by client bossEventPacket.setOverlay(overlay); @@ -67,12 +67,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.setTitle(MessageUtils.getTranslatedBedrockMessage(title, session.getClientData().getLanguageCode())); session.sendUpstreamPacket(bossEventPacket); } 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..9601a298 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,18 +27,22 @@ 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 com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; +import lombok.Getter; import org.geysermc.connector.bootstrap.GeyserBootstrap; 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 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()) { @@ -48,74 +52,52 @@ public class ChunkCache { } } - 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, int 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 int 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/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/session/cache/WorldCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/WorldCache.java index 0cbfffba..310e5f9d 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/WorldCache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,40 +31,37 @@ 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; + + private GeyserSession session; + @Setter private Difficulty difficulty = Difficulty.EASY; + private boolean showCoordinates = true; private Scoreboard scoreboard; - private final ScoreboardUpdater scoreboardUpdater; public WorldCache(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 * 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..680a2d0c 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/EntityIdentifierRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/EntityIdentifierRegistry.java index f4c0f9ab..f1000242 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..92d2e910 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,6 +25,7 @@ package org.geysermc.connector.network.translators; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerKeepAlivePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListDataPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerUpdateLightPacket; import com.github.steveice10.packetlib.packet.Packet; @@ -32,7 +33,6 @@ 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; @@ -48,7 +48,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(); @@ -74,6 +74,7 @@ public class PacketTranslatorRegistry { } } + 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 } 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/BedrockAdventureSettingsTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java index 5274cef8..f1efc222 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAdventureSettingsTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/BedrockAnimateTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java index 6e97a518..012582da 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockAnimateTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 +25,23 @@ package org.geysermc.connector.network.translators.bedrock; +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.packet.ingame.client.player.ClientPlayerSwingArmPacket; import com.github.steveice10.mc.protocol.packet.ingame.client.world.ClientSteerBoatPacket; import com.nukkitx.protocol.bedrock.packet.AnimatePacket; -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 = AnimatePacket.class) public class BedrockAnimateTranslator 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..38b94039 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,18 +26,23 @@ 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.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(); @@ -45,8 +50,9 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator 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 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 the bounds of the four lines + // 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; } 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); } // 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); + //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 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); + // We remove the sign position from map to indicate there is no work-in-progress sign + lastMessages.remove(pos); } } 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..39cfceb1 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockBlockPickRequestPacketTranslator.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to 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.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(); + int blockToPick = session.getConnector().getWorldManager().getBlockAt(session, vector.getX(), vector.getY(), vector.getZ()); + + // Block is air - chunk caching is probably off + if (blockToPick == 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..d05a667d 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 @@ -25,7 +25,7 @@ package org.geysermc.connector.network.translators.bedrock; -import org.geysermc.common.PlatformType; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.command.CommandManager; import org.geysermc.connector.network.session.GeyserSession; @@ -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(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/BedrockInventoryTransactionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockInventoryTransactionTranslator.java index 8263507b..f8e4eb6d 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 @@ -39,16 +39,11 @@ import com.github.steveice10.mc.protocol.packet.ingame.client.player.ClientPlaye import com.nukkitx.math.vector.Vector3f; import com.nukkitx.math.vector.Vector3i; 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.InventoryTransactionPacket; +import com.nukkitx.protocol.bedrock.packet.LevelEventPacket; 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 +53,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,17 +75,6 @@ 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()], @@ -168,50 +97,40 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator { - ClientPlayerUseItemPacket itemPacket = new ClientPlayerUseItemPacket(Hand.MAIN_HAND); - session.sendDownstreamPacket(itemPacket); - }, 5, TimeUnit.MILLISECONDS)); + // Otherwise boats will not be able to be placed in survival and buckets wont work on mobile + if (packet.getItemInHand() != null && (packet.getItemInHand().getId() == ItemRegistry.BOAT.getBedrockId() || packet.getItemInHand().getId() == ItemRegistry.BUCKET.getBedrockId())) { + 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.getBlockFace()) { + 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: @@ -221,45 +140,34 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator MAXIMUM_BLOCK_DESTROYING_DISTANCE) { - restoreCorrectBlock(session, packet.getBlockPosition(), packet); - return; + LevelEventPacket blockBreakPacket = new LevelEventPacket(); + blockBreakPacket.setType(LevelEventType.PARTICLE_DESTROY_BLOCK); + 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.isSneaking()); session.sendDownstreamPacket(attackPacket); break; } @@ -287,18 +195,6 @@ public class BedrockInventoryTransactionTranslator 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()); 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..26d7f1d4 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,28 +27,19 @@ 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/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 index b69cedcb..d4a0e8d3 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/BedrockPlayerInputTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockPlayerInputTranslator.java index a04e332c..2bd46c7c 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -31,9 +31,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 index da760cdd..75f60ffd 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/BedrockRespawnTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockRespawnTranslator.java index 2964bd65..4e4b4a30 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 @@ -28,10 +28,7 @@ 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; @@ -42,30 +39,12 @@ 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); - 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); + if (!session.isSpawned()) { // Otherwise when immediate respawn is on the client never loads + RespawnPacket respawnPacket = new RespawnPacket(); + respawnPacket.setRuntimeEntityId(0); + respawnPacket.setPosition(Vector3f.ZERO); + respawnPacket.setState(RespawnPacket.State.SERVER_SEARCHING); + session.sendUpstreamPacket(respawnPacket); } ClientRequestPacket javaRespawnPacket = new ClientRequestPacket(ClientRequest.RESPAWN); 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 index 997bba8a..a8591cd7 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/BedrockSetLocalPlayerAsInitializedTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockSetLocalPlayerAsInitializedTranslator.java index ac6f543d..c1ad7409 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); + SkinUtils.requestAndHandleSkinAndCape(entity, session, null); 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 index a89bfdfb..18fd6614 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 +42,13 @@ public class BedrockEntityEventTranslator 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; @@ -122,232 +84,50 @@ public class BedrockInteractTranslator extends PacketTranslator 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; - } + String interactiveTag; + switch (interactEntity.getEntityType()) { + case BOAT: + interactiveTag = "action.interact.ride.boat"; + break; + case DONKEY: + case HORSE: + case LLAMA: + case MULE: + case SKELETON_HORSE: + case TRADER_LLAMA: + case ZOMBIE_HORSE: + if (entityMetadata.getFlags().getFlag(EntityFlag.TAMED)) { + interactiveTag = "action.interact.ride.horse"; + } else { + interactiveTag = "action.interact.mount"; + } + break; + case MINECART: + interactiveTag = "action.interact.ride.minecart"; + break; + case PIG: + if (entityMetadata.getFlags().getFlag(EntityFlag.SADDLED)) { + interactiveTag = "action.interact.mount"; + } else interactiveTag = ""; + 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 = "action.interact.trade"; + } else interactiveTag = ""; + break; + case WANDERING_TRADER: + interactiveTag = "action.interact.trade"; // Since you can always trade with a wandering villager, presumably. + break; + default: + return; // No need to process any further since there is no interactive tag } - session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag.getValue()); + session.getPlayerEntity().getMetadata().put(EntityData.INTERACTIVE_TAG, interactiveTag); session.getPlayerEntity().updateBedrockMetadata(session); } else { - if (!session.getPlayerEntity().getMetadata().getString(EntityData.INTERACTIVE_TAG).isEmpty()) { + 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); @@ -367,65 +147,4 @@ public class BedrockInteractTranslator extends PacketTranslator 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 index 2f6ba0d4..be918ba7 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,28 +25,28 @@ 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.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 (!session.isSpawned()) return; + if (entity == null || !session.isSpawned() || session.getPendingDimSwitches().get() > 0) return; if (!session.getUpstream().isInitialized()) { MoveEntityAbsolutePacket moveEntityBack = new MoveEntityAbsolutePacket(); @@ -59,88 +59,49 @@ public class BedrockMovePlayerTranslator extends PacketTranslator= 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(); - } - } - } + if(!session.confirmTeleport(position)){ + return; } - // 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); + 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); } - private boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) { + public boolean isValidMove(GeyserSession session, MovePlayerPacket.Mode mode, Vector3f currentPosition, Vector3f newPosition) { if (mode != MovePlayerPacket.Mode.NORMAL) return true; @@ -164,5 +125,19 @@ public class BedrockMovePlayerTranslator 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 index c87692b8..44553e82 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..b827bb93 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 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..39c586db 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,11 +32,10 @@ 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; +import org.geysermc.connector.utils.LanguageUtils; import java.io.InputStream; import java.util.HashMap; @@ -51,19 +50,8 @@ public class EffectRegistry { public static final Map SOUND_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 +68,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(LanguageUtils.getLocaleStringLog("geyser.particle.failed_map", entry.getKey(), entry.getValue().asText())); } } - } catch (Exception e) { - e.printStackTrace(); } /* Load effects */ @@ -163,27 +149,11 @@ public class EffectRegistry { } } - /** - * @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 index 2b130240..c82bca33 100644 --- 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 @@ -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.effect; 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 index e9d876c7..77641e37 100644 --- 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 @@ -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.effect; 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 index 85dea329..67b10bb2 100644 --- 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 @@ -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.effect; 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..ab266fae 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 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..6f00fc4d 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 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..4b8b57e8 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 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..89cdbe8d 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 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..152f4a85 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 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..f5ebe62d 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 @@ -30,9 +30,12 @@ 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.packet.ContainerOpenPacket; +import org.geysermc.connector.GeyserConnector; 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; @@ -45,7 +48,7 @@ public class CraftingInventoryTranslator extends BlockInventoryTranslator { @Override public int bedrockSlotToJava(InventoryActionData action) { if (action.getSlot() == 50) { - // Slot 50 is used for crafting with a controller. + GeyserConnector.getInstance().getLogger().warning("Slot 50 found, please report: " + action); return 0; } 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..1183b21d 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 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..cbcdce10 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 @@ -42,12 +42,13 @@ 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.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 java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; /** * A temporary reconstruction of the enchantment table UI until our inventory rewrite is complete. @@ -56,8 +57,9 @@ import java.util.*; */ 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(); + private static final int DYE_ID = 351; + private static final short LAPIS_DAMAGE = 4; + private static final int ENCHANTED_BOOK_ID = 403; public EnchantmentInventoryTranslator(InventoryUpdater updater) { super(2, "minecraft:hopper[enabled=false,facing=down]", ContainerType.HOPPER, updater); @@ -71,7 +73,8 @@ public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { 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) { + if ((action.getToItem().getId() != DYE_ID + && action.getToItem().getDamage() != LAPIS_DAMAGE) && action.getToItem() != ItemData.AIR) { updateInventory(session, inventory); InventoryUtils.updateCursor(session); return; @@ -98,11 +101,11 @@ public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { @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))); + ItemData[] items = new ItemData[5]; + items[0] = ItemTranslator.translateToBedrock(session, inventory.getItem(0)); + items[1] = 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()); + items[i + 2] = session.getEnchantmentSlotData()[i].getItem() != null ? session.getEnchantmentSlotData()[i].getItem() : createEnchantmentBook(); } InventoryContentPacket contentPacket = new InventoryContentPacket(); @@ -196,7 +199,7 @@ public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { private String toRomanNumeral(GeyserSession session, int level) { return LocaleUtils.getLocaleString("enchantment.level." + level, - session.getLocale()); + session.getClientData().getLanguageCode()); } /** @@ -258,7 +261,7 @@ public class EnchantmentInventoryTranslator extends BlockInventoryTranslator { public String toString(GeyserSession session) { return LocaleUtils.getLocaleString("enchantment.minecraft." + this.toString().toLowerCase(), - session.getLocale()); + session.getClientData().getLanguageCode()); } } } 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..1f148e02 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 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..4b4a1246 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 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..e44e4bd0 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 @@ -53,9 +53,9 @@ 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.GRINDSTONE, new GrindstoneInventoryTranslator()); put(WindowType.MERCHANT, new MerchantInventoryTranslator()); - //put(WindowType.SMITHING, new SmithingInventoryTranslator()); //TODO for server authoritative inventories + put(WindowType.SMITHING, new SmithingInventoryTranslator()); InventoryTranslator furnace = new FurnaceInventoryTranslator(); put(WindowType.FURNACE, furnace); 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 index aa36a8a8..25fdae68 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,6 +27,7 @@ package org.geysermc.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.inventory.InventorySource; import org.geysermc.connector.inventory.Inventory; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.inventory.updater.CursorInventoryUpdater; 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..7d7673c4 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 @@ -41,8 +41,6 @@ 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 { @@ -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); } @@ -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); } } 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..45860dcd 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 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 index 19c2522e..f7f0acd8 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..96cbd61f 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 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..6dfde5d1 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 @@ -35,8 +35,9 @@ 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 { @@ -59,7 +60,7 @@ public class BlockInventoryHolder extends InventoryHolder { .putInt("x", position.getX()) .putInt("y", position.getY()) .putInt("z", position.getZ()) - .putString("CustomName", inventory.getTitle()).build(); + .putString("CustomName", LocaleUtils.getLocaleString(inventory.getTitle(), session.getClientData().getLanguageCode())).build(); BlockEntityDataPacket dataPacket = new BlockEntityDataPacket(); dataPacket.setData(tag); dataPacket.setBlockPosition(position); 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..e45945bc 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 @@ -36,9 +36,6 @@ 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")); @@ -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..51f33ac4 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 @@ -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..26d88990 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 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..57601a9e 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 @@ -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..31ec0c7f 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 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..19f83cd9 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 @@ -34,10 +34,9 @@ import lombok.ToString; @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..56ed2d6e 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 @@ import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.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; @@ -52,37 +50,19 @@ 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 + * Boat item entry, used in BedrockInventoryTransactionTranslator.java */ - public static ItemEntry BAMBOO; + public static ItemEntry BOAT; /** - * Boat item entries, used in BedrockInventoryTransactionTranslator.java + * Bucket item entry, 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; + public static ItemEntry BUCKET; /** * Gold item entry, used in PiglinEntity.java */ @@ -91,14 +71,6 @@ public class ItemRegistry { * 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; public static int BARRIER_INDEX = 0; @@ -108,14 +80,11 @@ 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); @@ -123,14 +92,8 @@ public class ItemRegistry { throw new AssertionError(LanguageUtils.getLocaleStringLog("geyser.toolbox.fail.runtime_bedrock"), 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"); @@ -146,29 +109,28 @@ public class ItemRegistry { 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())); } 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())); } @@ -176,11 +138,8 @@ public class ItemRegistry { case "minecraft:barrier": BARRIER_INDEX = itemIndex; break; - case "minecraft:bamboo": - BAMBOO = ITEM_ENTRIES.get(itemIndex); - break; - case "minecraft:egg": - EGG = ITEM_ENTRIES.get(itemIndex); + case "minecraft:oak_boat": + BOAT = ITEM_ENTRIES.get(itemIndex); break; case "minecraft:gold_ingot": GOLD = ITEM_ENTRIES.get(itemIndex); @@ -188,35 +147,18 @@ public class ItemRegistry { 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); + case "minecraft:bucket": + BUCKET = 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()); - } - 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)); + // Add the loadstonecompass since it doesn't exist on java but we need it for item conversion + ITEM_ENTRIES.put(itemIndex, new ItemEntry("minecraft:lodestonecompass", itemIndex, 741, 0, false)); /* Load creative items */ stream = FileUtils.getResource("bedrock/creative_items.json"); @@ -255,13 +197,8 @@ 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; } } @@ -280,14 +217,8 @@ 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; - }); + 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..dce0f4b4 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.item; import com.github.steveice10.mc.protocol.data.game.entity.metadata.ItemStack; +import com.github.steveice10.mc.protocol.data.message.MessageSerializer; import com.github.steveice10.opennbt.tag.builtin.*; import com.nukkitx.nbt.NbtList; import com.nukkitx.nbt.NbtMap; @@ -34,19 +35,21 @@ import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.kyori.adventure.text.TextComponent; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; 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.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)) { @@ -111,10 +114,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; } @@ -130,7 +129,7 @@ public abstract class ItemTranslator { // This is a fallback for maps with no nbt if (nbt == null && bedrockItem.getJavaIdentifier().equals("minecraft:filled_map")) { - nbt = new CompoundTag(""); + nbt = new com.github.steveice10.opennbt.tag.builtin.CompoundTag(""); nbt.put(new IntTag("map", 0)); } @@ -154,43 +153,9 @@ 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); - } - 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() { @@ -219,17 +184,19 @@ public abstract class ItemTranslator { public abstract List getAppliedItems(); public NbtMap translateNbtToBedrock(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag) { - NbtMapBuilder builder = NbtMap.builder(); + Map javaValue = new HashMap<>(); if (tag.getValue() != null && !tag.getValue().isEmpty()) { for (String str : tag.getValue().keySet()) { - Tag javaTag = tag.get(str); + com.github.steveice10.opennbt.tag.builtin.Tag javaTag = tag.get(str); Object translatedTag = translateToBedrockNBT(javaTag); if (translatedTag == null) continue; - builder.put(javaTag.getName(), translatedTag); + javaValue.put(javaTag.getName(), translatedTag); } } + NbtMapBuilder builder = NbtMap.builder(); + javaValue.forEach(builder::put); return builder.build(); } @@ -291,21 +258,21 @@ public abstract class ItemTranslator { return new NbtList(type, 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(); + public com.github.steveice10.opennbt.tag.builtin.CompoundTag translateToJavaNBT(String name, NbtMap tag) { + com.github.steveice10.opennbt.tag.builtin.CompoundTag javaTag = new com.github.steveice10.opennbt.tag.builtin.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); + com.github.steveice10.opennbt.tag.builtin.Tag translatedTag = translateToJavaNBT(str, bedrockTag); if (translatedTag == null) continue; @@ -317,7 +284,7 @@ public abstract class ItemTranslator { return javaTag; } - private Tag translateToJavaNBT(String name, Object object) { + private com.github.steveice10.opennbt.tag.builtin.Tag translateToJavaNBT(String name, Object object) { if (object instanceof int[]) { return new IntArrayTag(name, (int[]) object); } @@ -359,10 +326,10 @@ public abstract class ItemTranslator { } if (object instanceof List) { - List tags = new ArrayList<>(); + List tags = new ArrayList<>(); for (Object value : (List) object) { - Tag javaTag = translateToJavaNBT("", value); + com.github.steveice10.opennbt.tag.builtin.Tag javaTag = translateToJavaNBT("", value); if (javaTag != null) tags.add(javaTag); } @@ -385,17 +352,26 @@ public abstract class ItemTranslator { public static void translateDisplayProperties(GeyserSession session, CompoundTag tag) { if (tag != null) { CompoundTag display = tag.get("display"); - if (display != null && display.contains("Name")) { + if (display != null && !display.isEmpty() && 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()); + // If its not a message convert it + if (!MessageUtils.isMessage(name)) { + TextComponent component = LegacyComponentSerializer.legacySection().deserialize(name); + name = GsonComponentSerializer.gson().serialize(component); + } - // Add the new name tag - display.put(new StringTag("Name", name)); + // Check if its a message to translate + if (MessageUtils.isMessage(name)) { + // Get the translated name + name = MessageUtils.getTranslatedBedrockMessage(MessageSerializer.fromString(name), session.getClientData().getLanguageCode()); - // Add to the new root tag - tag.put(display); + // Add the new name tag + display.put(new StringTag("Name", name)); + + // Add to the new root tag + tag.put(display); + } } } } 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..89d41e98 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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 index 16cbc54a..a17fbd5f 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/item/RecipeRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/item/RecipeRegistry.java index 7e307281..191b285c 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,80 +34,36 @@ import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; import java.io.InputStream; -import java.util.*; +import java.util.List; +import java.util.UUID; /** * 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<>(); + public static 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<>(); + public static List FIREWORK_ROCKET_RECIPES = new ObjectArrayList<>(21); /** * 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<>(); + public static List FIREWORK_STAR_RECIPES = new ObjectArrayList<>(40); /** * 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; - + public static List SHULKER_BOX_DYEING_RECIPES = new ObjectArrayList<>(); 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"); @@ -132,12 +88,6 @@ public class RecipeRegistry { 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)); - } } /** @@ -147,48 +97,18 @@ public class RecipeRegistry { */ 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)); } + UUID uuid = UUID.randomUUID(); 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++); + inputs.toArray(new ItemData[0]), new ItemData[]{output}, uuid, "crafting_table", 0); } return CraftingData.fromShapeless(uuid.toString(), - inputs, Collections.singletonList(output), uuid, "crafting_table", 0, LAST_RECIPE_NET_ID++); + inputs.toArray(new ItemData[0]), new ItemData[]{output}, uuid, "crafting_table", 0); } public static void init() { 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..10edcdec 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +32,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..304ea3fb 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,20 @@ 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.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.NbtList; import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import org.geysermc.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,44 +49,54 @@ 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()); + 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); + + ItemData itemData = super.translateToBedrock(itemStack, itemEntry); + + CompoundTag blockEntityTag = itemStack.getNbt().get("BlockEntityTag"); + if (blockEntityTag.contains("Patterns")) { + ListTag patterns = blockEntityTag.get("Patterns"); + + NbtMapBuilder builder = itemData.getTag().toBuilder(); + builder.put("Patterns", convertBannerPattern(patterns)); + + itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build()); + } + + return itemData; + } + + @Override + public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { + if (itemData.getTag() == null) return super.translateToJava(itemData, itemEntry); + + ItemStack itemStack = super.translateToJava(itemData, itemEntry); + + NbtMap nbtTag = itemData.getTag(); + if (nbtTag.containsKey("Patterns", NbtType.COMPOUND)) { + List patterns = nbtTag.getList("Patterns", NbtType.COMPOUND); + + CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); + blockEntityTag.put(convertBannerPattern(patterns)); + + itemStack.getNbt().put(blockEntityTag); + } + + return itemStack; + } + + @Override + public List getAppliedItems() { + return appliedItems; } /** @@ -93,7 +107,7 @@ public class BannerTranslator extends ItemTranslator { */ public static NbtList convertBannerPattern(ListTag patterns) { List tagsList = new ArrayList<>(); - for (Tag patternTag : patterns.getValue()) { + for (com.github.steveice10.opennbt.tag.builtin.Tag patternTag : patterns.getValue()) { NbtMap newPatternTag = getBedrockBannerPattern((CompoundTag) patternTag); if (newPatternTag != null) { tagsList.add(newPatternTag); @@ -119,6 +133,7 @@ public class BannerTranslator extends ItemTranslator { return NbtMap.builder() .putInt("Color", 15 - (int) pattern.get("Color").getValue()) + .putString("Pattern", (String) pattern.get("Pattern").getValue()) .putString("Pattern", patternName) .build(); } @@ -132,7 +147,8 @@ public class BannerTranslator extends ItemTranslator { public static ListTag convertBannerPattern(List patterns) { List tagsList = new ArrayList<>(); for (Object patternTag : patterns) { - tagsList.add(getJavaBannerPattern((NbtMap) patternTag)); + CompoundTag newPatternTag = getJavaBannerPattern((NbtMap) patternTag); + tagsList.add(newPatternTag); } return new ListTag("Patterns", tagsList); @@ -151,64 +167,4 @@ public class BannerTranslator extends ItemTranslator { return new CompoundTag("", tags); } - - @Override - public ItemData translateToBedrock(ItemStack itemStack, ItemEntry 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")) { - 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)); - } - - itemData = ItemData.of(itemData.getId(), itemData.getDamage(), itemData.getCount(), builder.build()); - } - - return itemData; - } - - @Override - public ItemStack translateToJava(ItemData itemData, ItemEntry 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); - - CompoundTag blockEntityTag = new CompoundTag("BlockEntityTag"); - blockEntityTag.put(convertBannerPattern(patterns)); - - itemStack.getNbt().put(blockEntityTag); - } - - return itemStack; - } - - @Override - public List getAppliedItems() { - return appliedItems; - } } 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 index 9e3bf7d4..675d4255 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -40,7 +40,7 @@ import java.util.stream.Collectors; @ItemRemapper public class CompassTranslator extends ItemTranslator { - private final List appliedItems; + private List appliedItems; public CompassTranslator() { appliedItems = ItemRegistry.ITEM_ENTRIES.values().stream().filter(entry -> entry.getJavaIdentifier().endsWith("compass")).collect(Collectors.toList()); @@ -53,7 +53,7 @@ public class CompassTranslator extends ItemTranslator { Tag lodestoneTag = itemStack.getNbt().get("LodestoneTracked"); if (lodestoneTag instanceof ByteTag) { // Get the fake lodestonecompass entry - itemEntry = ItemRegistry.getItemEntry("minecraft:lodestone_compass"); + itemEntry = ItemRegistry.getItemEntry("minecraft:lodestonecompass"); // Get the loadstone pos CompoundTag loadstonePos = itemStack.getNbt().get("LodestonePos"); @@ -83,7 +83,7 @@ public class CompassTranslator extends ItemTranslator { @Override public ItemStack translateToJava(ItemData itemData, ItemEntry itemEntry) { boolean isLoadstone = false; - if (itemEntry.getBedrockIdentifier().equals("minecraft:lodestone_compass")) { + if (itemEntry.getJavaIdentifier().equals("minecraft:lodestonecompass")) { // Revert the entry back to the compass itemEntry = ItemRegistry.getItemEntry("minecraft:compass"); 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..7cb88d70 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 @@ -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..e4556626 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 @@ -37,6 +37,7 @@ 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.MessageUtils; import java.util.ArrayList; import java.util.List; @@ -100,14 +101,14 @@ public class BasicItemTranslator extends NbtItemStackTranslator { if (message.startsWith("§r")) { message = message.replaceFirst("§r", ""); } - Component component = Component.text(message); + Component component = TextComponent.of(message); return GsonComponentSerializer.gson().serialize(component); } private String toBedrockMessage(StringTag tag) { String message = tag.getValue(); if (message == null) return null; - TextComponent component = (TextComponent) GsonComponentSerializer.gson().deserialize(message); + TextComponent component = (TextComponent) MessageUtils.phraseJavaMessage(message); String legacy = LegacyComponentSerializer.legacySection().serialize(component); if (hasFormatting(LegacyComponentSerializer.legacySection().deserialize(legacy))) { return "§r" + 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..41ee4fbc 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 @@ -33,7 +33,7 @@ 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; @@ -56,7 +56,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 +78,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..979c5a20 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,15 +25,14 @@ 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 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.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; +import org.geysermc.connector.network.translators.item.ItemEntry; @ItemRemapper public class CrossbowTranslator extends NbtItemStackTranslator { @@ -45,17 +44,12 @@ public class CrossbowTranslator extends NbtItemStackTranslator { 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..990d5a7a 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 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..6884c00b 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 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..3b453ea1 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 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..93af3e70 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 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..c9b49efd 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,7 +25,10 @@ package org.geysermc.connector.network.translators.item.translators.nbt; -import com.github.steveice10.opennbt.tag.builtin.*; +import com.github.steveice10.opennbt.tag.builtin.ByteTag; +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.LongTag; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.ItemEntry; @@ -36,22 +39,14 @@ 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; + 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 LongTag("map_uuid", mapId.getValue())); + 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 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 index 5ddaa997..1780537c 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -26,6 +26,7 @@ package org.geysermc.connector.network.translators.item.translators.nbt; import com.github.steveice10.opennbt.tag.builtin.*; +import com.nukkitx.protocol.bedrock.packet.StartGamePacket; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.ItemRemapper; import org.geysermc.connector.network.translators.item.ItemEntry; @@ -41,7 +42,6 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { 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 @@ -50,8 +50,15 @@ public class ShulkerBoxItemTranslator extends NbtItemStackTranslator { boxItemTag.put(new ByteTag("WasPickedUp", (byte) 0)); // ??? ItemEntry boxItemEntry = ItemRegistry.getItemEntry(((StringTag) itemData.get("id")).getValue()); + String blockName = ""; + for (StartGamePacket.ItemEntry startGamePacketItemEntry : ItemRegistry.ITEMS) { + if (startGamePacketItemEntry.getId() == (short) boxItemEntry.getBedrockId()) { + blockName = startGamePacketItemEntry.getIdentifier(); // Find the Bedrock string name + break; + } + } - boxItemTag.put(new StringTag("Name", boxItemEntry.getBedrockIdentifier())); + boxItemTag.put(new StringTag("Name", blockName)); boxItemTag.put(new ShortTag("Damage", (short) boxItemEntry.getBedrockData())); boxItemTag.put(new ByteTag("Count", ((ByteTag) itemData.get("Count")).getValue())); if (itemData.contains("tag")) { 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..d222d729 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,15 @@ package org.geysermc.connector.network.translators.java; +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 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 java.util.List; @Translator(packet = ServerChatPacket.class) public class JavaChatTranslator extends PacketTranslator { @@ -56,8 +59,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()).getWith(), locale, packet.getMessage()); + textPacket.setParameters(paramsTranslated); + + textPacket.setMessage(MessageUtils.insertParams(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, true, packet.getMessage()), paramsTranslated)); + } else { + textPacket.setNeedsTranslation(false); + + textPacket.setMessage(MessageUtils.getTranslatedBedrockMessage(packet.getMessage(), locale, false, packet.getMessage())); + } 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..beed8232 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 @@ -33,97 +33,57 @@ 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.packet.AvailableCommandsPacket; +import it.unimi.dsi.fastutil.Hash; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import lombok.Getter; 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.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 { - @Override - public void translate(ServerDeclareCommandsPacket packet, GeyserSession session) { - // Don't send command suggestions if they are disabled - if (!session.getConnector().getConfig().isCommandSuggestions()) { - session.getConnector().getLogger().debug("Not sending translated command suggestions as they are disabled."); - // Send an empty packet so Bedrock doesn't override /help with its own, built-in help command. - AvailableCommandsPacket emptyPacket = new AvailableCommandsPacket(); - session.sendUpstreamPacket(emptyPacket); - return; + private static final String[] ENUM_BOOLEAN = {"true", "false"}; + + private static final Hash.Strategy PARAM_STRATEGY = new Hash.Strategy() { + @Override + public int hashCode(CommandParamData[][] o) { + return Arrays.deepHashCode(o); } - List commandData = new ArrayList<>(); - Int2ObjectMap commands = new Int2ObjectOpenHashMap<>(); - Int2ObjectMap> commandArgs = new Int2ObjectOpenHashMap<>(); + @Override + public boolean equals(CommandParamData[][] a, CommandParamData[][] b) { + if (a == b) return true; + if (a == null || b == null) return false; + if (a.length != b.length) return false; + for (int i = 0; i < a.length; i++) { + CommandParamData[] a1 = a[i]; + CommandParamData[] b1 = b[i]; + if (a1.length != b1.length) return false; - // Get the first node, it should be a root node - CommandNode rootNode = packet.getNodes()[packet.getFirstNodeIndex()]; - - // Loop through the root nodes to get all commands - for (int nodeIndex : rootNode.getChildIndices()) { - CommandNode node = packet.getNodes()[nodeIndex]; - - // Make sure we don't have duplicated commands (happens if there is more than 1 root node) - if (commands.containsKey(nodeIndex)) { continue; } - if (commands.containsValue(node.getName())) { continue; } - - // Get and update the commandArgs list with the found arguments - if (node.getChildIndices().length >= 1) { - for (int childIndex : node.getChildIndices()) { - commandArgs.putIfAbsent(nodeIndex, new ArrayList<>()); - commandArgs.get(nodeIndex).add(packet.getNodes()[childIndex]); + for (int i2 = 0; i2 < a1.length; i2++) { + if (!a1[i].equals(b1[i])) return false; } } - - // Insert the command name into the list - commands.put(nodeIndex, node.getName()); + return true; } - - // The command flags, not sure what these do apart from break things - List flags = Collections.emptyList(); - - // 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); - - // Get and parse all params - CommandParamData[][] params = getParams(packet.getNodes()[commandID], packet.getNodes()); - - // Build the completed command and add it to the final list - CommandData data = new CommandData(commandName, session.getConnector().getCommandManager().getDescription(commandName), flags, (byte) 0, aliases, params); - commandData.add(data); - } - - // Add our commands to the AvailableCommandsPacket for the bedrock client - AvailableCommandsPacket availableCommandsPacket = new AvailableCommandsPacket(); - availableCommandsPacket.getCommands().addAll(commandData); - - GeyserConnector.getInstance().getLogger().debug("Sending command packet of " + commandData.size() + " commands"); - - // Finally, send the commands to the client - session.sendUpstreamPacket(availableCommandsPacket); - } + }; /** * Build the command parameter array for the given command * * @param commandNode The command to build the parameters for - * @param allNodes Every command node - * + * @param allNodes Every command node * @return An array of parameter option arrays */ - private CommandParamData[][] getParams(CommandNode commandNode, CommandNode[] allNodes) { + private static CommandParamData[][] getParams(CommandNode commandNode, CommandNode[] allNodes) { // Check if the command is an alias and redirect it if (commandNode.getRedirectIndex() != -1) { GeyserConnector.getInstance().getLogger().debug("Redirecting command " + commandNode.getName() + " to " + allNodes[commandNode.getRedirectIndex()].getName()); @@ -136,16 +96,8 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator treeData = rootParam.getTree(); - CommandParamData[][] params = new CommandParamData[treeData.size()][]; - // Fill the nested params array - int i = 0; - for (CommandParamData[] tree : treeData) { - params[i] = tree; - i++; - } - - return params; + return treeData.toArray(new CommandParamData[0][]); } return new CommandParamData[0][0]; @@ -155,14 +107,17 @@ public class JavaDeclareCommandsTranslator extends PacketTranslator commandData = new ArrayList<>(); + IntSet commandNodes = new IntOpenHashSet(); + Set knownAliases = new HashSet<>(); + Map> commands = new Object2ObjectOpenCustomHashMap<>(PARAM_STRATEGY); + Int2ObjectMap> commandArgs = new Int2ObjectOpenHashMap<>(); + + // Get the first node, it should be a root node + CommandNode rootNode = nodes[packet.getFirstNodeIndex()]; + + // Loop through the root nodes to get all commands + for (int nodeIndex : rootNode.getChildIndices()) { + CommandNode node = nodes[nodeIndex]; + + // Make sure we don't have duplicated commands (happens if there is more than 1 root node) + if (!commandNodes.add(nodeIndex) || !knownAliases.add(node.getName().toLowerCase())) continue; + + // Get and update the commandArgs list with the found arguments + if (node.getChildIndices().length >= 1) { + for (int childIndex : node.getChildIndices()) { + commandArgs.putIfAbsent(nodeIndex, new ArrayList<>()); + commandArgs.get(nodeIndex).add(nodes[childIndex]); + } + } + + // Get and parse all params + CommandParamData[][] params = getParams(nodes[nodeIndex], nodes); + + // Insert the alias name into the command list + commands.computeIfAbsent(params, index -> new HashSet<>()).add(node.getName().toLowerCase()); + } + + // The command flags, not sure what these do apart from break things + List flags = new ArrayList<>(); + + // Loop through all the found commands + + for (Map.Entry> entry : commands.entrySet()) { + String commandName = entry.getValue().iterator().next(); // We know this has a value + + // Create a basic alias + CommandEnumData aliases = new CommandEnumData(commandName + "Aliases", entry.getValue().toArray(new String[0]), false); + + // Build the completed command and add it to the final list + CommandData data = new CommandData(commandName, session.getConnector().getCommandManager().getDescription(commandName), flags, (byte) 0, aliases, entry.getKey()); + commandData.add(data); + } + + // Add our commands to the AvailableCommandsPacket for the bedrock client + AvailableCommandsPacket availableCommandsPacket = new AvailableCommandsPacket(); + for (CommandData data : commandData) { + availableCommandsPacket.getCommands().add(data); + } + + GeyserConnector.getInstance().getLogger().debug("Sending command packet of " + commandData.size() + " commands"); + + // Finally, send the commands to the client + session.sendUpstreamPacket(availableCommandsPacket); + } + @Getter - private class ParamInfo { + private static class ParamInfo { private CommandNode paramNode; private CommandParamData paramData; private List children; @@ -262,8 +286,17 @@ public class JavaDeclareCommandsTranslator 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..a8fc122b 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 @@ -28,18 +28,16 @@ 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.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 java.util.Arrays; import java.util.List; @@ -55,12 +53,12 @@ public class JavaJoinGameTranslator extends PacketTranslator skinParts = Arrays.asList(SkinPart.values()); ClientSettingsPacket clientSettingsPacket = new ClientSettingsPacket(locale, (byte) session.getRenderDistance(), ChatVisibility.FULL, true, skinParts, HandPreference.RIGHT_HAND); session.sendDownstreamPacket(clientSettingsPacket); - session.sendDownstreamPacket(new ClientPluginMessagePacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData())); - - if (!newDimension.equals(session.getDimension())) { + if (!newDimension.equals(entity.getDimension())) { DimensionUtils.switchDimension(session, newDimension); } } 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 index 3433edcc..d4504226 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,7 +29,7 @@ import com.github.steveice10.mc.protocol.packet.login.server.LoginDisconnectPack 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; @Translator(packet = LoginDisconnectPacket.class) public class JavaLoginDisconnectTranslator extends PacketTranslator { @@ -37,6 +37,6 @@ public class JavaLoginDisconnectTranslator 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..11e7744d 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 @@ -43,6 +43,8 @@ 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 @@ -64,24 +66,18 @@ public class JavaRespawnTranslator extends PacketTranslator session.setRaining(false); } - 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); - DimensionUtils.switchDimension(session, fakeDim); - } - session.setWorldName(packet.getWorldName()); + if (!entity.getDimension().equals(newDimension)) { DimensionUtils.switchDimension(session, newDimension); + } else { + if (session.isManyDimPackets()) { //reloading world + String fakeDim = entity.getDimension().equals(DimensionUtils.OVERWORLD) ? DimensionUtils.NETHER : DimensionUtils.OVERWORLD; + DimensionUtils.switchDimension(session, fakeDim); + DimensionUtils.switchDimension(session, newDimension); + } else { + // Handled in JavaPlayerPositionRotationTranslator + session.setSpawned(false); + } } } } 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..6a885e90 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,23 +39,16 @@ 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); - } + String locale = session.getClientData().getLanguageCode(); switch (packet.getAction()) { case TITLE: titlePacket.setType(SetTitlePacket.Type.TITLE); - titlePacket.setText(text); + titlePacket.setText(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), locale)); break; case SUBTITLE: titlePacket.setType(SetTitlePacket.Type.SUBTITLE); - titlePacket.setText(text); + titlePacket.setText(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), locale)); break; case CLEAR: case RESET: @@ -64,10 +57,9 @@ public class JavaTitleTranslator extends PacketTranslator { break; case ACTION_BAR: titlePacket.setType(SetTitlePacket.Type.ACTIONBAR); - titlePacket.setText(text); + titlePacket.setText(MessageUtils.getTranslatedBedrockMessage(packet.getTitle(), locale)); 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..b642a75b 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -62,7 +62,7 @@ public class JavaEntityAttachTranslator extends PacketTranslator { @@ -41,7 +43,7 @@ public class JavaEntityEffectTranslator extends PacketTranslator { @@ -41,7 +43,7 @@ public class JavaEntityRemoveEffectTranslator extends PacketTranslator 1)); rider = false; } @@ -99,9 +90,6 @@ public class JavaEntitySetPassengersTranslator extends PacketTranslator 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 LLAMA: + case TRADER_LLAMA: + yOffset = 2.5f; + break; + case PIG: + yOffset = 1.85001f; + break; + case ARMOR_STAND: + yOffset = 1.3f; break; case STRIDER: - mountedHeightOffset = height - 0.19f; + yOffset = passenger.getEntityType() == EntityType.PLAYER ? 2.8200102f : 1.6f; 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; + Vector3f offset = Vector3f.from(0f, yOffset, 0f); + if (mountType == EntityType.STRIDER) { + offset = offset.add(0f, 0f, -0.2f); } - if (passenger instanceof AnimalEntity) { - return 0.14f; + // 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..ac2a80f7 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 @@ -26,21 +26,16 @@ 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.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 org.geysermc.connector.network.translators.item.ItemRegistry; @Translator(packet = ServerEntityStatusPacket.class) public class JavaEntityStatusTranslator extends PacketTranslator { @@ -89,27 +84,10 @@ public class JavaEntityStatusTranslator extends PacketTranslator { 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..9ed11a23 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,19 +82,24 @@ public class JavaPlayerListEntryTranslator 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..d9c859d3 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 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..5e33c8a1 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 diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java index 1abe9937..5fe3847f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPaintingTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/JavaSpawnPlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java index 97d69a63..47beca8a 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -28,12 +28,12 @@ package org.geysermc.connector.network.translators.java.entity.spawn; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket; import com.nukkitx.math.vector.Vector3f; import org.geysermc.connector.GeyserConnector; -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.LanguageUtils; -import org.geysermc.connector.skin.SkinManager; +import org.geysermc.connector.utils.SkinUtils; @Translator(packet = ServerSpawnPlayerPacket.class) public class JavaSpawnPlayerTranslator extends PacketTranslator { @@ -43,26 +43,20 @@ public class JavaSpawnPlayerTranslator 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())); - } - - int pps = session.getWorldCache().increaseAndGetScoreboardPacketsPerSecond(); + GeyserConnector.getInstance().getLogger().debug("Team packet " + packet.getTeamName() + " " + packet.getAction() + " " + Arrays.toString(packet.getPlayers())); Scoreboard scoreboard = session.getWorldCache().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.getTranslatedBedrockMessage(packet.getPrefix(), session.getClientData().getLanguageCode())) + .setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode())); 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.getTranslatedBedrockMessage(packet.getPrefix(), session.getClientData().getLanguageCode())) + .setSuffix(MessageUtils.getTranslatedBedrockMessage(packet.getSuffix(), session.getClientData().getLanguageCode())) + .setUpdateType(UpdateType.UPDATE); + } else { + GeyserConnector.getInstance().getLogger().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); } - - 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().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); } - 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().debug(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_not_registered", packet.getAction(), packet.getTeamName())); } - 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..8d7d59a8 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,48 @@ 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 com.github.steveice10.mc.protocol.data.game.scoreboard.ScoreboardAction; +import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; import org.geysermc.connector.utils.LanguageUtils; @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.getWorldCache().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(LanguageUtils.getLocaleStringLog("geyser.network.translator.score.failed_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..02e6514d 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/JavaBlockChangeTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java index d74165b1..9e81ce59 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/world/JavaBlockChangeTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.network.translators.java.world; import com.github.steveice10.mc.protocol.data.game.entity.metadata.Position; -import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket; import com.nukkitx.math.vector.Vector3i; import com.nukkitx.protocol.bedrock.data.SoundEvent; import com.nukkitx.protocol.bedrock.packet.LevelSoundEventPacket; -import org.geysermc.common.PlatformType; +import org.geysermc.connector.common.PlatformType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; import org.geysermc.connector.network.translators.Translator; @@ -38,17 +37,17 @@ import org.geysermc.connector.network.translators.sound.BlockSoundInteractionHan import org.geysermc.connector.network.translators.world.block.BlockTranslator; import org.geysermc.connector.utils.ChunkUtils; +import com.github.steveice10.mc.protocol.packet.ingame.server.world.ServerBlockChangePacket; + @Translator(packet = ServerBlockChangePacket.class) public class JavaBlockChangeTranslator 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()) == packet.getRecord().getBlock()); + ChunkUtils.updateBlock(session, packet.getRecord().getBlock(), packet.getRecord().getPosition()); + if (updatePlacement && session.getConnector().getPlatformType() != PlatformType.SPIGOT) { 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..3d3df51c 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,7 +25,6 @@ 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; @@ -54,12 +53,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 +73,14 @@ 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 +51,52 @@ 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 (NbtMap blockEntity : chunkData.getBlockEntities()) { + nbtStream.writeTag(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); + + 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..efed6ba4 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -46,7 +46,7 @@ public class JavaExplosionTranslator extends PacketTranslator boolean shouldStore = false; mapItemDataPacket.setUniqueMapId(packet.getMapId()); - mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getDimension())); + mapItemDataPacket.setDimensionId(DimensionUtils.javaToBedrock(session.getPlayerEntity().getDimension())); mapItemDataPacket.setLocked(packet.isLocked()); mapItemDataPacket.setScale(packet.getScale()); 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..33e602eb 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 @@ -38,12 +38,11 @@ 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.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.network.translators.inventory.PlayerInventoryTranslator; -import org.geysermc.connector.utils.LocaleUtils; @Translator(packet = ServerNotifyClientPacket.class) public class JavaNotifyClientTranslator extends PacketTranslator { @@ -103,13 +102,15 @@ public class JavaNotifyClientTranslator extends PacketTranslator { @@ -82,11 +82,7 @@ public class JavaPlayBuiltinSoundTranslator extends PacketTranslator params = new ArrayList<>(); String recordString = "%item." + soundEvent.name().toLowerCase(Locale.ROOT) + ".desc"; - params.add(LocaleUtils.getLocaleString(recordString, session.getLocale())); + params.add(LocaleUtils.getLocaleString(recordString, session.getClientData().getLanguageCode())); textPacket.setParameters(params); session.sendUpstreamPacket(textPacket); } 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 92% 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..1d5ea4f5 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,14 +36,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..52d3f649 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 @@ -78,7 +78,7 @@ public class JavaSpawnParticleTranslator extends PacketTranslator 0 ? packet.getVillagerLevel() - 1 : 0); // -1 crashes client + recipe.putInt("tier", packet.getVillagerLevel() - 1); recipe.put("buyA", getItemTag(session, trade.getFirstInput(), trade.getSpecialPrice())); if (trade.getSecondInput() != null) { recipe.put("buyB", getItemTag(session, trade.getSecondInput(), 0)); @@ -139,7 +131,7 @@ public class JavaTradeListTranslator 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..ae4ed779 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,28 +25,17 @@ 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) { @@ -55,30 +44,15 @@ public class JavaUpdateTileEntityTranslator extends PacketTranslator= 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.containsKey(packet.getPosition())) { + int blockState = ChunkUtils.CACHED_BLOCK_ENTITIES.getOrDefault(packet.getPosition(), 0); + BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), + blockState), packet.getPosition()); + ChunkUtils.CACHED_BLOCK_ENTITIES.remove(packet.getPosition(), blockState); + } else { + BlockEntityUtils.updateBlockEntity(session, translator.getBlockEntityTag(id, packet.getNbt(), 0), 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..8dc68918 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,49 @@ 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) { + session.sendGameRule("dodaylightcycle", doCycle); + } + } 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..782b9039 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/BlockSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/BlockSoundInteractionHandler.java index 5ef00449..f3dff0cc 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/EntitySoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/EntitySoundInteractionHandler.java index 484936e5..fbc3b26b 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/SoundHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandler.java index 4af1b820..05ec1194 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/SoundHandlerRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundHandlerRegistry.java index 6cfb9767..893975e5 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,6 @@ 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 +38,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..f5339cf1 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/SoundRegistry.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/SoundRegistry.java index 8ebca00e..1c91498b 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/block/BucketSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/BucketSoundInteractionHandler.java index bad9b41d..ed51297e 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -38,7 +38,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 +68,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..6f80c6ae 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/block/DoorSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/DoorSoundInteractionHandler.java index 8c6c62f0..10d4bb89 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -37,7 +37,6 @@ 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.setPosition(position); 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..0d417750 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/block/GrassPathInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/GrassPathInteractionHandler.java index 328dbfbf..13e3ba3d 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/block/HoeInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/HoeInteractionHandler.java index 30fe94b5..c465f31a 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/block/LeverSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/block/LeverSoundInteractionHandler.java index 83fe79f2..3ff77c8c 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/sound/entity/MilkCowSoundInteractionHandler.java b/connector/src/main/java/org/geysermc/connector/network/translators/sound/entity/MilkCowSoundInteractionHandler.java index e2dcf29a..852ad3fa 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/GeyserWorldManager.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/GeyserWorldManager.java index 5507b778..83f1a778 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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.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.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.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 { @@ -42,50 +40,7 @@ public class GeyserWorldManager extends WorldManager { @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]; + return session.getChunkCache().getBlockAt(new Position(x, y, z)); } @Override 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..32601227 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,7 +25,6 @@ package org.geysermc.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; @@ -43,7 +42,7 @@ import org.geysermc.connector.utils.GameRule; public abstract class WorldManager { /** - * Gets the Java block state at the specified location + * Gets the block state at the specified location * * @param session the session * @param position the position @@ -54,7 +53,7 @@ public abstract class WorldManager { } /** - * Gets the Java block state at the specified location + * Gets the block state at the specified location * * @param session the session * @param vector the position @@ -65,7 +64,7 @@ public abstract class WorldManager { } /** - * Gets the Java block state at the specified location + * Gets the block state at the specified location * * @param session the session * @param x the x coordinate to get the block at @@ -75,37 +74,6 @@ public abstract class WorldManager { */ 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 * @@ -116,7 +84,7 @@ public abstract class WorldManager { public abstract void setGameRule(GeyserSession session, String name, Object value); /** - * Gets a gamerule value as a boolean + * Get 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 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..53607317 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 @@ -36,9 +36,9 @@ 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 Int2ObjectMap DOUBLE_CHEST_VALUES = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap FLOWER_POT_VALUES = new Int2ObjectOpenHashMap<>(); private static final Map FLOWER_POT_BLOCKS = new HashMap<>(); @@ -47,13 +47,11 @@ public class BlockStateValues { 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(); /** * 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) { @@ -69,11 +67,6 @@ 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()) || @@ -102,7 +95,7 @@ public class BlockStateValues { } JsonNode skullVariation = entry.getValue().get("variation"); - if (skullVariation != null) { + if(skullVariation != null) { SKULL_VARIANTS.put(javaBlockState, (byte) skullVariation.intValue()); } @@ -111,26 +104,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()); @@ -145,7 +118,10 @@ public class BlockStateValues { * @return Banner color integer or -1 if no color */ public static int getBannerColor(int state) { - return BANNER_COLORS.getOrDefault(state, -1); + if (BANNER_COLORS.containsKey(state)) { + return BANNER_COLORS.get(state); + } + return -1; } /** @@ -156,23 +132,15 @@ public class BlockStateValues { * @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; + if (BED_COLORS.containsKey(state)) { + return BED_COLORS.get(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 +149,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,7 +157,6 @@ public class BlockStateValues { /** * Get the map of contained flower pot plants to Bedrock CompoundTag - * * @return Map of flower pot blocks. */ public static Map getFlowerPotBlocks() { @@ -200,17 +166,18 @@ public class BlockStateValues { /** * 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); + if (NOTEBLOCK_PITCHES.containsKey(state)) { + return NOTEBLOCK_PITCHES.get(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() { @@ -229,7 +196,10 @@ public class BlockStateValues { * @return Skull variant byte or -1 if no variant */ public static byte getSkullVariant(int state) { - return SKULL_VARIANTS.getOrDefault(state, (byte) -1); + if (SKULL_VARIANTS.containsKey(state)) { + return SKULL_VARIANTS.get(state); + } + return -1; } /** @@ -240,18 +210,12 @@ public class BlockStateValues { * @return Skull rotation value or -1 if no value */ public static byte getSkullRotation(int state) { - return SKULL_ROTATIONS.getOrDefault(state, (byte) -1); + if (SKULL_ROTATIONS.containsKey(state)) { + return SKULL_ROTATIONS.get(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. @@ -261,6 +225,9 @@ public class BlockStateValues { * @return Shulker direction value or -1 if no value */ public static byte getShulkerBoxDirection(int state) { - return SHULKERBOX_DIRECTIONS.getOrDefault(state, (byte) -1); + if (SHULKERBOX_DIRECTIONS.containsKey(state)) { + return SHULKERBOX_DIRECTIONS.get(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..e627b845 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 @@ -28,39 +28,30 @@ package org.geysermc.connector.network.translators.world.block; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; -import com.nukkitx.nbt.*; +import com.nukkitx.nbt.NBTInputStream; +import com.nukkitx.nbt.NbtList; +import com.nukkitx.nbt.NbtMap; +import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtType; +import com.nukkitx.nbt.NbtUtils; 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 NbtList BLOCKS; + public static final int AIR = 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 IntSet WATERLOGGED = new IntOpenHashSet(); private static final Object2IntMap ITEM_FRAMES = new Object2IntOpenHashMap<>(); @@ -68,28 +59,13 @@ public class BlockTranslator { // Bedrock carpet ID, used in LlamaEntity.java for decoration public static final int CARPET = 171; + private static final Int2ObjectMap JAVA_ID_TO_BLOCK_ENTITY_MAP = new Int2ObjectOpenHashMap<>(); + 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 = 17825806; 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); + try (NBTInputStream nbtInputStream = NbtUtils.createNetworkReader(stream)) { + blocksTag = (NbtList) 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 (NbtMap tag : blocksTag) { + 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,26 @@ 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!"); - } // TODO fix this, (no block should have a null hardness) JsonNode hardnessNode = entry.getValue().get("block_hardness"); @@ -173,36 +140,33 @@ public class BlockTranslator { 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); + // 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(javaRuntimeId, clazz.getAnnotation(BlockEntity.class).name()); + break; + } + } + 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); - } - - String bedrockIdentifier = entry.getValue().get("bedrock_identifier").asText(); - - if (!cleanJavaIdentifier.equals(bedrockIdentifier)) { - JAVA_TO_BEDROCK_IDENTIFIERS.put(cleanJavaIdentifier, bedrockIdentifier); - } - // 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)) { @@ -218,30 +182,34 @@ public class BlockTranslator { BEDROCK_TO_JAVA_BLOCK_MAP.putIfAbsent(bedrockRuntimeId, javaRuntimeId); } + NbtMap 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 +217,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 +237,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 (NbtMap tag : paletteList) { + NbtMap blockTag = tag.getCompound("block"); + if (blockTag.getString("name").equals("minecraft:frame")) { + ITEM_FRAMES.put(tag, frameRuntimeId); } + frameRuntimeId++; } + + BLOCKS = new NbtList<>(NbtType.COMPOUND, paletteList); } private BlockTranslator() { @@ -332,14 +297,6 @@ public class BlockTranslator { 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) { return ITEM_FRAMES.getOrDefault(tag, -1); } @@ -352,12 +309,12 @@ 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); + return JAVA_ID_BLOCK_MAP.get(javaId); + } + + public static String getBlockEntityString(int javaId) { + return JAVA_ID_TO_BLOCK_ENTITY_MAP.get(javaId); } public static boolean isWaterlogged(int state) { @@ -371,19 +328,4 @@ public class BlockTranslator { public static int 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..284f8c57 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/BannerBlockEntityTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/block/entity/BannerBlockEntityTranslator.java index 07760c46..9e86cb4c 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 @@ -27,37 +27,55 @@ package org.geysermc.connector.network.translators.world.block.entity; 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.NbtMap; +import com.nukkitx.nbt.NbtType; 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.HashMap; +import java.util.Map; + @BlockEntity(name = "Banner", regex = "banner") public class BannerBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + @Override public boolean isBlock(int blockState) { return BlockStateValues.getBannerColor(blockState) != -1; } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); + int bannerColor = BlockStateValues.getBannerColor(blockState); if (bannerColor != -1) { - builder.put("Base", 15 - bannerColor); + tags.put("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.put("Patterns", BannerTranslator.convertBannerPattern(patterns)); } if (tag.contains("CustomName")) { - builder.put("CustomName", tag.get("CustomName").getValue()); + tags.put("CustomName", 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 NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putList("Patterns", NbtType.COMPOUND, new ArrayList<>()) + .build(); } } 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..b84aad98 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 @@ -26,23 +26,39 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import java.util.HashMap; +import java.util.Map; + @BlockEntity(name = "Bed", regex = "bed") public class BedBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + @Override public boolean isBlock(int blockState) { return BlockStateValues.getBedColor(blockState) != -1; } @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); byte bedcolor = BlockStateValues.getBedColor(blockState); // Just in case... - if (bedcolor == -1) { - bedcolor = 0; - } - builder.put("color", bedcolor); + if (bedcolor == -1) bedcolor = 0; + tags.put("color", bedcolor); + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putByte("color", (byte) 0) + .build(); } } 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..d2e4537f 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,7 @@ import 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. @@ -48,7 +49,7 @@ public interface BedrockOnlyBlockEntity { * @return Bedrock tag, or null if not a Bedrock-only Block Entity */ static NbtMap getTag(Vector3i position, int blockState) { - if (FlowerPotBlockEntityTranslator.isFlowerBlock(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..c4401c4c 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 @@ -28,29 +28,22 @@ package org.geysermc.connector.network.translators.world.block.entity; 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 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.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<>(); + public static ObjectArrayList REQUIRES_BLOCK_STATE_LIST = new ObjectArrayList<>(); /** * Contains a list of irregular block entity name translations that can't be fit into the regex @@ -59,7 +52,6 @@ public abstract class BlockEntityTranslator { { // 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 @@ -74,7 +66,7 @@ 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()); @@ -84,33 +76,31 @@ public abstract class BlockEntityTranslator { GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.network.translator.block_entity.failed", 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())); } } } - public abstract void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState); + public abstract Map translateTag(CompoundTag tag, int blockState); + + public abstract CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z); + + public abstract NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z); 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(); + 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())); NbtMapBuilder tagBuilder = getConstantBedrockTag(BlockEntityUtils.getBedrockBlockEntityId(id), x, y, z).toBuilder(); - translateTag(tagBuilder, tag, blockState); + Map translatedTags = translateTag(tag, blockState); + translatedTags.forEach(tagBuilder::put); return tagBuilder.build(); } @@ -133,7 +123,7 @@ public abstract class BlockEntityTranslator { } @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..e3d2c9f5 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 @@ -32,22 +32,40 @@ import com.nukkitx.nbt.NbtMapBuilder; import org.geysermc.connector.network.translators.item.ItemEntry; import org.geysermc.connector.network.translators.item.ItemRegistry; +import java.util.HashMap; +import java.util.Map; + @BlockEntity(name = "Campfire", regex = "campfire") public class CampfireBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); 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.put("Item" + i, getItem((CompoundTag) itemTag)); i++; } + 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("Items")); + return tag; + } + + @Override + public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z); } protected NbtMap getItem(CompoundTag tag) { ItemEntry entry = ItemRegistry.getItemEntry((String) tag.get("id").getValue()); NbtMapBuilder tagBuilder = NbtMap.builder() - .putString("Name", entry.getBedrockIdentifier()) + .putShort("id", (short) entry.getBedrockId()) .putByte("Count", (byte) tag.get("Count").getValue()) .putShort("Damage", (short) entry.getBedrockData()); tagBuilder.put("tag", NbtMap.builder().build()); 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..fa8bab3b 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -27,17 +27,22 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.nukkitx.math.vector.Vector3i; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtMapBuilder; 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.HashMap; +import java.util.Map; + /** * 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); @@ -47,39 +52,53 @@ public class DoubleChestBlockEntityTranslator extends BlockEntityTranslator impl public void updateBlock(GeyserSession session, int 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); + translateTag(javaTag, blockState).forEach(tagBuilder::put); BlockEntityUtils.updateBlockEntity(session, tagBuilder.build(), 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 Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); + if (BlockStateValues.getDoubleChestValues().containsKey(blockState)) { + DoubleChestValue chestValues = BlockStateValues.getDoubleChestValues().get(blockState); + 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.put("pairx", x); + tags.put("pairz", z); + if (!chestValues.isLeft) { + tags.put("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 NbtMap 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..6de13611 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 @@ -26,11 +26,26 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtMap; + +import java.util.HashMap; +import java.util.Map; @BlockEntity(name = "Empty", regex = "") public class EmptyBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public Map translateTag(CompoundTag tag, int blockState) { + return new HashMap<>(); + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return getConstantJavaTag(javaId, x, y, z); + } + + @Override + public NbtMap 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..784afed5 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 @@ -26,20 +26,25 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.LongTag; import com.nukkitx.nbt.NbtList; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtMap; import com.nukkitx.nbt.NbtType; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import java.util.Arrays; +import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.Map; @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 Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); + tags.put("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(); @@ -47,16 +52,30 @@ public class EndGatewayBlockEntityTranslator extends BlockEntityTranslator { tagsList.add(getExitPortalCoordinate(tag, "X")); tagsList.add(getExitPortalCoordinate(tag, "Y")); tagsList.add(getExitPortalCoordinate(tag, "Z")); - builder.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList)); + tags.put("ExitPortal", new NbtList<>(NbtType.INT, tagsList)); + 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 NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putList("ExitPortal", NbtType.INT, Arrays.asList(0, 0, 0)) + .build(); } 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); + 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..7bfcc7ee 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 +35,30 @@ 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); + + @Override + public boolean isBlock(int blockState) { + return (BlockStateValues.getFlowerPotValues().containsKey(blockState)); + } + + @Override + public void updateBlock(GeyserSession session, int 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); + session.sendUpstreamPacket(updateBlockPacket); + BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position); } /** * Get the Nukkit CompoundTag of the flower pot. - * * @param blockState Java block state of flower pot. - * @param position Bedrock position of flower pot. + * @param position Bedrock position of flower pot. * @return Bedrock tag of flower pot. */ public static NbtMap getTag(int blockState, Vector3i position) { @@ -69,23 +80,4 @@ public class FlowerPotBlockEntityTranslator implements BedrockOnlyBlockEntity, R } return tagBuilder.build(); } - - @Override - public boolean isBlock(int blockState) { - return isFlowerBlock(blockState); - } - - @Override - public void updateBlock(GeyserSession session, int 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); - session.sendUpstreamPacket(updateBlockPacket); - BlockEntityUtils.updateBlockEntity(session, getTag(blockState, position), position); - } } 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..f3e43009 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,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) { 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); + int blockState = ChunkUtils.CACHED_BLOCK_ENTITIES.getOrDefault(position, 0); 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..54feacbe 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,9 +34,9 @@ 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. */ @@ -46,9 +46,8 @@ public class PistonBlockEntityTranslator { /** * 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 position Bedrock position of piston. * @return Bedrock tag of piston. */ public static NbtMap getTag(int blockState, Vector3i position) { @@ -58,13 +57,14 @@ public class PistonBlockEntityTranslator { .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)); - + if (BlockStateValues.getPistonValues().containsKey(blockState)) { + 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(); } + } 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..0db306aa 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 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..08a7ae18 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,18 +26,35 @@ package org.geysermc.connector.network.translators.world.block.entity; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import com.nukkitx.nbt.NbtMapBuilder; +import com.nukkitx.nbt.NbtMap; import org.geysermc.connector.network.translators.world.block.BlockStateValues; +import java.util.HashMap; +import java.util.Map; + @BlockEntity(name = "ShulkerBox", regex = "shulker_box") public class ShulkerBoxBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { + public Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); + byte direction = BlockStateValues.getShulkerBoxDirection(blockState); // Just in case... - if (direction == -1) { - direction = 1; - } - builder.put("facing", direction); + if (direction == -1) direction = 1; + tags.put("facing", direction); + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putByte("facing", (byte) 1) + .build(); } } 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..ab9ba306 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,22 +25,71 @@ package org.geysermc.connector.network.translators.world.block.entity; +import com.github.steveice10.mc.protocol.data.message.MessageSerializer; 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.NbtMap; +import org.geysermc.connector.utils.MessageUtils; + +import java.util.HashMap; +import java.util.Map; @BlockEntity(name = "Sign", regex = "sign") public class SignBlockEntityTranslator extends BlockEntityTranslator { + + @Override + public Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); + + StringBuilder signText = new StringBuilder(); + for(int i = 0; i < 4; i++) { + int currentLine = i+1; + String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), ""); + signLine = MessageUtils.getBedrockMessage(MessageSerializer.fromString(signLine)); + + //Java allows up to 16+ characters on certain symbols. + if(signLine.length() >= 15 && (signLine.contains("-") || signLine.contains("="))) { + signLine = signLine.substring(0, 14); + } + + // 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(signLine); + signText.append("\n"); + } + + tags.put("Text", MessageUtils.getBedrockMessage(MessageSerializer.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 NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putString("Text", "") + .build(); + } + /** * 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)}. + * The color names correspond to dye names, because of this we can't use {@link MessageUtils#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) { + private static String getBedrockSignColor(String javaColor) { String base = "\u00a7"; switch (javaColor) { case "white": @@ -93,41 +142,4 @@ public class SignBlockEntityTranslator extends BlockEntityTranslator { return base; } - @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - StringBuilder signText = new StringBuilder(); - for (int i = 0; i < 4; i++) { - int currentLine = i + 1; - String signLine = getOrDefault(tag.getValue().get("Text" + currentLine), ""); - signLine = MessageTranslator.convertMessageLenient(signLine); - - // Trim any trailing formatting codes - if (signLine.length() > 2 && signLine.toCharArray()[signLine.length() - 2] == '\u00a7') { - signLine = signLine.substring(0, signLine.length() - 2); - } - - // 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("\n"); - } - - builder.put("Text", signText.toString()); - } } 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..9547ba2f 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,66 @@ -/* - * 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.nukkitx.nbt.NbtMap; +import org.geysermc.connector.network.translators.world.block.BlockStateValues; + +import java.util.HashMap; +import java.util.Map; + +@BlockEntity(name = "Skull", regex = "skull") +public class SkullBlockEntityTranslator extends BlockEntityTranslator implements RequiresBlockState { + + @Override + public boolean isBlock(int blockState) { + return BlockStateValues.getSkullVariant(blockState) != -1; + } + + @Override + public Map translateTag(com.github.steveice10.opennbt.tag.builtin.CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); + byte skullVariant = BlockStateValues.getSkullVariant(blockState); + float rotation = BlockStateValues.getSkullRotation(blockState) * 22.5f; + // Just in case... + if (skullVariant == -1) skullVariant = 0; + tags.put("Rotation", rotation); + tags.put("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 NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putFloat("Rotation", 0f) + .putByte("SkullType", (byte) 0) + .build(); + } +} 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..3c443eee 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,58 +26,76 @@ package org.geysermc.connector.network.translators.world.block.entity; 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.NbtMap; import org.geysermc.connector.entity.type.EntityType; +import java.util.HashMap; +import java.util.Map; + @BlockEntity(name = "MobSpawner", regex = "mob_spawner") public class SpawnerBlockEntityTranslator extends BlockEntityTranslator { + @Override - public void translateTag(NbtMapBuilder builder, CompoundTag tag, int blockState) { - Tag current; + public Map translateTag(CompoundTag tag, int blockState) { + Map tags = new HashMap<>(); - if ((current = tag.get("MaxNearbyEntities")) != null) { - builder.put("MaxNearbyEntities", current.getValue()); + if (tag.get("MaxNearbyEntities") != null) { + tags.put("MaxNearbyEntities", (short) tag.get("MaxNearbyEntities").getValue()); } - if ((current = tag.get("RequiredPlayerRange")) != null) { - builder.put("RequiredPlayerRange", current.getValue()); + if (tag.get("RequiredPlayerRange") != null) { + tags.put("RequiredPlayerRange", (short) tag.get("RequiredPlayerRange").getValue()); } - if ((current = tag.get("SpawnCount")) != null) { - builder.put("SpawnCount", current.getValue()); + if (tag.get("SpawnCount") != null) { + tags.put("SpawnCount", (short) tag.get("SpawnCount").getValue()); } - if ((current = tag.get("MaxSpawnDelay")) != null) { - builder.put("MaxSpawnDelay", current.getValue()); + if (tag.get("MaxSpawnDelay") != null) { + tags.put("MaxSpawnDelay", (short) tag.get("MaxSpawnDelay").getValue()); } - if ((current = tag.get("Delay")) != null) { - builder.put("Delay", current.getValue()); + if (tag.get("Delay") != null) { + tags.put("Delay", (short) tag.get("Delay").getValue()); } - if ((current = tag.get("SpawnRange")) != null) { - builder.put("SpawnRange", current.getValue()); + if (tag.get("SpawnRange") != null) { + tags.put("SpawnRange", (short) tag.get("SpawnRange").getValue()); } - if ((current = tag.get("MinSpawnDelay")) != null) { - builder.put("MinSpawnDelay", current.getValue()); + if (tag.get("MinSpawnDelay") != null) { + tags.put("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.put("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.put("DisplayEntityWidth", type.getWidth()); + tags.put("DisplayEntityHeight", type.getHeight()); + tags.put("DisplayEntityScale", 1.0f); } } - builder.put("id", "MobSpawner"); - builder.put("isMovable", (byte) 1); + tags.put("id", "MobSpawner"); + tags.put("isMovable", (byte) 1); + + return tags; + } + + @Override + public CompoundTag getDefaultJavaTag(String javaId, int x, int y, int z) { + return null; + } + + @Override + public NbtMap getDefaultBedrockTag(String bedrockId, int x, int y, int z) { + return getConstantBedrockTag(bedrockId, x, y, z).toBuilder() + .putByte("isMovable", (byte) 1) + .putString("id", "MobSpawner") + .build(); } } 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..30edf178 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 +29,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 +46,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 +64,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 +84,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/bedrock/BedrockEmoteListTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkPosition.java similarity index 60% 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/world/chunk/ChunkPosition.java index 7e2238f3..a32d9316 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/BedrockEmoteListTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/ChunkPosition.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,31 @@ * @link https://github.com/GeyserMC/Geyser */ -package org.geysermc.connector.network.translators.bedrock; +package org.geysermc.connector.network.translators.world.chunk; -import com.nukkitx.protocol.bedrock.packet.EmoteListPacket; -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.metadata.Position; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; -@Translator(packet = EmoteListPacket.class) -public class BedrockEmoteListTranslator extends PacketTranslator { +@Getter +@Setter +@AllArgsConstructor +@EqualsAndHashCode +public class ChunkPosition { - @Override - public void translate(EmoteListPacket packet, GeyserSession session) { - session.refreshEmotes(packet.getPieceIds()); + 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..48ec8806 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,19 +27,42 @@ 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 +77,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 +109,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 +135,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..37203377 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/chunk/bitarray/BitArray.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArray.java index 5c278eb9..d3f8927d 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/chunk/bitarray/BitArrayVersion.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/BitArrayVersion.java index f45e9f6b..20fa849c 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,8 +37,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 +58,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 +78,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..3068bd68 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/chunk/bitarray/Pow2BitArray.java b/connector/src/main/java/org/geysermc/connector/network/translators/world/chunk/bitarray/Pow2BitArray.java index 1a784b7f..dd679b71 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,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/ping/GeyserLegacyPingPassthrough.java b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java index a8af51bf..519d847d 100644 --- a/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java +++ b/connector/src/main/java/org/geysermc/connector/ping/GeyserLegacyPingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -70,7 +70,7 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn } @Override - public GeyserPingInfo getPingInformation(InetSocketAddress inetSocketAddress) { + public GeyserPingInfo getPingInformation() { return pingInfo; } 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..049f8504 100644 --- a/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java +++ b/connector/src/main/java/org/geysermc/connector/ping/IGeyserPingPassthrough.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,29 +27,15 @@ package org.geysermc.connector.ping; import org.geysermc.connector.common.ping.GeyserPingInfo; -import java.net.Inet4Address; -import java.net.InetSocketAddress; - /** * 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..5fdda617 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,69 @@ 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(LanguageUtils.getLocaleStringLog("geyser.network.translator.team.failed_overrides", teamName)); + 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 +106,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 +218,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..45cd0f9b 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 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..7815e36b 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BedrockMapIcon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/utils/BlockEntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java index 0c570dae..0ae31b33 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/BlockEntityUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,17 +33,17 @@ 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 (BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.containsKey(id)) { + return BlockEntityTranslator.BLOCK_ENTITY_TRANSLATIONS.get(id); } id = id.replace("minecraft:", "") - .replace("_", " "); + .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] @@ -60,10 +60,11 @@ public class BlockEntityUtils { 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) { 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..79fc5a78 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,11 +25,8 @@ 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.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.StringTag; @@ -39,53 +36,37 @@ import com.nukkitx.math.vector.Vector3i; import com.nukkitx.nbt.NBTOutputStream; import com.nukkitx.nbt.NbtMap; 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.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 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<>(); private static final NbtMap EMPTY_TAG = NbtMap.builder().build(); 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 @@ -95,168 +76,61 @@ public class ChunkUtils { } 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(); + // Temporarily stores positions of BlockState values per chunk load + Object2IntMap blockEntityPositions = new Object2IntOpenHashMap<>(); + + // 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++) { + int 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) || + BlockStateValues.getPistonValues().containsKey(blockState)) { + 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); + } + } + } + } + + } + NbtMap[] bedrockBlockEntities = new NbtMap[blockEntities.length + bedrockOnlyBlockEntities.size()]; int i = 0; while (i < blockEntities.length) { @@ -270,7 +144,7 @@ public class ChunkUtils { for (Tag subTag : tag) { if (subTag instanceof StringTag) { StringTag stringTag = (StringTag) subTag; - if (stringTag.getValue().isEmpty()) { + if (stringTag.getValue().equals("")) { tagName = stringTag.getName(); break; } @@ -284,30 +158,17 @@ public class ChunkUtils { 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); - } - + int blockState = blockEntityPositions.getOrDefault(pos, 0); 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) { bedrockBlockEntities[i] = tag; i++; } - return new ChunkData(sections, bedrockBlockEntities); + chunkData.blockEntities = bedrockBlockEntities; + return chunkData; } public static void updateChunkPosition(GeyserSession session, Vector3i position) { @@ -324,37 +185,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) { 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) { // 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 == 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 +204,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(); @@ -384,7 +220,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 +234,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 +266,10 @@ public class ChunkUtils { } } - @Data public static final class ChunkData { - private final ChunkSection[] sections; + public ChunkSection[] sections; - private final NbtMap[] blockEntities; + @Getter + private NbtMap[] blockEntities = new NbtMap[0]; } } diff --git a/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java b/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java index 5a49fd9b..7db3fadd 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/CooldownUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/utils/DimensionUtils.java b/connector/src/main/java/org/geysermc/connector/utils/DimensionUtils.java index f193a61d..7b283e9c 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 @@ -41,26 +41,22 @@ 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 - */ + // Static references to all vanilla dimensions 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) { int bedrockDimension = javaToBedrock(javaDimension); Entity player = session.getPlayerEntity(); + if (javaDimension.equals(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 +65,12 @@ public class DimensionUtils { changeDimensionPacket.setRespawn(true); changeDimensionPacket.setPosition(pos.toFloat()); session.sendUpstreamPacket(changeDimensionPacket); - session.setDimension(javaDimension); + player.setDimension(javaDimension); 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,7 +78,7 @@ 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(); @@ -115,46 +111,23 @@ public class DimensionUtils { /** * 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; + return "minecraft: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; + return "minecraft: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..59a03988 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java +++ b/connector/src/main/java/org/geysermc/connector/utils/DockerCheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/utils/EntityUtils.java b/connector/src/main/java/org/geysermc/connector/utils/EntityUtils.java index eb712b13..51102202 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 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..38369d6c 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 { @@ -57,16 +51,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 * @@ -156,88 +140,4 @@ public class FileUtils { } 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..f97e57e8 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FireworkColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/utils/GameRule.java b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java index a4e4ef23..48feb1c1 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/GameRule.java +++ b/connector/src/main/java/org/geysermc/connector/utils/GameRule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/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..cb51e2f3 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,9 +26,6 @@ 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; @@ -36,17 +33,14 @@ import com.nukkitx.nbt.NbtType; import com.nukkitx.protocol.bedrock.data.inventory.ContainerId; import com.nukkitx.protocol.bedrock.data.inventory.ItemData; import com.nukkitx.protocol.bedrock.packet.InventorySlotPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerHotbarPacket; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.common.ChatColor; +import org.geysermc.connector.GeyserConnector; 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; @@ -157,99 +151,4 @@ public class InventoryUtils { 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 - } } 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..bb3cf0ed 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 diff --git a/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java index 1a1f758d..de6796a2 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LanguageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -59,8 +59,6 @@ public class LanguageUtils { */ 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"); @@ -105,11 +103,7 @@ public class LanguageUtils { locale = formatLocale(locale); Properties properties = LOCALE_MAPPINGS.get(locale); - String formatString = null; - - if (properties != null) { - formatString = properties.getProperty(key); - } + String formatString = properties.getProperty(key); // Try and get the key from the default locale if (formatString == null) { @@ -137,7 +131,7 @@ public class LanguageUtils { * @param locale The locale to format * @return The formatted locale */ - public static String formatLocale(String locale) { + private static String formatLocale(String locale) { try { String[] parts = locale.toLowerCase().split("_"); return parts[0] + "_" + parts[1].toUpperCase(); @@ -187,11 +181,7 @@ public class LanguageUtils { 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 - } + 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)) { diff --git a/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java b/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java index bd41c34a..a0e3718b 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LoadstoneTracker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/utils/LocaleUtils.java b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java index e180682d..285846a9 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 @@ -35,6 +35,7 @@ import org.geysermc.connector.GeyserConnector; import java.io.*; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -47,7 +48,7 @@ public class LocaleUtils { private static final Map ASSET_MAP = new HashMap<>(); - private static VersionDownload clientJarInfo; + private static String smallestURL = ""; static { // Create the locales folder @@ -87,8 +88,9 @@ public class LocaleUtils { // 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)); + VersionDownload download = versionInfo.getDownloads().get("client"); + GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(download)); + smallestURL = download.getUrl(); // Get the assets list JsonNode assets = GeyserConnector.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); @@ -131,33 +133,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 = Paths.get(GeyserConnector.getInstance().getBootstrap().getConfigFolder().toString(),"locales",locale + ".json").toFile(); // 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 +150,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, localeFile.toString()); } /** @@ -222,11 +203,11 @@ public class LocaleUtils { 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().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, tmpFilePath.toString()); // Load in the JAR as a zip and extract the file ZipFile localeJar = new ZipFile(tmpFilePath.toString()); @@ -247,9 +228,6 @@ public class LocaleUtils { fileStream.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); } catch (Exception e) { @@ -266,32 +244,12 @@ public class LocaleUtils { */ public static String getLocaleString(String messageText, String locale) { Map localeStrings = LocaleUtils.LOCALE_MAPPINGS.get(locale.toLowerCase()); - if (localeStrings == null) { + 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; - } - } 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 } 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..4bc997bd 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; @@ -155,28 +156,20 @@ 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(); + String userLanguage = session.getClientData().getLanguageCode(); 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_login", userLanguage))); window.getButtons().add(new FormButton(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.notice.btn_disconnect", userLanguage))); session.sendForm(window, AUTH_FORM_ID); } public static void showLoginDetailsWindow(GeyserSession session) { - String userLanguage = session.getLocale(); + String userLanguage = session.getClientData().getLanguageCode(); 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", "")) @@ -186,33 +179,12 @@ public class LoginEncryptionUtils { 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 +198,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(LanguageUtils.getPlayerLocaleString("geyser.auth.login.form.disconnect", session.getClientData().getLanguageCode())); } } 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..f70414ca 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/MapColor.java +++ b/connector/src/main/java/org/geysermc/connector/utils/MapColor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * Permission is hereby 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/utils/MathUtils.java b/connector/src/main/java/org/geysermc/connector/utils/MathUtils.java index 0bb85442..48702492 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 @@ -40,26 +40,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 +54,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..a127fd8d --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/MessageUtils.java @@ -0,0 +1,494 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to 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.Message; +import com.github.steveice10.mc.protocol.data.message.MessageSerializer; +import com.github.steveice10.mc.protocol.data.message.TextMessage; +import com.github.steveice10.mc.protocol.data.message.TranslationMessage; +import com.github.steveice10.mc.protocol.data.message.style.ChatColor; +import com.github.steveice10.mc.protocol.data.message.style.ChatFormat; +import com.github.steveice10.mc.protocol.data.message.style.MessageStyle; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; +import org.geysermc.connector.network.session.GeyserSession; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class MessageUtils { + + private static final Map COLORS = new HashMap<>(); + private static final Map TEAM_COLORS = new HashMap<>(); + + static { + COLORS.put(ChatColor.BLACK, 0x000000); + COLORS.put(ChatColor.DARK_BLUE, 0x0000aa); + COLORS.put(ChatColor.DARK_GREEN, 0x00aa00); + COLORS.put(ChatColor.DARK_AQUA, 0x00aaaa); + COLORS.put(ChatColor.DARK_RED, 0xaa0000); + COLORS.put(ChatColor.DARK_PURPLE, 0xaa00aa); + COLORS.put(ChatColor.GOLD, 0xffaa00); + COLORS.put(ChatColor.GRAY, 0xaaaaaa); + COLORS.put(ChatColor.DARK_GRAY, 0x555555); + COLORS.put(ChatColor.BLUE, 0x5555ff); + COLORS.put(ChatColor.GREEN, 0x55ff55); + COLORS.put(ChatColor.AQUA, 0x55ffff); + COLORS.put(ChatColor.RED, 0xff5555); + COLORS.put(ChatColor.LIGHT_PURPLE, 0xff55ff); + COLORS.put(ChatColor.YELLOW, 0xffff55); + COLORS.put(ChatColor.WHITE, 0xffffff); + + TEAM_COLORS.put(TeamColor.BLACK, getColor(ChatColor.BLACK)); + TEAM_COLORS.put(TeamColor.DARK_BLUE, getColor(ChatColor.DARK_BLUE)); + TEAM_COLORS.put(TeamColor.DARK_GREEN, getColor(ChatColor.DARK_GREEN)); + TEAM_COLORS.put(TeamColor.DARK_AQUA, getColor(ChatColor.DARK_AQUA)); + TEAM_COLORS.put(TeamColor.DARK_RED, getColor(ChatColor.DARK_RED)); + TEAM_COLORS.put(TeamColor.DARK_PURPLE, getColor(ChatColor.DARK_PURPLE)); + TEAM_COLORS.put(TeamColor.GOLD, getColor(ChatColor.GOLD)); + TEAM_COLORS.put(TeamColor.GRAY, getColor(ChatColor.GRAY)); + TEAM_COLORS.put(TeamColor.DARK_GRAY, getColor(ChatColor.DARK_GRAY)); + TEAM_COLORS.put(TeamColor.BLUE, getColor(ChatColor.BLUE)); + TEAM_COLORS.put(TeamColor.GREEN, getColor(ChatColor.GREEN)); + TEAM_COLORS.put(TeamColor.AQUA, getColor(ChatColor.AQUA)); + TEAM_COLORS.put(TeamColor.RED, getColor(ChatColor.RED)); + TEAM_COLORS.put(TeamColor.LIGHT_PURPLE, getColor(ChatColor.LIGHT_PURPLE)); + TEAM_COLORS.put(TeamColor.YELLOW, getColor(ChatColor.YELLOW)); + TEAM_COLORS.put(TeamColor.WHITE, getColor(ChatColor.WHITE)); + TEAM_COLORS.put(TeamColor.OBFUSCATED, getFormat(Collections.singletonList(ChatFormat.OBFUSCATED))); + TEAM_COLORS.put(TeamColor.BOLD, getFormat(Collections.singletonList(ChatFormat.BOLD))); + TEAM_COLORS.put(TeamColor.STRIKETHROUGH, getFormat(Collections.singletonList(ChatFormat.STRIKETHROUGH))); + TEAM_COLORS.put(TeamColor.ITALIC, getFormat(Collections.singletonList(ChatFormat.ITALIC))); + } + + /** + * Recursively parse each message from a list for usage in a {@link TranslationMessage} + * + * @param messages A {@link List} of {@link Message} to parse + * @param locale A locale loaded to get the message for + * @param parent A {@link Message} to use as the parent (can be null) + * @return the translation parameters + */ + public static List getTranslationParams(List messages, String locale, Message parent) { + List strings = new ArrayList<>(); + for (Message message : messages) { + message = fixMessageStyle(message, parent); + + if (message instanceof TranslationMessage) { + TranslationMessage translation = (TranslationMessage) message; + + if (locale == null) { + String builder = "%" + translation.getKey(); + strings.add(builder); + } + + // Collect all params and add format corrections to the end of them + List furtherParams = new ArrayList<>(); + for (String param : getTranslationParams(translation.getWith(), locale, message)) { + String newParam = param; + if (parent.getStyle().getFormats().size() != 0) { + newParam += getFormat(parent.getStyle().getFormats()); + } + if (parent.getStyle().getColor() != ChatColor.NONE) { + newParam += getColor(parent.getStyle().getColor()); + } + + furtherParams.add(newParam); + } + + if (locale != null) { + String builder = getFormat(message.getStyle().getFormats()) + + getColor(message.getStyle().getColor()); + builder += insertParams(LocaleUtils.getLocaleString(translation.getKey(), locale), furtherParams); + strings.add(builder); + } else { + String format = getFormat(message.getStyle().getFormats()) + + getColor(message.getStyle().getColor()); + for (String param : furtherParams) { + strings.add(format + param); + } + } + } else { + String builder = getFormat(message.getStyle().getFormats()) + + getColor(message.getStyle().getColor()); + builder += getTranslatedBedrockMessage(message, locale, false, parent); + strings.add(builder); + } + } + + return strings; + } + + public static String getTranslatedBedrockMessage(Message message, String locale) { + return getTranslatedBedrockMessage(message, locale, true); + } + + public static String getTranslatedBedrockMessage(Message message, String locale, boolean shouldTranslate) { + return getTranslatedBedrockMessage(message, locale, shouldTranslate, null); + } + + /** + * Translate a given {@link TranslationMessage} to the given locale + * + * @param message The {@link Message} to send + * @param locale the locale + * @param shouldTranslate if the message should be translated + * @param parent the parent message + * @return the given translation message translated from the given locale + */ + public static String getTranslatedBedrockMessage(Message message, String locale, boolean shouldTranslate, Message parent) { + JsonParser parser = new JsonParser(); + if (isMessage(message.toString())) { + JsonObject object = parser.parse(message.toString()).getAsJsonObject(); + message = MessageSerializer.fromJson(object); + } + + message = fixMessageStyle(message, parent); + + String messageText = (message instanceof TranslationMessage) ? ((TranslationMessage) message).getKey() : ((TextMessage) message).getText(); + if (locale != null && shouldTranslate) { + messageText = LocaleUtils.getLocaleString(messageText, locale); + } + + StringBuilder builder = new StringBuilder(); + builder.append(getFormat(message.getStyle().getFormats())); + builder.append(getColor(message.getStyle().getColor())); + builder.append(messageText); + + for (Message msg : message.getExtra()) { + builder.append(getFormat(msg.getStyle().getFormats())); + builder.append(getColor(msg.getStyle().getColor())); + if (!(msg.toString() == null)) { + boolean isTranslationMessage = (msg instanceof TranslationMessage); + String extraText = ""; + + if (isTranslationMessage) { + List paramsTranslated = getTranslationParams(((TranslationMessage) msg).getWith(), locale, message); + extraText = insertParams(getTranslatedBedrockMessage(msg, locale, isTranslationMessage, message), paramsTranslated); + } else { + extraText = getTranslatedBedrockMessage(msg, locale, isTranslationMessage, message); + } + + builder.append(extraText); + builder.append("\u00a7r"); + } + } + + return builder.toString(); + } + + /** + * If the passed {@link Message} color or format are empty then copy from parent + * + * @param message {@link Message} to update + * @param parent Parent {@link Message} for style + * @return The updated {@link Message} + */ + private static Message fixMessageStyle(Message message, Message parent) { + if (parent == null) { + return message; + } + MessageStyle.Builder styleBuilder = message.getStyle().toBuilder(); + + // Copy color from parent + if (message.getStyle().getColor() == ChatColor.NONE) { + styleBuilder.color(parent.getStyle().getColor()); + } + + // Copy formatting from parent + if (message.getStyle().getFormats().size() == 0) { + styleBuilder.formats(parent.getStyle().getFormats()); + } + + return message.toBuilder().style(styleBuilder.build()).build(); + } + + public static String getBedrockMessage(Message message) { + if (isMessage(((TextMessage) message).getText())) { + return getBedrockMessage(((TextMessage) message).getText()); + } else { + return getBedrockMessage(MessageSerializer.toJsonString(message)); + } + } + + /** + * 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.legacySection().serialize(component); + } + + public static Component phraseJavaMessage(String message) { + return GsonComponentSerializer.gson().deserialize(message); + } + + public static String getJavaMessage(String message) { + Component component = LegacyComponentSerializer.legacySection().deserialize(message); + return GsonComponentSerializer.gson().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; + } + + /** + * Convert a ChatColor into a string for inserting into messages + * + * @param color ChatColor to convert + * @return The converted color string + */ + private static String getColor(String color) { + String base = "\u00a7"; + switch (color) { + case ChatColor.BLACK: + base += "0"; + break; + case ChatColor.DARK_BLUE: + base += "1"; + break; + case ChatColor.DARK_GREEN: + base += "2"; + break; + case ChatColor.DARK_AQUA: + base += "3"; + break; + case ChatColor.DARK_RED: + base += "4"; + break; + case ChatColor.DARK_PURPLE: + base += "5"; + break; + case ChatColor.GOLD: + base += "6"; + break; + case ChatColor.GRAY: + base += "7"; + break; + case ChatColor.DARK_GRAY: + base += "8"; + break; + case ChatColor.BLUE: + base += "9"; + break; + case ChatColor.GREEN: + base += "a"; + break; + case ChatColor.AQUA: + base += "b"; + break; + case ChatColor.RED: + base += "c"; + break; + case ChatColor.LIGHT_PURPLE: + base += "d"; + break; + case ChatColor.YELLOW: + base += "e"; + break; + case ChatColor.WHITE: + base += "f"; + break; + case ChatColor.RESET: + //case NONE: + base += "r"; + break; + case "": // To stop recursion + return ""; + default: + return getClosestColor(color); + } + + return base; + } + + /** + * Based on https://github.com/ViaVersion/ViaBackwards/blob/master/core/src/main/java/nl/matsv/viabackwards/protocol/protocol1_15_2to1_16/chat/TranslatableRewriter1_16.java + * + * @param color A color string + * @return The closest color to that string + */ + private static String getClosestColor(String color) { + if (!color.startsWith("#")) { + return ""; + } + + int rgb = Integer.parseInt(color.substring(1), 16); + int r = (rgb >> 16) & 0xFF; + int g = (rgb >> 8) & 0xFF; + int b = rgb & 0xFF; + + String closest = null; + int smallestDiff = 0; + + for (Map.Entry testColor : COLORS.entrySet()) { + if (testColor.getValue() == rgb) { + closest = testColor.getKey(); + break; + } + + int testR = (testColor.getValue() >> 16) & 0xFF; + int testG = (testColor.getValue() >> 8) & 0xFF; + int testB = testColor.getValue() & 0xFF; + + // Check by the greatest diff of the 3 values + int rAverage = (testR + r) / 2; + int rDiff = testR - r; + int gDiff = testG - g; + int bDiff = testB - b; + int diff = ((2 + (rAverage >> 8)) * rDiff * rDiff) + + (4 * gDiff * gDiff) + + ((2 + ((255 - rAverage) >> 8)) * bDiff * bDiff); + if (closest == null || diff < smallestDiff) { + closest = testColor.getKey(); + smallestDiff = diff; + } + } + + return getColor(closest); + } + + /** + * 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 { + MessageSerializer.fromJson(object); + } catch (Exception ex) { + return false; + } + } catch (Exception ex) { + return false; + } + return true; + } + + public static String toChatColor(TeamColor teamColor) { + return TEAM_COLORS.getOrDefault(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 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.getClientData().getLanguageCode(), message.length())); + 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 index 77afda53..89e9fe67 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/SettingsUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org * * 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,13 +52,13 @@ public class SettingsUtils { */ public static void buildForm(GeyserSession session) { // Cache the language for cleaner access - String language = session.getLocale(); + String language = session.getClientData().getLanguageCode(); 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())); + builder.addComponent(new ToggleComponent(LanguageUtils.getPlayerLocaleString("geyser.settings.option.coordinates", language, session.getWorldCache().isShowCoordinates()))); if (session.getOpPermissionLevel() >= 2 || session.hasPermission("geyser.settings.server")) { @@ -112,9 +112,6 @@ public class SettingsUtils { settingsForm.setResponse(response); CustomFormResponse settingsResponse = (CustomFormResponse) settingsForm.getResponse(); - if (settingsResponse == null) { - return false; - } int offset = 0; offset++; // Client settings title 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 83% 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..5551230b 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,32 @@ * @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.io.*; import java.net.HttpURLConnection; import java.net.URL; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.*; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; import java.util.concurrent.*; public class SkinProvider { @@ -85,25 +81,45 @@ public class SkinProvider { 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(); 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); + 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(); // 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(); + File cacheFolder = Paths.get("cache", "images").toFile(); if (!cacheFolder.exists()) { return; } @@ -141,19 +157,10 @@ public class SkinProvider { 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) ); @@ -192,6 +199,7 @@ public class SkinProvider { if (capeUrl == null || capeUrl.isEmpty()) return CompletableFuture.completedFuture(EMPTY_CAPE); if (requestedCapes.containsKey(capeUrl)) return requestedCapes.get(capeUrl); // already requested + boolean officialCape = provider == CapeProvider.MINECRAFT; Cape cachedCape = cachedCapes.getIfPresent(capeUrl); if (cachedCape != null) { return CompletableFuture.completedFuture(cachedCape); @@ -266,7 +274,7 @@ public class SkinProvider { return CompletableFuture.completedFuture(officialSkin); } - public static CompletableFuture requestBedrockCape(UUID playerID) { + public static CompletableFuture requestBedrockCape(UUID playerID, boolean newThread) { Cape bedrockCape = cachedCapes.getIfPresent(playerID.toString() + ".Bedrock"); if (bedrockCape == null) { bedrockCape = EMPTY_CAPE; @@ -274,7 +282,7 @@ public class SkinProvider { 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); } @@ -387,7 +395,7 @@ public class SkinProvider { BufferedImage image = null; // 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(); + File imageFile = Paths.get("cache", "images", UUID.nameUUIDFromBytes(imageUrl.getBytes()).toString() + ".png").toFile(); if (imageFile.exists()) { try { GeyserConnector.getInstance().getLogger().debug("Reading cached image from file " + imageFile.getPath() + " for " + imageUrl); @@ -430,60 +438,6 @@ 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); @@ -646,8 +600,8 @@ 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); 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..f0b88c43 --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/SkinUtils.java @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2019-2020 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to 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.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.common.AuthType; +import org.geysermc.connector.GeyserConnector; +import org.geysermc.connector.entity.Entity; +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(GeyserSession session, GameProfile profile, long geyserId) { + GameProfileData data = GameProfileData.from(profile); + 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, + profile.getId(), + profile.getName(), + geyserId, + skin.getTextureUrl(), + skin.getSkinData(), + cape.getCapeId(), + cape.getCapeData(), + geometry.getGeometryName(), + geometry.getGeometryData() + ); + } + + public static PlayerListPacket.Entry buildDefaultEntry(GeyserSession session, GameProfile profile, long geyserId) { + return buildEntryManually( + session, + profile.getId(), + profile.getName(), + geyserId, + "default", + SkinProvider.STEVE_SKIN, + SkinProvider.EMPTY_CAPE.getCapeId(), + SkinProvider.EMPTY_CAPE.getCapeData(), + SkinProvider.EMPTY_GEOMETRY.getGeometryName(), + SkinProvider.EMPTY_GEOMETRY.getGeometryData() + ); + } + + public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, 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, skinId + ); + + // This attempts to find the xuid of the player so profile images show up for xbox accounts + String xuid = ""; + for (GeyserSession player : GeyserConnector.getInstance().getPlayers()) { + if (player.getPlayerEntity().getUuid().equals(uuid)) { + xuid = player.getAuthData().getXboxUUID(); + break; + } + } + + 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; + } + + @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 = (Math.abs(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()); + } + } + + entity.setLastSkinUpdate(skin.getRequestedOn()); + + if (session.getUpstream().isInitialized()) { + PlayerListPacket.Entry updatedEntry = buildEntryManually( + session, + entity.getUuid(), + entity.getUsername(), + entity.getGeyserId(), + skin.getTextureUrl(), + skin.getSkinData(), + cape.getCapeId(), + cape.getCapeData(), + geometry.getGeometryName(), + geometry.getGeometryData() + ); + + + 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 = 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(), 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); + } + } +} 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..94167c3e 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,7 +25,6 @@ package org.geysermc.connector.utils; -import com.fasterxml.jackson.databind.JsonNode; import org.geysermc.connector.GeyserConnector; import java.io.*; @@ -58,18 +57,6 @@ public class WebUtils { } } - /** - * 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 * 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..eea92a95 100644 --- a/connector/src/main/resources/bedrock/creative_items.json +++ b/connector/src/main/resources/bedrock/creative_items.json @@ -258,31 +258,31 @@ "id" : -275 }, { - "id" : 359 + "id" : 324 }, { - "id" : 543 + "id" : 427 }, { - "id" : 544 + "id" : 428 }, { - "id" : 545 + "id" : 429 }, { - "id" : 546 + "id" : 430 }, { - "id" : 547 + "id" : 431 }, { - "id" : 370 + "id" : 330 }, { - "id" : 604 + "id" : 755 }, { - "id" : 605 + "id" : 756 }, { "id" : 96 @@ -314,6 +314,9 @@ { "id" : 101 }, + { + "id" : 758 + }, { "id" : 20 }, @@ -738,15 +741,66 @@ { "id" : 170 }, + { + "id" : -239 + }, { "id" : 216 }, + { + "id" : 214 + }, + { + "id" : -227 + }, { "id" : 112 }, { "id" : 215 }, + { + "id" : -225 + }, + { + "id" : -226 + }, + { + "id" : -240 + }, + { + "id" : -241 + }, + { + "id" : -299 + }, + { + "id" : -298 + }, + { + "id" : -300 + }, + { + "id" : -301 + }, + { + "id" : -230 + }, + { + "id" : -232 + }, + { + "id" : -233 + }, + { + "id" : -234 + }, + { + "id" : -235 + }, + { + "id" : -236 + }, { "id" : -270 }, @@ -1129,30 +1183,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 +1190,6 @@ "id" : 3, "damage" : 1 }, - { - "id" : 60 - }, { "id" : 2 }, @@ -1291,18 +1318,6 @@ { "id" : -9 }, - { - "id" : -225 - }, - { - "id" : -240 - }, - { - "id" : -226 - }, - { - "id" : -241 - }, { "id" : -212 }, @@ -1350,18 +1365,6 @@ "id" : -212, "damage" : 13 }, - { - "id" : -299 - }, - { - "id" : -300 - }, - { - "id" : -298 - }, - { - "id" : -301 - }, { "id" : 18 }, @@ -1408,58 +1411,59 @@ "damage" : 5 }, { - "id" : -218 - }, - { - "id" : 291 - }, - { - "id" : 292 - }, - { - "id" : 293 + "id" : -218, + "damage" : 3 }, { "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 +1475,7 @@ "id" : 91 }, { - "id" : 580 + "id" : 736 }, { "id" : 31, @@ -1490,7 +1494,7 @@ "damage" : 2 }, { - "id" : 609 + "id" : 760 }, { "id" : -131, @@ -1570,7 +1574,7 @@ "damage" : 4 }, { - "id" : 380 + "id" : 335 }, { "id" : -130 @@ -1646,64 +1650,83 @@ "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 @@ -1739,31 +1762,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 @@ -1793,25 +1816,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,193 +1869,252 @@ "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" : 125 }, { - "id" : 494 + "id" : 383, + "damage" : 124 }, { - "id" : 495 + "id" : 383, + "damage" : 123 }, { - "id" : 496 + "id" : 383, + "damage" : 126 }, { - "id" : 497 + "id" : 383, + "damage" : 41 }, { - "id" : 452 + "id" : 383, + "damage" : 43 }, { - "id" : 454 + "id" : 383, + "damage" : 54 }, { - "id" : 467 + "id" : 383, + "damage" : 57 }, { - "id" : 472 + "id" : 383, + "damage" : 104 }, { - "id" : 473 + "id" : 383, + "damage" : 105 }, { - "id" : 474 + "id" : 383, + "damage" : 115 }, { - "id" : 447 + "id" : 383, + "damage" : 118 }, { - "id" : 490 + "id" : 383, + "damage" : 116 }, { - "id" : 475 + "id" : 383, + "damage" : 58 }, { - "id" : 484 + "id" : 383, + "damage" : 114 }, { - "id" : 489 - }, - { - "id" : 491 + "id" : 383, + "damage" : 59 }, { "id" : 49 @@ -2053,7 +2135,7 @@ "id" : 213 }, { - "id" : 294 + "id" : 372 }, { "id" : 121 @@ -2065,10 +2147,10 @@ "id" : 240 }, { - "id" : 548 + "id" : 432 }, { - "id" : 549 + "id" : 433 }, { "id" : 19 @@ -2116,1024 +2198,1024 @@ "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" : 310 }, { - "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" : 748 }, { "id" : 299 }, { - "id" : 537 + "id" : 303 }, { - "id" : 391 + "id" : 307 }, { - "id" : 389 + "id" : 315 }, { - "id" : 505 + "id" : 311 }, { - "id" : 505, - "damage" : 2 + "id" : 749 }, { - "id" : 369 + "id" : 300 }, { - "id" : 520 + "id" : 304 }, { - "id" : 521 + "id" : 308 }, { - "id" : 522 + "id" : 316 }, { - "id" : 523 + "id" : 312 }, { - "id" : 536 + "id" : 750 }, { - "id" : 563 + "id" : 301 }, { - "id" : 554 + "id" : 305 }, { - "id" : 558 + "id" : 309 }, { - "id" : 425 + "id" : 317 }, { - "id" : 498 + "id" : 313 }, { - "id" : 424 + "id" : 751 }, { - "id" : 424, - "damage" : 1 + "id" : 268 }, { - "id" : 424, - "damage" : 2 + "id" : 272 }, { - "id" : 424, - "damage" : 3 + "id" : 267 }, { - "id" : 424, - "damage" : 4 + "id" : 283 }, { - "id" : 424, - "damage" : 5 + "id" : 276 }, { - "id" : 424, + "id" : 743 + }, + { + "id" : 271 + }, + { + "id" : 275 + }, + { + "id" : 258 + }, + { + "id" : 286 + }, + { + "id" : 279 + }, + { + "id" : 746 + }, + { + "id" : 270 + }, + { + "id" : 274 + }, + { + "id" : 257 + }, + { + "id" : 285 + }, + { + "id" : 278 + }, + { + "id" : 745 + }, + { + "id" : 269 + }, + { + "id" : 273 + }, + { + "id" : 256 + }, + { + "id" : 284 + }, + { + "id" : 277 + }, + { + "id" : 744 + }, + { + "id" : 290 + }, + { + "id" : 291 + }, + { + "id" : 292 + }, + { + "id" : 294 + }, + { + "id" : 293 + }, + { + "id" : 747 + }, + { + "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" : 262, + "damage" : 43 }, { - "id" : 551, - "damage" : 1 + "id" : 513 }, { - "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" : 757 + }, + { + "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" : 373, + "damage" : 42 + }, + { + "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" : 438, + "damage" : 42 + }, + { + "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" : 441, + "damage" : 42 + }, + { + "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 }, { @@ -3164,13 +3246,14 @@ "id" : -202 }, { - "id" : -219 + "id" : -219, + "damage" : 3 }, { - "id" : 578 + "id" : 720 }, { - "id" : 610 + "id" : 801 }, { "id" : 61 @@ -3185,7 +3268,7 @@ "id" : -272 }, { - "id" : 429 + "id" : 379 }, { "id" : 145 @@ -3211,7 +3294,7 @@ "id" : -194 }, { - "id" : 430 + "id" : 380 }, { "id" : -213 @@ -3295,7 +3378,7 @@ "damage" : 6 }, { - "id" : 542 + "id" : 425 }, { "id" : 25 @@ -3304,46 +3387,46 @@ "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" : 759 }, { - "id" : 392 + "id" : 348 }, { "id" : 89 @@ -3355,89 +3438,96 @@ "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" : 476 }, { - "id" : 602 + "id" : 753 }, { - "id" : 603 - }, - { - "id" : 357 - }, - { - "id" : 503 - }, - { - "id" : 581 - }, - { - "id" : 504 + "id" : 754 }, { "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 +3546,92 @@ "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" : 752 }, { - "id" : 591 + "id" : 742 }, { - "id" : 423 + "id" : 371 }, { - "id" : 306 + "id" : 266 }, { - "id" : 502 + "id" : 388 }, { - "id" : 514 + "id" : 406 }, { - "id" : 382 + "id" : 337 }, { - "id" : 381 + "id" : 336 }, { - "id" : 513 + "id" : 405 }, { - "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 +3639,496 @@ { "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" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBsAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZBwAAAA=" + }, + { + "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" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAQACAgBpZCQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAgACAgBpZCQAAAA=" + }, + { + "id" : 403, + "nbt_b64" : "CgAACQQAZW5jaAoBAAAAAgMAbHZsAwACAgBpZCQAAAA=" + }, + { + "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 +4142,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 @@ -4145,13 +4241,13 @@ "id" : 151 }, { - "id" : 417 + "id" : 356 }, { - "id" : 512 + "id" : 404 }, { - "id" : 517 + "id" : 410 }, { "id" : 125, @@ -4173,255 +4269,252 @@ "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" : 434, + "damage" : 6 }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwAAAAAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMAAAAAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAABwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAIBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAHBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAPBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAMBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAOBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAABBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAEBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAFBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAANBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAADQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAJBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACQEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAADBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAALBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACwEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAKBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAACgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAACBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAAAgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 509, - "nbt_b64" : "CgAACgkARmlyZXdvcmtzCQoARXhwbG9zaW9ucwoBAAAABw0ARmlyZXdvcmtDb2xvcgEAAAAGBwwARmlyZXdvcmtGYWRlAAAAAAEPAEZpcmV3b3JrRmxpY2tlcgABDQBGaXJld29ya1RyYWlsAAEMAEZpcmV3b3JrVHlwZQAAAQYARmxpZ2h0AQAA" + "id" : 401, + "nbt_b64" : "CgAACgkARmlyZXdvcmtzAQYARmxpZ2h0AQkKAEV4cGxvc2lvbnMKAQAAAAcNAEZpcmV3b3JrQ29sb3IBAAAABgEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAAA" }, { - "id" : 510, - "nbt_b64" : "CgAACg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAcMAEZpcmV3b3JrRmFkZQAAAAABDwBGaXJld29ya0ZsaWNrZXIAAQ0ARmlyZXdvcmtUcmFpbAABDABGaXJld29ya1R5cGUAAAMLAGN1c3RvbUNvbG9yIR0d/wA=" + "id" : 402, + "nbt_b64" : "CgAAAwsAY3VzdG9tQ29sb3IhHR3/Cg0ARmlyZXdvcmtzSXRlbQcNAEZpcmV3b3JrQ29sb3IBAAAAAAEMAEZpcmV3b3JrVHlwZQAHDABGaXJld29ya0ZhZGUAAAAAAQ0ARmlyZXdvcmtUcmFpbAABDwBGaXJld29ya0ZsaWNrZXIAAAA=" }, { - "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/runtime_item_states.json b/connector/src/main/resources/bedrock/items.json similarity index 84% rename from connector/src/main/resources/bedrock/runtime_item_states.json rename to connector/src/main/resources/bedrock/items.json index eaf6656b..0614b364 100644 --- a/connector/src/main/resources/bedrock/runtime_item_states.json +++ b/connector/src/main/resources/bedrock/items.json @@ -1,1043 +1,2103 @@ [ { - "name" : "minecraft:acacia_boat", - "id" : 377 + "name" : "minecraft:purpur_block", + "id" : 201 }, { - "name" : "minecraft:acacia_button", - "id" : -140 + "name" : "minecraft:bow", + "id" : 261 }, { - "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:end_bricks", + "id" : 206 }, { "name" : "minecraft:air", "id" : -158 }, { - "name" : "minecraft:allow", - "id" : 210 + "name" : "minecraft:element_94", + "id" : -105 }, { - "name" : "minecraft:ancient_debris", - "id" : -271 + "name" : "minecraft:rabbit", + "id" : 411 }, { - "name" : "minecraft:andesite_stairs", - "id" : -171 + "name" : "minecraft:element_25", + "id" : -36 }, { - "name" : "minecraft:anvil", - "id" : 145 + "name" : "minecraft:mushroom_stew", + "id" : 282 }, { - "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:polished_blackstone_brick_slab", + "id" : -284 }, { "name" : "minecraft:cooked_porkchop", - "id" : 263 + "id" : 320 }, { - "name" : "minecraft:cooked_rabbit", - "id" : 289 + "name" : "minecraft:record_ward", + "id" : 509 }, { - "name" : "minecraft:cooked_salmon", - "id" : 269 + "name" : "minecraft:appleenchanted", + "id" : 466 + }, + { + "name" : "minecraft:pumpkin", + "id" : 86 + }, + { + "name" : "minecraft:slime", + "id" : 165 + }, + { + "name" : "minecraft:apple", + "id" : 260 + }, + { + "name" : "minecraft:element_50", + "id" : -61 + }, + { + "name" : "minecraft:stripped_oak_log", + "id" : -10 + }, + { + "name" : "minecraft:golden_apple", + "id" : 322 + }, + { + "name" : "minecraft:fish", + "id" : 349 + }, + { + "name" : "minecraft:item.dark_oak_door", + "id" : 197 + }, + { + "name" : "minecraft:light_block", + "id" : -215 + }, + { + "name" : "minecraft:yellow_glazed_terracotta", + "id" : 224 + }, + { + "name" : "minecraft:stone_brick_stairs", + "id" : 109 + }, + { + "name" : "minecraft:portal", + "id" : 90 + }, + { + "name" : "minecraft:gold_ingot", + "id" : 266 + }, + { + "name" : "minecraft:iron_ingot", + "id" : 265 }, { "name" : "minecraft:cookie", - "id" : 271 + "id" : 357 }, { - "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", + "name" : "minecraft:porkchop", "id" : 319 }, + { + "name" : "minecraft:bread", + "id" : 297 + }, + { + "name" : "minecraft:element_7", + "id" : -18 + }, { "name" : "minecraft:diamond_block", "id" : 57 }, { - "name" : "minecraft:diamond_boots", + "name" : "minecraft:iron_pickaxe", + "id" : 257 + }, + { + "name" : "minecraft:element_27", + "id" : -38 + }, + { + "name" : "minecraft:beef", + "id" : 363 + }, + { + "name" : "minecraft:salmon", + "id" : 460 + }, + { + "name" : "minecraft:melon", + "id" : 360 + }, + { + "name" : "minecraft:clownfish", + "id" : 461 + }, + { + "name" : "minecraft:element_16", + "id" : -27 + }, + { + "name" : "minecraft:tripwire", + "id" : 132 + }, + { + "name" : "minecraft:stone_axe", + "id" : 275 + }, + { + "name" : "minecraft:stained_glass_pane", + "id" : 160 + }, + { + "name" : "minecraft:trapped_chest", + "id" : 146 + }, + { + "name" : "minecraft:pufferfish", + "id" : 462 + }, + { + "name" : "minecraft:bucket", + "id" : 325 + }, + { + "name" : "minecraft:ancient_debris", + "id" : -271 + }, + { + "name" : "minecraft:anvil", + "id" : 145 + }, + { + "name" : "minecraft:stick", + "id" : 280 + }, + { + "name" : "minecraft:cooked_fish", "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", + "name" : "minecraft:cooked_salmon", "id" : 463 }, { - "name" : "minecraft:double_plant", - "id" : 175 + "name" : "minecraft:element_61", + "id" : -72 }, { - "name" : "minecraft:double_stone_slab", - "id" : 44 + "name" : "minecraft:sparkler", + "id" : 442 }, { - "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:warped_door", + "id" : 756 }, { "name" : "minecraft:dried_kelp", - "id" : 270 + "id" : 464 }, { - "name" : "minecraft:dried_kelp_block", - "id" : -139 + "name" : "minecraft:hay_block", + "id" : 170 }, { - "name" : "minecraft:dropper", - "id" : 125 + "name" : "minecraft:wooden_shovel", + "id" : 269 }, { - "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:nautilus_shell", + "id" : 465 }, { "name" : "minecraft:element_1", "id" : -12 }, { - "name" : "minecraft:element_10", - "id" : -21 + "name" : "minecraft:stonecutter_block", + "id" : -197 }, { - "name" : "minecraft:element_100", - "id" : -111 + "name" : "minecraft:cooked_beef", + "id" : 364 }, { - "name" : "minecraft:element_101", - "id" : -112 + "name" : "minecraft:comparator", + "id" : 404 }, { - "name" : "minecraft:element_102", - "id" : -113 + "name" : "minecraft:carrot", + "id" : 391 }, { - "name" : "minecraft:element_103", - "id" : -114 + "name" : "minecraft:command_block", + "id" : 137 + }, + { + "name" : "minecraft:chicken", + "id" : 365 + }, + { + "name" : "minecraft:potion", + "id" : 373 + }, + { + "name" : "minecraft:rotten_flesh", + "id" : 367 + }, + { + "name" : "minecraft:dirt", + "id" : 3 + }, + { + "name" : "minecraft:element_62", + "id" : -73 + }, + { + "name" : "minecraft:daylight_detector", + "id" : 151 + }, + { + "name" : "minecraft:snow_layer", + "id" : 78 + }, + { + "name" : "minecraft:rabbit_foot", + "id" : 414 + }, + { + "name" : "minecraft:lingering_potion", + "id" : 441 + }, + { + "name" : "minecraft:campfire", + "id" : 720 + }, + { + "name" : "minecraft:smoker", + "id" : -198 + }, + { + "name" : "minecraft:warped_fence", + "id" : -257 + }, + { + "name" : "minecraft:cooked_chicken", + "id" : 366 + }, + { + "name" : "minecraft:light_blue_glazed_terracotta", + "id" : 223 + }, + { + "name" : "minecraft:stone_sword", + "id" : 272 + }, + { + "name" : "minecraft:record_far", + "id" : 504 + }, + { + "name" : "minecraft:spider_eye", + "id" : 375 + }, + { + "name" : "minecraft:smooth_quartz_stairs", + "id" : -185 + }, + { + "name" : "minecraft:potato", + "id" : 392 + }, + { + "name" : "minecraft:baked_potato", + "id" : 393 + }, + { + "name" : "minecraft:element_88", + "id" : -99 + }, + { + "name" : "minecraft:golden_carrot", + "id" : 396 + }, + { + "name" : "minecraft:spruce_stairs", + "id" : 134 + }, + { + "name" : "minecraft:poisonous_potato", + "id" : 394 + }, + { + "name" : "minecraft:element_13", + "id" : -24 + }, + { + "name" : "minecraft:obsidian", + "id" : 49 + }, + { + "name" : "minecraft:pumpkin_pie", + "id" : 400 + }, + { + "name" : "minecraft:diamond_pickaxe", + "id" : 278 + }, + { + "name" : "minecraft:lantern", + "id" : -208 + }, + { + "name" : "minecraft:iron_sword", + "id" : 267 + }, + { + "name" : "minecraft:smooth_stone", + "id" : -183 + }, + { + "name" : "minecraft:beetroot", + "id" : 457 + }, + { + "name" : "minecraft:element_43", + "id" : -54 + }, + { + "name" : "minecraft:beetroot_soup", + "id" : 459 + }, + { + "name" : "minecraft:red_mushroom", + "id" : 40 + }, + { + "name" : "minecraft:wooden_pickaxe", + "id" : 270 + }, + { + "name" : "minecraft:invisiblebedrock", + "id" : 95 + }, + { + "name" : "minecraft:sweet_berries", + "id" : 477 + }, + { + "name" : "minecraft:prismarine_bricks_stairs", + "id" : -4 + }, + { + "name" : "minecraft:cooked_rabbit", + "id" : 412 + }, + { + "name" : "minecraft:rabbit_stew", + "id" : 413 + }, + { + "name" : "minecraft:birch_fence_gate", + "id" : 184 + }, + { + "name" : "minecraft:wheat_seeds", + "id" : 295 + }, + { + "name" : "minecraft:chest", + "id" : 54 + }, + { + "name" : "minecraft:pumpkin_seeds", + "id" : 361 + }, + { + "name" : "minecraft:element_2", + "id" : -13 + }, + { + "name" : "minecraft:item.crimson_door", + "id" : -244 + }, + { + "name" : "minecraft:command_block_minecart", + "id" : 443 + }, + { + "name" : "minecraft:melon_seeds", + "id" : 362 + }, + { + "name" : "minecraft:iron_axe", + "id" : 258 + }, + { + "name" : "minecraft:spawn_egg", + "id" : 383 + }, + { + "name" : "minecraft:element_93", + "id" : -104 + }, + { + "name" : "minecraft:nether_wart", + "id" : 372 + }, + { + "name" : "minecraft:beetroot_seeds", + "id" : 458 + }, + { + "name" : "minecraft:element_35", + "id" : -46 + }, + { + "name" : "minecraft:iron_shovel", + "id" : 256 }, { "name" : "minecraft:element_104", "id" : -115 }, { - "name" : "minecraft:element_105", - "id" : -116 + "name" : "minecraft:granite_stairs", + "id" : -169 }, { - "name" : "minecraft:element_106", - "id" : -117 + "name" : "minecraft:flint_and_steel", + "id" : 259 }, { - "name" : "minecraft:element_107", - "id" : -118 + "name" : "minecraft:stone_shovel", + "id" : 273 }, { - "name" : "minecraft:element_108", - "id" : -119 + "name" : "minecraft:horsearmorleather", + "id" : 416 }, { - "name" : "minecraft:element_109", - "id" : -120 + "name" : "minecraft:item.cauldron", + "id" : 118 }, { - "name" : "minecraft:element_11", - "id" : -22 + "name" : "minecraft:melon_block", + "id" : 103 }, { - "name" : "minecraft:element_110", - "id" : -121 + "name" : "minecraft:arrow", + "id" : 262 }, { - "name" : "minecraft:element_111", - "id" : -122 + "name" : "minecraft:coal", + "id" : 263 }, { - "name" : "minecraft:element_112", - "id" : -123 + "name" : "minecraft:real_double_stone_slab2", + "id" : 181 }, { - "name" : "minecraft:element_113", - "id" : -124 + "name" : "minecraft:chorus_plant", + "id" : 240 }, { - "name" : "minecraft:element_114", - "id" : -125 + "name" : "minecraft:gold_block", + "id" : 41 }, { - "name" : "minecraft:element_115", - "id" : -126 + "name" : "minecraft:carrots", + "id" : 141 + }, + { + "name" : "minecraft:diamond", + "id" : 264 + }, + { + "name" : "minecraft:wooden_sword", + "id" : 268 + }, + { + "name" : "minecraft:record_strad", + "id" : 508 + }, + { + "name" : "minecraft:netherite_boots", + "id" : 751 + }, + { + "name" : "minecraft:dark_oak_stairs", + "id" : 164 + }, + { + "name" : "minecraft:farmland", + "id" : 60 + }, + { + "name" : "minecraft:wooden_axe", + "id" : 271 + }, + { + "name" : "minecraft:stone_pickaxe", + "id" : 274 + }, + { + "name" : "minecraft:planks", + "id" : 5 + }, + { + "name" : "minecraft:chainmail_helmet", + "id" : 302 + }, + { + "name" : "minecraft:diamond_shovel", + "id" : 277 + }, + { + "name" : "minecraft:diamond_sword", + "id" : 276 + }, + { + "name" : "minecraft:smithing_table", + "id" : -202 + }, + { + "name" : "minecraft:diamond_axe", + "id" : 279 + }, + { + "name" : "minecraft:bowl", + "id" : 281 + }, + { + "name" : "minecraft:flowing_water", + "id" : 8 + }, + { + "name" : "minecraft:golden_sword", + "id" : 283 + }, + { + "name" : "minecraft:honey_block", + "id" : -220 + }, + { + "name" : "minecraft:golden_shovel", + "id" : 284 + }, + { + "name" : "minecraft:golden_pickaxe", + "id" : 285 + }, + { + "name" : "minecraft:lit_redstone_lamp", + "id" : 124 + }, + { + "name" : "minecraft:elytra", + "id" : 444 + }, + { + "name" : "minecraft:golden_axe", + "id" : 286 + }, + { + "name" : "minecraft:element_52", + "id" : -63 + }, + { + "name" : "minecraft:string", + "id" : 287 + }, + { + "name" : "minecraft:real_double_stone_slab4", + "id" : -168 + }, + { + "name" : "minecraft:feather", + "id" : 288 + }, + { + "name" : "minecraft:gunpowder", + "id" : 289 + }, + { + "name" : "minecraft:acacia_stairs", + "id" : 163 + }, + { + "name" : "minecraft:wooden_hoe", + "id" : 290 + }, + { + "name" : "minecraft:stone_hoe", + "id" : 291 + }, + { + "name" : "minecraft:iron_hoe", + "id" : 292 + }, + { + "name" : "minecraft:diamond_hoe", + "id" : 293 + }, + { + "name" : "minecraft:element_86", + "id" : -97 + }, + { + "name" : "minecraft:golden_hoe", + "id" : 294 + }, + { + "name" : "minecraft:wheat", + "id" : 296 + }, + { + "name" : "minecraft:leather_helmet", + "id" : 298 + }, + { + "name" : "minecraft:leather_chestplate", + "id" : 299 + }, + { + "name" : "minecraft:leather_leggings", + "id" : 300 + }, + { + "name" : "minecraft:lodestone", + "id" : -222 + }, + { + "name" : "minecraft:brown_mushroom", + "id" : 39 + }, + { + "name" : "minecraft:leather_boots", + "id" : 301 + }, + { + "name" : "minecraft:chainmail_chestplate", + "id" : 303 + }, + { + "name" : "minecraft:end_gateway", + "id" : 209 + }, + { + "name" : "minecraft:item.beetroot", + "id" : 244 + }, + { + "name" : "minecraft:chainmail_leggings", + "id" : 304 + }, + { + "name" : "minecraft:element_101", + "id" : -112 + }, + { + "name" : "minecraft:chainmail_boots", + "id" : 305 + }, + { + "name" : "minecraft:soul_sand", + "id" : 88 + }, + { + "name" : "minecraft:iron_helmet", + "id" : 306 + }, + { + "name" : "minecraft:snowball", + "id" : 332 + }, + { + "name" : "minecraft:element_49", + "id" : -60 + }, + { + "name" : "minecraft:record_mellohi", + "id" : 506 + }, + { + "name" : "minecraft:iron_chestplate", + "id" : 307 + }, + { + "name" : "minecraft:barrel", + "id" : -203 + }, + { + "name" : "minecraft:iron_leggings", + "id" : 308 + }, + { + "name" : "minecraft:crimson_double_slab", + "id" : -266 + }, + { + "name" : "minecraft:iron_boots", + "id" : 309 + }, + { + "name" : "minecraft:real_double_stone_slab3", + "id" : -167 + }, + { + "name" : "minecraft:ender_eye", + "id" : 381 + }, + { + "name" : "minecraft:stickypistonarmcollision", + "id" : -217 + }, + { + "name" : "minecraft:iron_trapdoor", + "id" : 167 + }, + { + "name" : "minecraft:diamond_helmet", + "id" : 310 + }, + { + "name" : "minecraft:stone_pressure_plate", + "id" : 70 + }, + { + "name" : "minecraft:diamond_chestplate", + "id" : 311 + }, + { + "name" : "minecraft:sand", + "id" : 12 + }, + { + "name" : "minecraft:light_weighted_pressure_plate", + "id" : 147 + }, + { + "name" : "minecraft:piston", + "id" : 33 + }, + { + "name" : "minecraft:diamond_leggings", + "id" : 312 + }, + { + "name" : "minecraft:element_30", + "id" : -41 + }, + { + "name" : "minecraft:diamond_boots", + "id" : 313 + }, + { + "name" : "minecraft:golden_helmet", + "id" : 314 + }, + { + "name" : "minecraft:element_51", + "id" : -62 + }, + { + "name" : "minecraft:double_wooden_slab", + "id" : 157 + }, + { + "name" : "minecraft:hard_stained_glass", + "id" : 254 + }, + { + "name" : "minecraft:element_84", + "id" : -95 + }, + { + "name" : "minecraft:golden_chestplate", + "id" : 315 + }, + { + "name" : "minecraft:sealantern", + "id" : 169 + }, + { + "name" : "minecraft:bedrock", + "id" : 7 + }, + { + "name" : "minecraft:glowstone", + "id" : 89 + }, + { + "name" : "minecraft:golden_leggings", + "id" : 316 + }, + { + "name" : "minecraft:golden_boots", + "id" : 317 + }, + { + "name" : "minecraft:shield", + "id" : 513 + }, + { + "name" : "minecraft:jungle_fence_gate", + "id" : 185 + }, + { + "name" : "minecraft:carpet", + "id" : 171 + }, + { + "name" : "minecraft:flowing_lava", + "id" : 10 + }, + { + "name" : "minecraft:flint", + "id" : 318 + }, + { + "name" : "minecraft:painting", + "id" : 321 + }, + { + "name" : "minecraft:heart_of_the_sea", + "id" : 467 + }, + { + "name" : "minecraft:sign", + "id" : 323 + }, + { + "name" : "minecraft:muttonraw", + "id" : 423 + }, + { + "name" : "minecraft:element_55", + "id" : -66 + }, + { + "name" : "minecraft:wooden_door", + "id" : 324 + }, + { + "name" : "minecraft:concrete_powder", + "id" : 237 + }, + { + "name" : "minecraft:minecart", + "id" : 328 + }, + { + "name" : "minecraft:saddle", + "id" : 329 + }, + { + "name" : "minecraft:nether_wart_block", + "id" : 214 + }, + { + "name" : "minecraft:crimson_roots", + "id" : -223 }, { "name" : "minecraft:element_116", "id" : -127 }, { - "name" : "minecraft:element_117", - "id" : -128 + "name" : "minecraft:iron_door", + "id" : 330 + }, + { + "name" : "minecraft:redstone", + "id" : 331 + }, + { + "name" : "minecraft:boat", + "id" : 333 + }, + { + "name" : "minecraft:written_book", + "id" : 387 + }, + { + "name" : "minecraft:iron_ore", + "id" : 15 + }, + { + "name" : "minecraft:leather", + "id" : 334 + }, + { + "name" : "minecraft:kelp", + "id" : 335 + }, + { + "name" : "minecraft:gold_nugget", + "id" : 371 + }, + { + "name" : "minecraft:brick", + "id" : 336 + }, + { + "name" : "minecraft:element_68", + "id" : -79 + }, + { + "name" : "minecraft:clay_ball", + "id" : 337 + }, + { + "name" : "minecraft:carrotonastick", + "id" : 398 + }, + { + "name" : "minecraft:reeds", + "id" : 338 + }, + { + "name" : "minecraft:paper", + "id" : 339 + }, + { + "name" : "minecraft:element_23", + "id" : -34 + }, + { + "name" : "minecraft:coral", + "id" : -131 + }, + { + "name" : "minecraft:book", + "id" : 340 + }, + { + "name" : "minecraft:end_portal", + "id" : 119 + }, + { + "name" : "minecraft:trident", + "id" : 455 + }, + { + "name" : "minecraft:slime_ball", + "id" : 341 + }, + { + "name" : "minecraft:chest_minecart", + "id" : 342 + }, + { + "name" : "minecraft:element_71", + "id" : -82 + }, + { + "name" : "minecraft:egg", + "id" : 344 + }, + { + "name" : "minecraft:netherite_sword", + "id" : 743 + }, + { + "name" : "minecraft:item.reeds", + "id" : 83 + }, + { + "name" : "minecraft:compass", + "id" : 345 + }, + { + "name" : "minecraft:crimson_stairs", + "id" : -254 + }, + { + "name" : "minecraft:fishing_rod", + "id" : 346 + }, + { + "name" : "minecraft:andesite_stairs", + "id" : -171 + }, + { + "name" : "minecraft:reserved6", + "id" : 255 + }, + { + "name" : "minecraft:clock", + "id" : 347 + }, + { + "name" : "minecraft:red_sandstone", + "id" : 179 + }, + { + "name" : "minecraft:spruce_button", + "id" : -144 + }, + { + "name" : "minecraft:glowstone_dust", + "id" : 348 + }, + { + "name" : "minecraft:blaze_rod", + "id" : 369 + }, + { + "name" : "minecraft:dye", + "id" : 351 + }, + { + "name" : "minecraft:element_74", + "id" : -85 + }, + { + "name" : "minecraft:bone", + "id" : 352 + }, + { + "name" : "minecraft:map", + "id" : 358 + }, + { + "name" : "minecraft:sugar", + "id" : 353 + }, + { + "name" : "minecraft:name_tag", + "id" : 421 + }, + { + "name" : "minecraft:cake", + "id" : 354 + }, + { + "name" : "minecraft:bed", + "id" : 355 + }, + { + "name" : "minecraft:stained_glass", + "id" : 241 + }, + { + "name" : "minecraft:repeater", + "id" : 356 + }, + { + "name" : "minecraft:beacon", + "id" : 138 + }, + { + "name" : "minecraft:netherite_chestplate", + "id" : 749 + }, + { + "name" : "minecraft:unpowered_comparator", + "id" : 149 + }, + { + "name" : "minecraft:shears", + "id" : 359 + }, + { + "name" : "minecraft:element_31", + "id" : -42 + }, + { + "name" : "minecraft:ender_pearl", + "id" : 368 + }, + { + "name" : "minecraft:red_sandstone_stairs", + "id" : 180 + }, + { + "name" : "minecraft:carved_pumpkin", + "id" : -155 + }, + { + "name" : "minecraft:ghast_tear", + "id" : 370 + }, + { + "name" : "minecraft:glass_bottle", + "id" : 374 + }, + { + "name" : "minecraft:element_44", + "id" : -55 + }, + { + "name" : "minecraft:lava", + "id" : 11 + }, + { + "name" : "minecraft:polished_blackstone_brick_stairs", + "id" : -275 + }, + { + "name" : "minecraft:jungle_pressure_plate", + "id" : -153 + }, + { + "name" : "minecraft:fermented_spider_eye", + "id" : 376 + }, + { + "name" : "minecraft:honeycomb_block", + "id" : -221 + }, + { + "name" : "minecraft:blaze_powder", + "id" : 377 + }, + { + "name" : "minecraft:magma_cream", + "id" : 378 + }, + { + "name" : "minecraft:jigsaw", + "id" : -211 + }, + { + "name" : "minecraft:brewing_stand", + "id" : 379 + }, + { + "name" : "minecraft:cauldron", + "id" : 380 + }, + { + "name" : "minecraft:element_111", + "id" : -122 + }, + { + "name" : "minecraft:rapid_fertilizer", + "id" : 449 + }, + { + "name" : "minecraft:clay", + "id" : 82 + }, + { + "name" : "minecraft:speckled_melon", + "id" : 382 + }, + { + "name" : "minecraft:experience_bottle", + "id" : 384 + }, + { + "name" : "minecraft:element_48", + "id" : -59 + }, + { + "name" : "minecraft:coal_block", + "id" : 173 + }, + { + "name" : "minecraft:fireball", + "id" : 385 + }, + { + "name" : "minecraft:writable_book", + "id" : 386 + }, + { + "name" : "minecraft:element_69", + "id" : -80 + }, + { + "name" : "minecraft:emerald", + "id" : 388 + }, + { + "name" : "minecraft:record_pigstep", + "id" : 759 + }, + { + "name" : "minecraft:element_66", + "id" : -77 + }, + { + "name" : "minecraft:frame", + "id" : 389 + }, + { + "name" : "minecraft:brewingstandblock", + "id" : 117 + }, + { + "name" : "minecraft:flower_pot", + "id" : 390 + }, + { + "name" : "minecraft:emptymap", + "id" : 395 + }, + { + "name" : "minecraft:element_110", + "id" : -121 + }, + { + "name" : "minecraft:element_75", + "id" : -86 + }, + { + "name" : "minecraft:skull", + "id" : 397 + }, + { + "name" : "minecraft:crimson_door", + "id" : 755 + }, + { + "name" : "minecraft:sponge", + "id" : 19 + }, + { + "name" : "minecraft:netherstar", + "id" : 399 + }, + { + "name" : "minecraft:fireworks", + "id" : 401 + }, + { + "name" : "minecraft:hopper_minecart", + "id" : 408 + }, + { + "name" : "minecraft:fireworkscharge", + "id" : 402 + }, + { + "name" : "minecraft:enchanted_book", + "id" : 403 + }, + { + "name" : "minecraft:netherbrick", + "id" : 405 + }, + { + "name" : "minecraft:cobblestone_wall", + "id" : 139 + }, + { + "name" : "minecraft:quartz", + "id" : 406 + }, + { + "name" : "minecraft:tnt_minecart", + "id" : 407 + }, + { + "name" : "minecraft:element_63", + "id" : -74 + }, + { + "name" : "minecraft:hopper", + "id" : 410 + }, + { + "name" : "minecraft:cobblestone", + "id" : 4 + }, + { + "name" : "minecraft:dragon_breath", + "id" : 437 + }, + { + "name" : "minecraft:rabbit_hide", + "id" : 415 + }, + { + "name" : "minecraft:horsearmoriron", + "id" : 417 + }, + { + "name" : "minecraft:horsearmorgold", + "id" : 418 + }, + { + "name" : "minecraft:colored_torch_bp", + "id" : 204 + }, + { + "name" : "minecraft:element_102", + "id" : -113 + }, + { + "name" : "minecraft:quartz_ore", + "id" : 153 + }, + { + "name" : "minecraft:netherite_shovel", + "id" : 744 + }, + { + "name" : "minecraft:horsearmordiamond", + "id" : 419 + }, + { + "name" : "minecraft:record_13", + "id" : 500 + }, + { + "name" : "minecraft:record_cat", + "id" : 501 + }, + { + "name" : "minecraft:element_3", + "id" : -14 + }, + { + "name" : "minecraft:polished_diorite_stairs", + "id" : -173 + }, + { + "name" : "minecraft:monster_egg", + "id" : 97 + }, + { + "name" : "minecraft:record_blocks", + "id" : 502 + }, + { + "name" : "minecraft:crimson_standing_sign", + "id" : -250 + }, + { + "name" : "minecraft:record_chirp", + "id" : 503 + }, + { + "name" : "minecraft:record_mall", + "id" : 505 + }, + { + "name" : "minecraft:respawn_anchor", + "id" : -272 + }, + { + "name" : "minecraft:record_stal", + "id" : 507 + }, + { + "name" : "minecraft:record_11", + "id" : 510 + }, + { + "name" : "minecraft:record_wait", + "id" : 511 + }, + { + "name" : "minecraft:info_update2", + "id" : 249 + }, + { + "name" : "minecraft:lead", + "id" : 420 + }, + { + "name" : "minecraft:prismarine_crystals", + "id" : 422 + }, + { + "name" : "minecraft:acacia_sign", + "id" : 475 + }, + { + "name" : "minecraft:muttoncooked", + "id" : 424 + }, + { + "name" : "minecraft:armor_stand", + "id" : 425 + }, + { + "name" : "minecraft:coal_ore", + "id" : 16 + }, + { + "name" : "minecraft:element_32", + "id" : -43 + }, + { + "name" : "minecraft:spruce_door", + "id" : 427 + }, + { + "name" : "minecraft:phantom_membrane", + "id" : 470 + }, + { + "name" : "minecraft:birch_door", + "id" : 428 + }, + { + "name" : "minecraft:element_85", + "id" : -96 + }, + { + "name" : "minecraft:polished_blackstone_wall", + "id" : -297 + }, + { + "name" : "minecraft:jungle_door", + "id" : 429 + }, + { + "name" : "minecraft:acacia_door", + "id" : 430 + }, + { + "name" : "minecraft:element_42", + "id" : -53 + }, + { + "name" : "minecraft:dark_oak_door", + "id" : 431 + }, + { + "name" : "minecraft:netherite_leggings", + "id" : 750 + }, + { + "name" : "minecraft:stripped_crimson_stem", + "id" : -240 + }, + { + "name" : "minecraft:chorus_fruit", + "id" : 432 + }, + { + "name" : "minecraft:camera", + "id" : 498 + }, + { + "name" : "minecraft:suspicious_stew", + "id" : 734 + }, + { + "name" : "minecraft:chorus_fruit_popped", + "id" : 433 + }, + { + "name" : "minecraft:element_98", + "id" : -109 + }, + { + "name" : "minecraft:splash_potion", + "id" : 438 + }, + { + "name" : "minecraft:element_73", + "id" : -84 + }, + { + "name" : "minecraft:prismarine_shard", + "id" : 409 + }, + { + "name" : "minecraft:seagrass", + "id" : -130 + }, + { + "name" : "minecraft:dark_oak_pressure_plate", + "id" : -152 + }, + { + "name" : "minecraft:shulker_shell", + "id" : 445 + }, + { + "name" : "minecraft:redstone_block", + "id" : 152 + }, + { + "name" : "minecraft:banner", + "id" : 446 + }, + { + "name" : "minecraft:totem", + "id" : 450 + }, + { + "name" : "minecraft:blackstone_slab", + "id" : -282 }, { "name" : "minecraft:element_118", "id" : -129 }, { - "name" : "minecraft:element_12", - "id" : -23 + "name" : "minecraft:iron_nugget", + "id" : 452 }, { - "name" : "minecraft:element_13", - "id" : -24 + "name" : "minecraft:netherite_pickaxe", + "id" : 745 + }, + { + "name" : "minecraft:jukebox", + "id" : 84 + }, + { + "name" : "minecraft:turtle_shell_piece", + "id" : 468 + }, + { + "name" : "minecraft:turtle_helmet", + "id" : 469 + }, + { + "name" : "minecraft:crossbow", + "id" : 471 + }, + { + "name" : "minecraft:glowingobsidian", + "id" : 246 + }, + { + "name" : "minecraft:leaves2", + "id" : 161 + }, + { + "name" : "minecraft:spruce_sign", + "id" : 472 + }, + { + "name" : "minecraft:element_38", + "id" : -49 + }, + { + "name" : "minecraft:coral_fan_hang2", + "id" : -136 + }, + { + "name" : "minecraft:birch_sign", + "id" : 473 + }, + { + "name" : "minecraft:coral_fan_dead", + "id" : -134 + }, + { + "name" : "minecraft:balloon", + "id" : 448 + }, + { + "name" : "minecraft:jungle_sign", + "id" : 474 + }, + { + "name" : "minecraft:darkoak_sign", + "id" : 476 + }, + { + "name" : "minecraft:element_24", + "id" : -35 + }, + { + "name" : "minecraft:banner_pattern", + "id" : 434 + }, + { + "name" : "minecraft:honeycomb", + "id" : 736 + }, + { + "name" : "minecraft:element_78", + "id" : -89 + }, + { + "name" : "minecraft:red_nether_brick", + "id" : 215 + }, + { + "name" : "minecraft:honey_bottle", + "id" : 737 + }, + { + "name" : "minecraft:compound", + "id" : 499 + }, + { + "name" : "minecraft:ice_bomb", + "id" : 453 + }, + { + "name" : "minecraft:brick_block", + "id" : 45 + }, + { + "name" : "minecraft:bleach", + "id" : 451 + }, + { + "name" : "minecraft:colored_torch_rg", + "id" : 202 + }, + { + "name" : "minecraft:medicine", + "id" : 447 + }, + { + "name" : "minecraft:warped_fungus", + "id" : -229 + }, + { + "name" : "minecraft:end_portal_frame", + "id" : 120 + }, + { + "name" : "minecraft:element_92", + "id" : -103 + }, + { + "name" : "minecraft:glow_stick", + "id" : 166 + }, + { + "name" : "minecraft:lodestonecompass", + "id" : 741 + }, + { + "name" : "minecraft:element_17", + "id" : -28 + }, + { + "name" : "minecraft:lit_pumpkin", + "id" : 91 + }, + { + "name" : "minecraft:netherite_ingot", + "id" : 742 + }, + { + "name" : "minecraft:chain_command_block", + "id" : 189 + }, + { + "name" : "minecraft:loom", + "id" : -204 + }, + { + "name" : "minecraft:item.warped_door", + "id" : -245 + }, + { + "name" : "minecraft:netherite_axe", + "id" : 746 + }, + { + "name" : "minecraft:netherite_hoe", + "id" : 747 + }, + { + "name" : "minecraft:dark_oak_fence_gate", + "id" : 186 + }, + { + "name" : "minecraft:element_115", + "id" : -126 + }, + { + "name" : "minecraft:netherite_helmet", + "id" : 748 + }, + { + "name" : "minecraft:element_117", + "id" : -128 + }, + { + "name" : "minecraft:netherite_scrap", + "id" : 752 + }, + { + "name" : "minecraft:crimson_sign", + "id" : 753 + }, + { + "name" : "minecraft:concrete", + "id" : 236 + }, + { + "name" : "minecraft:chiseled_nether_bricks", + "id" : -302 + }, + { + "name" : "minecraft:mob_spawner", + "id" : 52 + }, + { + "name" : "minecraft:warped_sign", + "id" : 754 + }, + { + "name" : "minecraft:chain", + "id" : 758 + }, + { + "name" : "minecraft:warped_fungus_on_a_stick", + "id" : 757 + }, + { + "name" : "minecraft:nether_sprouts", + "id" : 760 + }, + { + "name" : "minecraft:cartography_table", + "id" : -200 + }, + { + "name" : "minecraft:polished_blackstone_slab", + "id" : -293 + }, + { + "name" : "minecraft:soul_campfire", + "id" : 801 + }, + { + "name" : "minecraft:stone", + "id" : 1 + }, + { + "name" : "minecraft:wool", + "id" : 35 + }, + { + "name" : "minecraft:yellow_flower", + "id" : 37 + }, + { + "name" : "minecraft:stained_hardened_clay", + "id" : 159 + }, + { + "name" : "minecraft:log", + "id" : 17 + }, + { + "name" : "minecraft:fence", + "id" : 85 + }, + { + "name" : "minecraft:element_53", + "id" : -64 + }, + { + "name" : "minecraft:stonebrick", + "id" : 98 + }, + { + "name" : "minecraft:lit_blast_furnace", + "id" : -214 + }, + { + "name" : "minecraft:coral_block", + "id" : -132 + }, + { + "name" : "minecraft:polished_blackstone_bricks", + "id" : -274 + }, + { + "name" : "minecraft:double_stone_slab", + "id" : 44 + }, + { + "name" : "minecraft:element_100", + "id" : -111 + }, + { + "name" : "minecraft:double_stone_slab2", + "id" : 182 + }, + { + "name" : "minecraft:fence_gate", + "id" : 107 + }, + { + "name" : "minecraft:double_stone_slab3", + "id" : -162 + }, + { + "name" : "minecraft:rail", + "id" : 66 + }, + { + "name" : "minecraft:double_stone_slab4", + "id" : -166 + }, + { + "name" : "minecraft:stripped_acacia_log", + "id" : -8 + }, + { + "name" : "minecraft:real_double_stone_slab", + "id" : 43 + }, + { + "name" : "minecraft:coral_fan", + "id" : -133 + }, + { + "name" : "minecraft:sea_pickle", + "id" : -156 + }, + { + "name" : "minecraft:polished_blackstone_button", + "id" : -296 + }, + { + "name" : "minecraft:element_90", + "id" : -101 + }, + { + "name" : "minecraft:polished_blackstone_double_slab", + "id" : -294 + }, + { + "name" : "minecraft:sapling", + "id" : 6 + }, + { + "name" : "minecraft:leaves", + "id" : 18 + }, + { + "name" : "minecraft:sandstone", + "id" : 24 + }, + { + "name" : "minecraft:silver_glazed_terracotta", + "id" : 228 + }, + { + "name" : "minecraft:wooden_slab", + "id" : 158 + }, + { + "name" : "minecraft:warped_roots", + "id" : -224 + }, + { + "name" : "minecraft:element_11", + "id" : -22 + }, + { + "name" : "minecraft:red_flower", + "id" : 38 + }, + { + "name" : "minecraft:element_59", + "id" : -70 + }, + { + "name" : "minecraft:double_plant", + "id" : 175 + }, + { + "name" : "minecraft:waterlily", + "id" : 111 + }, + { + "name" : "minecraft:quartz_block", + "id" : 155 + }, + { + "name" : "minecraft:element_95", + "id" : -106 + }, + { + "name" : "minecraft:soul_soil", + "id" : -236 + }, + { + "name" : "minecraft:acacia_pressure_plate", + "id" : -150 + }, + { + "name" : "minecraft:tallgrass", + "id" : 31 + }, + { + "name" : "minecraft:brown_mushroom_block", + "id" : 99 + }, + { + "name" : "minecraft:element_103", + "id" : -114 + }, + { + "name" : "minecraft:crimson_fungus", + "id" : -228 + }, + { + "name" : "minecraft:item.frame", + "id" : 199 + }, + { + "name" : "minecraft:red_mushroom_block", + "id" : 100 + }, + { + "name" : "minecraft:log2", + "id" : 162 + }, + { + "name" : "minecraft:conduit", + "id" : -157 + }, + { + "name" : "minecraft:prismarine", + "id" : 168 + }, + { + "name" : "minecraft:magma", + "id" : 213 + }, + { + "name" : "minecraft:element_22", + "id" : -33 + }, + { + "name" : "minecraft:undyed_shulker_box", + "id" : 205 + }, + { + "name" : "minecraft:shulker_box", + "id" : 218 + }, + { + "name" : "minecraft:spruce_standing_sign", + "id" : -181 + }, + { + "name" : "minecraft:sticky_piston", + "id" : 29 + }, + { + "name" : "minecraft:element_10", + "id" : -21 + }, + { + "name" : "minecraft:turtle_egg", + "id" : -159 + }, + { + "name" : "minecraft:bamboo", + "id" : -163 + }, + { + "name" : "minecraft:observer", + "id" : 251 + }, + { + "name" : "minecraft:scaffolding", + "id" : -165 + }, + { + "name" : "minecraft:blast_furnace", + "id" : -196 + }, + { + "name" : "minecraft:grindstone", + "id" : -195 + }, + { + "name" : "minecraft:bell", + "id" : -206 + }, + { + "name" : "minecraft:end_rod", + "id" : 208 + }, + { + "name" : "minecraft:fletching_table", + "id" : -201 + }, + { + "name" : "minecraft:item.hopper", + "id" : 154 + }, + { + "name" : "minecraft:wood", + "id" : -212 + }, + { + "name" : "minecraft:chemistry_table", + "id" : 238 + }, + { + "name" : "minecraft:tnt", + "id" : 46 + }, + { + "name" : "minecraft:hard_stained_glass_pane", + "id" : 191 + }, + { + "name" : "minecraft:crimson_slab", + "id" : -264 + }, + { + "name" : "minecraft:element_87", + "id" : -98 + }, + { + "name" : "minecraft:warped_slab", + "id" : -265 + }, + { + "name" : "minecraft:element_0", + "id" : 36 + }, + { + "name" : "minecraft:element_4", + "id" : -15 + }, + { + "name" : "minecraft:ender_chest", + "id" : 130 + }, + { + "name" : "minecraft:element_5", + "id" : -16 + }, + { + "name" : "minecraft:element_6", + "id" : -17 + }, + { + "name" : "minecraft:element_8", + "id" : -19 + }, + { + "name" : "minecraft:element_9", + "id" : -20 + }, + { + "name" : "minecraft:element_12", + "id" : -23 }, { "name" : "minecraft:element_14", @@ -1047,14 +2107,6 @@ "name" : "minecraft:element_15", "id" : -26 }, - { - "name" : "minecraft:element_16", - "id" : -27 - }, - { - "name" : "minecraft:element_17", - "id" : -28 - }, { "name" : "minecraft:element_18", "id" : -29 @@ -1063,10 +2115,6 @@ "name" : "minecraft:element_19", "id" : -30 }, - { - "name" : "minecraft:element_2", - "id" : -13 - }, { "name" : "minecraft:element_20", "id" : -31 @@ -1075,30 +2123,10 @@ "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 @@ -1107,22 +2135,6 @@ "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 @@ -1131,30 +2143,22 @@ "name" : "minecraft:element_34", "id" : -45 }, - { - "name" : "minecraft:element_35", - "id" : -46 - }, { "name" : "minecraft:element_36", "id" : -47 }, + { + "name" : "minecraft:ice", + "id" : 79 + }, { "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 @@ -1163,18 +2167,6 @@ "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 @@ -1183,50 +2175,34 @@ "name" : "minecraft:element_46", "id" : -57 }, + { + "name" : "minecraft:netherite_block", + "id" : -270 + }, { "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:black_glazed_terracotta", + "id" : 235 + }, + { + "name" : "minecraft:lit_redstone_ore", + "id" : 74 + }, + { + "name" : "minecraft:crafting_table", + "id" : 58 + }, { "name" : "minecraft:element_57", "id" : -68 @@ -1235,30 +2211,10 @@ "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 @@ -1267,69 +2223,45 @@ "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:dark_oak_button", + "id" : -142 + }, { "name" : "minecraft:element_77", "id" : -88 }, { - "name" : "minecraft:element_78", - "id" : -89 + "name" : "minecraft:diorite_stairs", + "id" : -170 + }, + { + "name" : "minecraft:redstone_torch", + "id" : 76 }, { "name" : "minecraft:element_79", "id" : -90 }, { - "name" : "minecraft:element_8", - "id" : -19 + "name" : "minecraft:iron_bars", + "id" : 101 }, { "name" : "minecraft:element_80", @@ -1343,62 +2275,26 @@ "name" : "minecraft:element_82", "id" : -93 }, + { + "name" : "minecraft:underwater_torch", + "id" : 239 + }, + { + "name" : "minecraft:blue_ice", + "id" : -11 + }, { "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 @@ -1408,2251 +2304,927 @@ "id" : -108 }, { - "name" : "minecraft:element_98", - "id" : -109 + "name" : "minecraft:cactus", + "id" : 81 }, { "name" : "minecraft:element_99", "id" : -110 }, { - "name" : "minecraft:elytra", - "id" : 554 + "name" : "minecraft:element_105", + "id" : -116 }, { - "name" : "minecraft:emerald", - "id" : 502 + "name" : "minecraft:element_106", + "id" : -117 }, { - "name" : "minecraft:emerald_block", - "id" : 133 + "name" : "minecraft:cyan_glazed_terracotta", + "id" : 229 }, { - "name" : "minecraft:emerald_ore", - "id" : 129 + "name" : "minecraft:element_107", + "id" : -118 }, { - "name" : "minecraft:empty_map", - "id" : 505 + "name" : "minecraft:element_108", + "id" : -119 }, { - "name" : "minecraft:enchanted_book", - "id" : 511 + "name" : "minecraft:element_109", + "id" : -120 }, { - "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:element_112", + "id" : -123 }, { "name" : "minecraft:warped_button", "id" : -261 }, { - "name" : "minecraft:warped_door", - "id" : 605 + "name" : "minecraft:element_113", + "id" : -124 }, { - "name" : "minecraft:warped_double_slab", - "id" : -267 + "name" : "minecraft:birch_stairs", + "id" : 135 }, { - "name" : "minecraft:warped_fence", - "id" : -257 + "name" : "minecraft:element_114", + "id" : -125 }, { - "name" : "minecraft:warped_fence_gate", - "id" : -259 + "name" : "minecraft:composter", + "id" : -213 }, { - "name" : "minecraft:warped_fungus", - "id" : -229 + "name" : "minecraft:crying_obsidian", + "id" : -289 }, { - "name" : "minecraft:warped_fungus_on_a_stick", - "id" : 606 + "name" : "minecraft:end_crystal", + "id" : 426 }, { - "name" : "minecraft:warped_hyphae", - "id" : -298 + "name" : "minecraft:tripwire_hook", + "id" : 131 }, { - "name" : "minecraft:warped_nylium", - "id" : -233 + "name" : "minecraft:blue_glazed_terracotta", + "id" : 231 }, { - "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:daylight_detector_inverted", + "id" : 178 }, { "name" : "minecraft:warped_trapdoor", "id" : -247 }, + { + "name" : "minecraft:twisting_vines", + "id" : -287 + }, + { + "name" : "minecraft:noteblock", + "id" : 25 + }, + { + "name" : "minecraft:gravel", + "id" : 13 + }, + { + "name" : "minecraft:golden_rail", + "id" : 27 + }, { "name" : "minecraft:warped_wall_sign", "id" : -253 }, { - "name" : "minecraft:warped_wart_block", - "id" : -227 + "name" : "minecraft:oak_stairs", + "id" : 53 + }, + { + "name" : "minecraft:grass", + "id" : 2 + }, + { + "name" : "minecraft:acacia_button", + "id" : -140 + }, + { + "name" : "minecraft:snow", + "id" : 80 + }, + { + "name" : "minecraft:detector_rail", + "id" : 28 + }, + { + "name" : "minecraft:dark_oak_trapdoor", + "id" : -147 + }, + { + "name" : "minecraft:spruce_pressure_plate", + "id" : -154 }, { "name" : "minecraft:water", "id" : 9 }, { - "name" : "minecraft:water_bucket", - "id" : 362 + "name" : "minecraft:furnace", + "id" : 61 }, { - "name" : "minecraft:waterlily", - "id" : 111 + "name" : "minecraft:item.wooden_door", + "id" : 64 + }, + { + "name" : "minecraft:gold_ore", + "id" : 14 }, { "name" : "minecraft:web", "id" : 30 }, { - "name" : "minecraft:weeping_vines", - "id" : -231 + "name" : "minecraft:unlit_redstone_torch", + "id" : 75 }, { - "name" : "minecraft:wheat", - "id" : 334 + "name" : "minecraft:ladder", + "id" : 65 }, { - "name" : "minecraft:wheat_seeds", - "id" : 291 + "name" : "minecraft:sweet_berry_bush", + "id" : -207 }, { - "name" : "minecraft:white_dye", - "id" : 408 + "name" : "minecraft:standing_sign", + "id" : 63 }, { - "name" : "minecraft:white_glazed_terracotta", - "id" : 220 + "name" : "minecraft:glass", + "id" : 20 }, { - "name" : "minecraft:witch_spawn_egg", - "id" : 450 + "name" : "minecraft:lapis_ore", + "id" : 21 + }, + { + "name" : "minecraft:bookshelf", + "id" : 47 + }, + { + "name" : "minecraft:item.bed", + "id" : 26 + }, + { + "name" : "minecraft:stripped_warped_hyphae", + "id" : -301 }, { "name" : "minecraft:wither_rose", "id" : -216 }, { - "name" : "minecraft:wither_skeleton_spawn_egg", - "id" : 462 + "name" : "minecraft:wooden_pressure_plate", + "id" : 72 }, { - "name" : "minecraft:wolf_spawn_egg", - "id" : 437 + "name" : "minecraft:powered_comparator", + "id" : 150 }, { - "name" : "minecraft:wood", - "id" : -212 + "name" : "minecraft:lapis_block", + "id" : 22 }, { - "name" : "minecraft:wooden_axe", - "id" : 311 + "name" : "minecraft:dispenser", + "id" : 23 + }, + { + "name" : "minecraft:item.wheat", + "id" : 59 + }, + { + "name" : "minecraft:item.spruce_door", + "id" : 193 + }, + { + "name" : "minecraft:diamond_ore", + "id" : 56 + }, + { + "name" : "minecraft:deadbush", + "id" : 32 + }, + { + "name" : "minecraft:pistonarmcollision", + "id" : 34 + }, + { + "name" : "minecraft:blackstone_stairs", + "id" : -276 + }, + { + "name" : "minecraft:dried_kelp_block", + "id" : -139 + }, + { + "name" : "minecraft:item.soul_campfire", + "id" : -290 + }, + { + "name" : "minecraft:green_glazed_terracotta", + "id" : 233 + }, + { + "name" : "minecraft:crimson_pressure_plate", + "id" : -262 + }, + { + "name" : "minecraft:spruce_fence_gate", + "id" : 183 + }, + { + "name" : "minecraft:iron_block", + "id" : 42 + }, + { + "name" : "minecraft:lever", + "id" : 69 + }, + { + "name" : "minecraft:mossy_cobblestone", + "id" : 48 + }, + { + "name" : "minecraft:torch", + "id" : 50 + }, + { + "name" : "minecraft:acacia_fence_gate", + "id" : 187 + }, + { + "name" : "minecraft:quartz_stairs", + "id" : 156 + }, + { + "name" : "minecraft:dragon_egg", + "id" : 122 + }, + { + "name" : "minecraft:lava_cauldron", + "id" : -210 + }, + { + "name" : "minecraft:jungle_standing_sign", + "id" : -188 + }, + { + "name" : "minecraft:redstone_wire", + "id" : 55 + }, + { + "name" : "minecraft:jungle_wall_sign", + "id" : -189 + }, + { + "name" : "minecraft:lit_furnace", + "id" : 62 + }, + { + "name" : "minecraft:beehive", + "id" : -219 + }, + { + "name" : "minecraft:crimson_wall_sign", + "id" : -252 + }, + { + "name" : "minecraft:stone_stairs", + "id" : 67 + }, + { + "name" : "minecraft:orange_glazed_terracotta", + "id" : 221 + }, + { + "name" : "minecraft:brick_stairs", + "id" : 108 + }, + { + "name" : "minecraft:wall_sign", + "id" : 68 + }, + { + "name" : "minecraft:warped_nylium", + "id" : -233 + }, + { + "name" : "minecraft:quartz_bricks", + "id" : -304 + }, + { + "name" : "minecraft:item.iron_door", + "id" : 71 + }, + { + "name" : "minecraft:redstone_ore", + "id" : 73 + }, + { + "name" : "minecraft:lectern", + "id" : -194 + }, + { + "name" : "minecraft:gilded_blackstone", + "id" : -281 + }, + { + "name" : "minecraft:red_nether_brick_stairs", + "id" : -184 + }, + { + "name" : "minecraft:basalt", + "id" : -234 + }, + { + "name" : "minecraft:stone_button", + "id" : 77 + }, + { + "name" : "minecraft:netherrack", + "id" : 87 + }, + { + "name" : "minecraft:nether_brick_stairs", + "id" : 114 + }, + { + "name" : "minecraft:item.acacia_door", + "id" : 196 + }, + { + "name" : "minecraft:item.cake", + "id" : 92 + }, + { + "name" : "minecraft:unpowered_repeater", + "id" : 93 + }, + { + "name" : "minecraft:powered_repeater", + "id" : 94 + }, + { + "name" : "minecraft:trapdoor", + "id" : 96 + }, + { + "name" : "minecraft:coral_fan_hang3", + "id" : -137 + }, + { + "name" : "minecraft:item.jungle_door", + "id" : 195 + }, + { + "name" : "minecraft:glass_pane", + "id" : 102 + }, + { + "name" : "minecraft:emerald_ore", + "id" : 129 + }, + { + "name" : "minecraft:crimson_planks", + "id" : -242 + }, + { + "name" : "minecraft:crimson_stem", + "id" : -225 + }, + { + "name" : "minecraft:weeping_vines", + "id" : -231 + }, + { + "name" : "minecraft:pumpkin_stem", + "id" : 104 + }, + { + "name" : "minecraft:emerald_block", + "id" : 133 + }, + { + "name" : "minecraft:melon_stem", + "id" : 105 + }, + { + "name" : "minecraft:chemical_heat", + "id" : 192 + }, + { + "name" : "minecraft:warped_wart_block", + "id" : -227 + }, + { + "name" : "minecraft:vine", + "id" : 106 + }, + { + "name" : "minecraft:bamboo_sapling", + "id" : -164 + }, + { + "name" : "minecraft:standing_banner", + "id" : 176 + }, + { + "name" : "minecraft:mycelium", + "id" : 110 + }, + { + "name" : "minecraft:nether_gold_ore", + "id" : -288 + }, + { + "name" : "minecraft:nether_brick", + "id" : 112 + }, + { + "name" : "minecraft:warped_double_slab", + "id" : -267 + }, + { + "name" : "minecraft:nether_brick_fence", + "id" : 113 + }, + { + "name" : "minecraft:sandstone_stairs", + "id" : 128 + }, + { + "name" : "minecraft:item.nether_wart", + "id" : 115 + }, + { + "name" : "minecraft:enchanting_table", + "id" : 116 + }, + { + "name" : "minecraft:end_stone", + "id" : 121 + }, + { + "name" : "minecraft:redstone_lamp", + "id" : 123 + }, + { + "name" : "minecraft:jungle_stairs", + "id" : 136 + }, + { + "name" : "minecraft:dropper", + "id" : 125 + }, + { + "name" : "minecraft:activator_rail", + "id" : 126 + }, + { + "name" : "minecraft:cocoa", + "id" : 127 + }, + { + "name" : "minecraft:soul_torch", + "id" : -268 + }, + { + "name" : "minecraft:info_update", + "id" : 248 + }, + { + "name" : "minecraft:packed_ice", + "id" : 174 + }, + { + "name" : "minecraft:coral_fan_hang", + "id" : -135 + }, + { + "name" : "minecraft:item.flower_pot", + "id" : 140 + }, + { + "name" : "minecraft:potatoes", + "id" : 142 }, { "name" : "minecraft:wooden_button", "id" : 143 }, { - "name" : "minecraft:wooden_door", - "id" : 359 + "name" : "minecraft:item.skull", + "id" : 144 }, { - "name" : "minecraft:wooden_hoe", - "id" : 329 + "name" : "minecraft:heavy_weighted_pressure_plate", + "id" : 148 }, { - "name" : "minecraft:wooden_pickaxe", - "id" : 310 + "name" : "minecraft:purple_glazed_terracotta", + "id" : 219 }, { - "name" : "minecraft:wooden_pressure_plate", - "id" : 72 + "name" : "minecraft:stripped_jungle_log", + "id" : -7 }, { - "name" : "minecraft:wooden_shovel", - "id" : 309 + "name" : "minecraft:hardened_clay", + "id" : 172 }, { - "name" : "minecraft:wooden_slab", - "id" : 158 + "name" : "minecraft:warped_planks", + "id" : -243 }, { - "name" : "minecraft:wooden_sword", - "id" : 308 + "name" : "minecraft:acacia_wall_sign", + "id" : -191 }, { - "name" : "minecraft:wool", - "id" : 35 + "name" : "minecraft:purpur_stairs", + "id" : 203 }, { - "name" : "minecraft:writable_book", - "id" : 500 + "name" : "minecraft:wall_banner", + "id" : 177 }, { - "name" : "minecraft:written_book", - "id" : 501 + "name" : "minecraft:spruce_trapdoor", + "id" : -149 }, { - "name" : "minecraft:yellow_dye", - "id" : 404 + "name" : "minecraft:repeating_command_block", + "id" : 188 }, { - "name" : "minecraft:yellow_flower", - "id" : 37 + "name" : "minecraft:item.chain", + "id" : -286 }, { - "name" : "minecraft:yellow_glazed_terracotta", - "id" : 224 + "name" : "minecraft:item.birch_door", + "id" : 194 }, { - "name" : "minecraft:zoglin_spawn_egg", - "id" : 496 + "name" : "minecraft:grass_path", + "id" : 198 }, { - "name" : "minecraft:zombie_horse_spawn_egg", - "id" : 466 + "name" : "minecraft:blackstone", + "id" : -273 }, { - "name" : "minecraft:zombie_pigman_spawn_egg", - "id" : 446 + "name" : "minecraft:chorus_flower", + "id" : 200 }, { - "name" : "minecraft:zombie_spawn_egg", - "id" : 445 + "name" : "minecraft:normal_stone_stairs", + "id" : -180 }, { - "name" : "minecraft:zombie_villager_spawn_egg", - "id" : 475 + "name" : "minecraft:barrier", + "id" : -161 + }, + { + "name" : "minecraft:frosted_ice", + "id" : 207 + }, + { + "name" : "minecraft:structure_block", + "id" : 252 + }, + { + "name" : "minecraft:allow", + "id" : 210 + }, + { + "name" : "minecraft:pink_glazed_terracotta", + "id" : 226 + }, + { + "name" : "minecraft:deny", + "id" : 211 + }, + { + "name" : "minecraft:border_block", + "id" : 212 + }, + { + "name" : "minecraft:movingblock", + "id" : 250 + }, + { + "name" : "minecraft:bone_block", + "id" : 216 + }, + { + "name" : "minecraft:structure_void", + "id" : 217 + }, + { + "name" : "minecraft:white_glazed_terracotta", + "id" : 220 + }, + { + "name" : "minecraft:magenta_glazed_terracotta", + "id" : 222 + }, + { + "name" : "minecraft:lime_glazed_terracotta", + "id" : 225 + }, + { + "name" : "minecraft:gray_glazed_terracotta", + "id" : 227 + }, + { + "name" : "minecraft:brown_glazed_terracotta", + "id" : 232 + }, + { + "name" : "minecraft:red_glazed_terracotta", + "id" : 234 + }, + { + "name" : "minecraft:crimson_nylium", + "id" : -232 + }, + { + "name" : "minecraft:acacia_trapdoor", + "id" : -145 + }, + { + "name" : "minecraft:smooth_sandstone_stairs", + "id" : -177 + }, + { + "name" : "minecraft:item.camera", + "id" : 242 + }, + { + "name" : "minecraft:podzol", + "id" : 243 + }, + { + "name" : "minecraft:stonecutter", + "id" : 245 + }, + { + "name" : "minecraft:netherreactor", + "id" : 247 + }, + { + "name" : "minecraft:prismarine_stairs", + "id" : -2 + }, + { + "name" : "minecraft:dark_prismarine_stairs", + "id" : -3 + }, + { + "name" : "minecraft:stripped_spruce_log", + "id" : -5 + }, + { + "name" : "minecraft:stripped_birch_log", + "id" : -6 + }, + { + "name" : "minecraft:stripped_dark_oak_log", + "id" : -9 + }, + { + "name" : "minecraft:fire", + "id" : 51 + }, + { + "name" : "minecraft:hard_glass", + "id" : 253 + }, + { + "name" : "minecraft:acacia_standing_sign", + "id" : -190 + }, + { + "name" : "minecraft:hard_glass_pane", + "id" : 190 + }, + { + "name" : "minecraft:mossy_cobblestone_stairs", + "id" : -179 + }, + { + "name" : "minecraft:crimson_fence_gate", + "id" : -258 + }, + { + "name" : "minecraft:mossy_stone_brick_stairs", + "id" : -175 + }, + { + "name" : "minecraft:item.nether_sprouts", + "id" : -238 + }, + { + "name" : "minecraft:polished_blackstone_brick_double_slab", + "id" : -285 + }, + { + "name" : "minecraft:cracked_polished_blackstone_bricks", + "id" : -280 + }, + { + "name" : "minecraft:smooth_red_sandstone_stairs", + "id" : -176 + }, + { + "name" : "minecraft:shroomlight", + "id" : -230 + }, + { + "name" : "minecraft:stripped_crimson_hyphae", + "id" : -300 + }, + { + "name" : "minecraft:crimson_button", + "id" : -260 + }, + { + "name" : "minecraft:soul_fire", + "id" : -237 + }, + { + "name" : "minecraft:polished_basalt", + "id" : -235 + }, + { + "name" : "minecraft:jungle_button", + "id" : -143 + }, + { + "name" : "minecraft:birch_pressure_plate", + "id" : -151 + }, + { + "name" : "minecraft:stripped_warped_stem", + "id" : -241 + }, + { + "name" : "minecraft:birch_wall_sign", + "id" : -187 + }, + { + "name" : "minecraft:jungle_trapdoor", + "id" : -148 + }, + { + "name" : "minecraft:item.kelp", + "id" : -138 + }, + { + "name" : "minecraft:birch_button", + "id" : -141 + }, + { + "name" : "minecraft:birch_trapdoor", + "id" : -146 + }, + { + "name" : "minecraft:bubble_column", + "id" : -160 + }, + { + "name" : "minecraft:polished_granite_stairs", + "id" : -172 + }, + { + "name" : "minecraft:polished_andesite_stairs", + "id" : -174 + }, + { + "name" : "minecraft:end_brick_stairs", + "id" : -178 + }, + { + "name" : "minecraft:spruce_wall_sign", + "id" : -182 + }, + { + "name" : "minecraft:chiseled_polished_blackstone", + "id" : -279 + }, + { + "name" : "minecraft:birch_standing_sign", + "id" : -186 + }, + { + "name" : "minecraft:darkoak_standing_sign", + "id" : -192 + }, + { + "name" : "minecraft:darkoak_wall_sign", + "id" : -193 + }, + { + "name" : "minecraft:lit_smoker", + "id" : -199 + }, + { + "name" : "minecraft:item.campfire", + "id" : -209 + }, + { + "name" : "minecraft:bee_nest", + "id" : -218 + }, + { + "name" : "minecraft:warped_fence_gate", + "id" : -259 + }, + { + "name" : "minecraft:warped_stem", + "id" : -226 + }, + { + "name" : "minecraft:blackstone_double_slab", + "id" : -283 + }, + { + "name" : "minecraft:target", + "id" : -239 + }, + { + "name" : "minecraft:crimson_trapdoor", + "id" : -246 + }, + { + "name" : "minecraft:polished_blackstone_brick_wall", + "id" : -278 + }, + { + "name" : "minecraft:warped_standing_sign", + "id" : -251 + }, + { + "name" : "minecraft:warped_stairs", + "id" : -255 + }, + { + "name" : "minecraft:crimson_fence", + "id" : -256 + }, + { + "name" : "minecraft:warped_pressure_plate", + "id" : -263 + }, + { + "name" : "minecraft:soul_lantern", + "id" : -269 + }, + { + "name" : "minecraft:blackstone_wall", + "id" : -277 + }, + { + "name" : "minecraft:polished_blackstone", + "id" : -291 + }, + { + "name" : "minecraft:polished_blackstone_stairs", + "id" : -292 + }, + { + "name" : "minecraft:polished_blackstone_pressure_plate", + "id" : -295 + }, + { + "name" : "minecraft:warped_hyphae", + "id" : -298 + }, + { + "name" : "minecraft:crimson_hyphae", + "id" : -299 + }, + { + "name" : "minecraft:cracked_nether_bricks", + "id" : -303 } ] \ 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..27594915 --- /dev/null +++ b/connector/src/main/resources/bedrock/legacy_block_ids.json @@ -0,0 +1,555 @@ +{ + "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:allow" : 210, + "minecraft:deny" : 211, + "minecraft:border_block" : 212, + "minecraft:magma" : 213, + "minecraft:nether_wart_block" : 214, + "minecraft:red_nether_brick" : 215, + "minecraft:bone_block" : 216, + "minecraft:structure_void" : 217, + "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:camera" : 242, + "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, + "minecraft:light_block" : 470, + "minecraft:wither_rose" : 471, + "minecraft:stickyPistonArmCollision" : 472, + "minecraft:bee_nest" : 473, + "minecraft:beehive" : 474, + "minecraft:honey_block" : 475, + "minecraft:honeycomb_block" : 476, + "minecraft:lodestone" : 477, + "minecraft:crimson_roots" : 478, + "minecraft:warped_roots" : 479, + "minecraft:crimson_stem" : 480, + "minecraft:warped_stem" : 481, + "minecraft:warped_wart_block" : 482, + "minecraft:crimson_fungus" : 483, + "minecraft:warped_fungus" : 484, + "minecraft:shroomlight" : 485, + "minecraft:weeping_vines" : 486, + "minecraft:crimson_nylium" : 487, + "minecraft:warped_nylium" : 488, + "minecraft:basalt" : 489, + "minecraft:polished_basalt" : 490, + "minecraft:soul_soil" : 491, + "minecraft:soul_fire" : 492, + "minecraft:nether_sprouts" : 493, + "minecraft:target" : 494, + "minecraft:stripped_crimson_stem" : 495, + "minecraft:stripped_warped_stem" : 496, + "minecraft:crimson_planks" : 497, + "minecraft:warped_planks" : 498, + "minecraft:crimson_door" : 499, + "minecraft:warped_door" : 500, + "minecraft:crimson_trapdoor" : 501, + "minecraft:warped_trapdoor" : 502, + "minecraft:crimson_standing_sign" : 505, + "minecraft:warped_standing_sign" : 506, + "minecraft:crimson_wall_sign" : 507, + "minecraft:warped_wall_sign" : 508, + "minecraft:crimson_stairs" : 509, + "minecraft:warped_stairs" : 510, + "minecraft:crimson_fence" : 511, + "minecraft:warped_fence" : 512, + "minecraft:crimson_fence_gate" : 513, + "minecraft:warped_fence_gate" : 514, + "minecraft:crimson_button" : 515, + "minecraft:warped_button" : 516, + "minecraft:crimson_pressure_plate" : 517, + "minecraft:warped_pressure_plate" : 518, + "minecraft:crimson_slab" : 519, + "minecraft:warped_slab" : 520, + "minecraft:crimson_double_slab" : 521, + "minecraft:warped_double_slab" : 522, + "minecraft:soul_torch" : 523, + "minecraft:soul_lantern" : 524, + "minecraft:netherite_block" : 525, + "minecraft:ancient_debris" : 526, + "minecraft:respawn_anchor" : 527, + "minecraft:blackstone" : 528, + "minecraft:polished_blackstone_bricks" : 529, + "minecraft:polished_blackstone_brick_stairs" : 530, + "minecraft:blackstone_stairs" : 531, + "minecraft:blackstone_wall" : 532, + "minecraft:polished_blackstone_brick_wall" : 533, + "minecraft:chiseled_polished_blackstone" : 534, + "minecraft:cracked_polished_blackstone_bricks" : 535, + "minecraft:gilded_blackstone" : 536, + "minecraft:blackstone_slab" : 537, + "minecraft:blackstone_double_slab" : 538, + "minecraft:polished_blackstone_brick_slab" : 539, + "minecraft:polished_blackstone_brick_double_slab" : 540, + "minecraft:chain" : 541, + "minecraft:twisting_vines" : 542, + "minecraft:nether_gold_ore" : 543, + "minecraft:crying_obsidian" : 544, + "minecraft:soul_campfire" : 545, + "minecraft:polished_blackstone" : 546, + "minecraft:polished_blackstone_stairs" : 547, + "minecraft:polished_blackstone_slab" : 548, + "minecraft:polished_blackstone_double_slab" : 549, + "minecraft:polished_blackstone_pressure_plate" : 550, + "minecraft:polished_blackstone_button" : 551, + "minecraft:polished_blackstone_wall" : 552, + "minecraft:warped_hyphae" : 553, + "minecraft:crimson_hyphae" : 554, + "minecraft:stripped_crimson_hyphae" : 555, + "minecraft:stripped_warped_hyphae" : 556, + "minecraft:chiseled_nether_bricks" : 557, + "minecraft:cracked_nether_bricks" : 558, + "minecraft:quartz_bricks" : 559 +} \ 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..3f22c91c --- /dev/null +++ b/connector/src/main/resources/bedrock/legacy_item_ids.json @@ -0,0 +1,255 @@ +{ + "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:ender_eye" : 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:name_tag" : 421, + "minecraft:prismarine_crystals" : 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:camera" : 498, + "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, + "minecraft:suspicious_stew" : 734, + "minecraft:honeycomb" : 736, + "minecraft:honey_bottle" : 737, + "minecraft:lodestonecompass" : 741, + "minecraft:netherite_ingot" : 742, + "minecraft:netherite_sword" : 743, + "minecraft:netherite_shovel" : 744, + "minecraft:netherite_pickaxe" : 745, + "minecraft:netherite_axe" : 746, + "minecraft:netherite_hoe" : 747, + "minecraft:netherite_helmet" : 748, + "minecraft:netherite_chestplate" : 749, + "minecraft:netherite_leggings" : 750, + "minecraft:netherite_boots" : 751, + "minecraft:netherite_scrap" : 752, + "minecraft:crimson_sign" : 753, + "minecraft:warped_sign" : 754, + "minecraft:crimson_door" : 755, + "minecraft:warped_door" : 756, + "minecraft:warped_fungus_on_a_stick" : 757, + "minecraft:chain" : 758, + "minecraft:record_pigstep" : 759, + "minecraft:nether_sprouts" : 760, + "minecraft:soul_campfire" : 801 +} \ No newline at end of file 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..feeeda66 Binary files /dev/null and b/connector/src/main/resources/bedrock/runtime_block_states.dat differ 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..af588185 100644 --- a/connector/src/main/resources/config.yml +++ b/connector/src/main/resources/config.yml @@ -13,14 +13,14 @@ bedrock: 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. + # Some hosting services change your Java port everytime you open 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. + # The Server Name that will be sent to Minecraft: Bedrock Edition clients. Visible in both the pause menu and the settings menu. server-name: "Geyser" remote: # The IP address of the remote (Java Edition) server @@ -32,41 +32,30 @@ remote: 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 three options enable "ping passthrough" -the MOTD, player count and/or protocol name 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! @@ -101,46 +90,28 @@ 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 # 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 +# 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 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: false # 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 - # Bedrock prevents building and displaying blocks above Y127 in the Nether - # enabling this config option works around that by changing the Nether dimension ID # to the End ID. The main downside to this is that the sky will resemble that of # 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/. @@ -153,12 +124,6 @@ metrics: # 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 @@ -167,8 +132,4 @@ enable-proxy-connections: false # 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 diff --git a/connector/src/main/resources/languages b/connector/src/main/resources/languages index 8141bc6a..93b2caed 160000 --- a/connector/src/main/resources/languages +++ b/connector/src/main/resources/languages @@ -1 +1 @@ -Subproject commit 8141bc6aed878a95ed9ee3ca83a2381f9906c4b4 +Subproject commit 93b2caed3c4ecd94b3c77a87f1b2304a7bf4f062 diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index dd0347bd..ec8b6829 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit dd0347bd51e00e42ea58faaf68b562526c4d2817 +Subproject commit ec8b68297c4d62a9e4d640a8c7e77977062628ee 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..acfdc3d6 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 @@ -71,6 +71,19 @@ + + + releases + nukkitx-releases + https://repo.nukkitx.com/maven-releases + + + snapshots + nukkitx-snapshots + https://repo.nukkitx.com/maven-snapshots + + + org.projectlombok