diff --git a/ap/pom.xml b/ap/pom.xml new file mode 100644 index 000000000..7e263c0d1 --- /dev/null +++ b/ap/pom.xml @@ -0,0 +1,14 @@ + + + 4.0.0 + + org.geysermc + geyser-parent + 1.4.1-SNAPSHOT + + + ap + 1.4.1-SNAPSHOT + \ No newline at end of file diff --git a/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java b/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java new file mode 100644 index 000000000..52a6e3aae --- /dev/null +++ b/ap/src/main/java/org/geysermc/processor/BlockEntityProcessor.java @@ -0,0 +1,38 @@ +/* + * 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.processor; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +@SupportedAnnotationTypes("org.geysermc.connector.network.translators.world.block.entity.BlockEntity") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class BlockEntityProcessor extends ClassProcessor { + public BlockEntityProcessor() { + super("org.geysermc.connector.network.translators.world.block.entity.BlockEntity"); + } +} diff --git a/ap/src/main/java/org/geysermc/processor/ClassProcessor.java b/ap/src/main/java/org/geysermc/processor/ClassProcessor.java new file mode 100644 index 000000000..3531d8794 --- /dev/null +++ b/ap/src/main/java/org/geysermc/processor/ClassProcessor.java @@ -0,0 +1,151 @@ +/* + * 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.processor; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.AnnotationMirror; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.StandardLocation; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +public class ClassProcessor extends AbstractProcessor { + private final String annotationClassName; + + private Path outputPath; + + private final List locations = new ArrayList<>(); + + public ClassProcessor(String annotationClassName) { + this.annotationClassName = annotationClassName; + } + + @Override + public synchronized void init(ProcessingEnvironment processingEnv) { + super.init(processingEnv); + + this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Initializing processor " + this.annotationClassName); + + String outputFile = processingEnv.getOptions().get("metadataOutputFile"); + if (outputFile != null && !outputFile.isEmpty()) { + this.outputPath = Paths.get(outputFile); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) { + if (!roundEnv.errorRaised()) { + complete(); + } + + return false; + } + + if (!contains(annotations, this.annotationClassName)) { + return false; + } + + for (Element element : roundEnv.getRootElements()) { + if (element.getKind() != ElementKind.CLASS) { + continue; + } + + if (!contains(element.getAnnotationMirrors(), this.annotationClassName)) { + continue; + } + + TypeElement typeElement = (TypeElement) element; + this.locations.add(typeElement.getQualifiedName().toString()); + } + return true; + } + + public boolean contains(Collection elements, String className) { + if (elements.isEmpty()) { + return false; + } + + for (TypeElement element : elements) { + if (element.getQualifiedName().contentEquals(className)) { + return true; + } + } + + return false; + } + + public boolean contains(List elements, String className) { + if (elements.isEmpty()) { + return false; + } + + for (AnnotationMirror element : elements) { + if (element.getAnnotationType().toString().equals(className)) { + return true; + } + } + + return false; + } + + public void complete() { + try (BufferedWriter writer = this.createWriter()) { + for (String location : this.locations) { + writer.write(location); + writer.newLine(); + } + } catch (IOException ex) { + ex.printStackTrace(); + } + + this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Completed processing for " + this.annotationClassName); + } + + private BufferedWriter createWriter() throws IOException { + if (this.outputPath != null) { + this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Writing " + this.annotationClassName + " to " + this.outputPath); + return Files.newBufferedWriter(this.outputPath); + } + + FileObject obj = this.processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", this.annotationClassName); + this.processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, "Writing " + this.annotationClassName + " to " + obj.toUri()); + return new BufferedWriter(obj.openWriter()); + } +} diff --git a/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java b/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java new file mode 100644 index 000000000..3f9111155 --- /dev/null +++ b/ap/src/main/java/org/geysermc/processor/CollisionRemapperProcessor.java @@ -0,0 +1,38 @@ +/* + * 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.processor; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +@SupportedAnnotationTypes("org.geysermc.connector.network.translators.collision.CollisionRemapper") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class CollisionRemapperProcessor extends ClassProcessor { + public CollisionRemapperProcessor() { + super("org.geysermc.connector.network.translators.collision.CollisionRemapper"); + } +} diff --git a/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java b/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java new file mode 100644 index 000000000..cbfd939c4 --- /dev/null +++ b/ap/src/main/java/org/geysermc/processor/ItemRemapperProcessor.java @@ -0,0 +1,38 @@ +/* + * 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.processor; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +@SupportedAnnotationTypes("org.geysermc.connector.network.translators.ItemRemapper") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class ItemRemapperProcessor extends ClassProcessor { + public ItemRemapperProcessor() { + super("org.geysermc.connector.network.translators.ItemRemapper"); + } +} diff --git a/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java b/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java new file mode 100644 index 000000000..cdfbcbe4a --- /dev/null +++ b/ap/src/main/java/org/geysermc/processor/PacketTranslatorProcessor.java @@ -0,0 +1,38 @@ +/* + * 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.processor; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +@SupportedAnnotationTypes("org.geysermc.connector.network.translators.Translator") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class PacketTranslatorProcessor extends ClassProcessor { + public PacketTranslatorProcessor() { + super("org.geysermc.connector.network.translators.Translator"); + } +} diff --git a/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java b/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java new file mode 100644 index 000000000..ee4b2ef45 --- /dev/null +++ b/ap/src/main/java/org/geysermc/processor/SoundHandlerProcessor.java @@ -0,0 +1,38 @@ +/* + * 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.processor; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +@SupportedAnnotationTypes("org.geysermc.connector.network.translators.sound.SoundHandler") +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public class SoundHandlerProcessor extends ClassProcessor { + public SoundHandlerProcessor() { + super("org.geysermc.connector.network.translators.sound.SoundHandler"); + } +} diff --git a/bootstrap/bungeecord/pom.xml b/bootstrap/bungeecord/pom.xml index 0f13390d5..839b8982c 100644 --- a/bootstrap/bungeecord/pom.xml +++ b/bootstrap/bungeecord/pom.xml @@ -71,10 +71,6 @@ io.netty.channel.kqueue org.geysermc.platform.bungeecord.shaded.io.netty.channel.kqueue - - org.reflections - org.geysermc.platform.bungeecord.shaded.reflections - com.google.common org.geysermc.platform.bungeecord.shaded.google.common @@ -83,10 +79,6 @@ 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/pom.xml b/bootstrap/pom.xml index 98a08ee31..6bbd1a0b6 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -29,6 +29,16 @@ https://repo.velocitypowered.com/snapshots/ + + + + org.geysermc + ap + 1.4.1-SNAPSHOT + provided + + + bungeecord spigot diff --git a/bootstrap/spigot/pom.xml b/bootstrap/spigot/pom.xml index 133ea7779..4277dc235 100644 --- a/bootstrap/spigot/pom.xml +++ b/bootstrap/spigot/pom.xml @@ -83,10 +83,6 @@ com.fasterxml.jackson org.geysermc.platform.spigot.shaded.jackson - - org.reflections - org.geysermc.platform.spigot.shaded.reflections - com.google.common org.geysermc.platform.spigot.shaded.google.common @@ -95,10 +91,6 @@ 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/sponge/pom.xml b/bootstrap/sponge/pom.xml index e0f019152..77f4fe78a 100644 --- a/bootstrap/sponge/pom.xml +++ b/bootstrap/sponge/pom.xml @@ -69,10 +69,6 @@ it.unimi.dsi.fastutil org.geysermc.platform.sponge.shaded.fastutil - - org.reflections - org.geysermc.platform.sponge.shaded.reflections - com.google.common org.geysermc.platform.sponge.shaded.google.common @@ -81,10 +77,6 @@ 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/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java b/bootstrap/standalone/src/main/java/org/geysermc/platform/standalone/GeyserStandaloneBootstrap.java index 551b0e584..1a25d2792 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 @@ -30,6 +30,7 @@ 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 io.netty.util.ResourceLeakDetector; import lombok.Getter; import net.minecrell.terminalconsole.TerminalConsoleAppender; import org.apache.logging.log4j.Level; @@ -80,6 +81,10 @@ public class GeyserStandaloneBootstrap implements GeyserBootstrap { private static final Map argsConfigKeys = new HashMap<>(); public static void main(String[] args) { + if (System.getProperty("io.netty.leakDetection.level") == null) { + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.DISABLED); // Can eat performance + } + GeyserStandaloneBootstrap bootstrap = new GeyserStandaloneBootstrap(); // Set defaults boolean useGuiOpts = bootstrap.useGui; diff --git a/bootstrap/velocity/pom.xml b/bootstrap/velocity/pom.xml index c67f5a628..5c12b6a46 100644 --- a/bootstrap/velocity/pom.xml +++ b/bootstrap/velocity/pom.xml @@ -65,10 +65,6 @@ it.unimi.dsi.fastutil org.geysermc.platform.velocity.shaded.fastutil - - org.reflections - org.geysermc.platform.velocity.shaded.reflections - com.google.common org.geysermc.platform.velocity.shaded.google.common @@ -77,10 +73,6 @@ com.google.guava org.geysermc.platform.velocity.shaded.google.guava - - org.dom4j - org.geysermc.platform.velocity.shaded.dom4j - net.kyori.adventure.text.serializer.gson.legacyimpl org.geysermc.platform.velocity.shaded.kyori.legacyimpl diff --git a/connector/pom.xml b/connector/pom.xml index 6849066d9..e6cc1c302 100644 --- a/connector/pom.xml +++ b/connector/pom.xml @@ -18,6 +18,12 @@ + + org.geysermc + ap + 1.4.1-SNAPSHOT + provided + org.geysermc common @@ -207,18 +213,6 @@ osx-x86_64 - - org.reflections - reflections - 0.9.11 - compile - - - org.dom4j - dom4j - 2.1.3 - compile - net.kyori @@ -342,54 +336,6 @@ - - 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 diff --git a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java index 291f2d7e5..173e41573 100644 --- a/connector/src/main/java/org/geysermc/connector/GeyserConnector.java +++ b/connector/src/main/java/org/geysermc/connector/GeyserConnector.java @@ -524,18 +524,6 @@ public class GeyserConnector { return !"DEV".equals(GeyserConnector.VERSION); } - /** - * Whether to use XML reflections in the jar or manually find the reflections. - * Will return true if in production 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() { - return !this.getPlatformType().equals(PlatformType.FABRIC) && isProductionEnvironment(); - } - public static GeyserConnector getInstance() { return instance; } 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 3c94f9de2..9aca12ba5 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 @@ -114,7 +114,7 @@ public class VillagerEntity extends AbstractMerchantEntity { if (bedPosition != null) { bedId = session.getConnector().getWorldManager().getBlockAt(session, bedPosition); } - String bedRotationZ = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().get(bedId); + String bedRotationZ = BlockRegistries.JAVA_IDENTIFIERS.get().get(bedId); setRotation(rotation); setOnGround(isOnGround); this.position = Vector3f.from(position.getX() + relX, position.getY() + relY, position.getZ() + relZ); 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 ad2e6d6c6..8f71e6fa8 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 @@ -560,8 +560,10 @@ public class GeyserSession implements CommandSender { } loggingIn = true; - // new thread so clients don't timeout - new Thread(() -> { + + // Use a future to prevent timeouts as all the authentication is handled sync + // This will be changed with the new protocol library. + CompletableFuture.supplyAsync(() -> { try { if (password != null && !password.isEmpty()) { AuthenticationService authenticationService; @@ -587,15 +589,14 @@ public class GeyserSession implements CommandSender { protocol = new MinecraftProtocol(validUsername); } - - connectDownstream(); } catch (InvalidCredentialsException | IllegalArgumentException e) { connector.getLogger().info(LanguageUtils.getLocaleStringLog("geyser.auth.login.invalid", username)); disconnect(LanguageUtils.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode())); } catch (RequestException ex) { ex.printStackTrace(); } - }).start(); + return null; + }).whenComplete((aVoid, ex) -> connectDownstream()); } /** @@ -608,28 +609,31 @@ public class GeyserSession implements CommandSender { } loggingIn = true; + + // This just looks cool + SetTimePacket packet = new SetTimePacket(); + packet.setTime(16000); + sendUpstreamPacket(packet); + // new thread so clients don't timeout - new Thread(() -> { + MsaAuthenticationService msaAuthenticationService = new MsaAuthenticationService(GeyserConnector.OAUTH_CLIENT_ID); + + // Use a future to prevent timeouts as all the authentication is handled sync + // This will be changed with the new protocol library. + CompletableFuture.supplyAsync(() -> { try { - MsaAuthenticationService msaAuthenticationService = new MsaAuthenticationService(GeyserConnector.OAUTH_CLIENT_ID); - - MsaAuthenticationService.MsCodeResponse response = msaAuthenticationService.getAuthCode(); - LoginEncryptionUtils.buildAndShowMicrosoftCodeWindow(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(); + return msaAuthenticationService.getAuthCode(); + } catch (RequestException e) { + throw new CompletionException(e); } - }).start(); + }).whenComplete((response, ex) -> { + if (ex != null) { + ex.printStackTrace(); + return; + } + LoginEncryptionUtils.buildAndShowMicrosoftCodeWindow(this, response); + attemptCodeAuthentication(msaAuthenticationService); + }); } /** @@ -646,7 +650,7 @@ public class GeyserSession implements CommandSender { connectDownstream(); } catch (RequestException e) { if (!(e instanceof AuthPendingException)) { - e.printStackTrace(); + throw new RuntimeException("Failed to log in with Microsoft code!", e); } else { // Wait one second before trying again connector.getGeneralThreadPool().schedule(() -> attemptCodeAuthentication(msaAuthenticationService), 1, TimeUnit.SECONDS); 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 2469f65da..d8f726223 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 @@ -35,13 +35,12 @@ import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LanguageUtils; -import org.reflections.Reflections; -import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.Map; public class PacketTranslatorRegistry { - private final Map, PacketTranslator> translators = new HashMap<>(); + private final Map, PacketTranslator> translators = new IdentityHashMap<>(); public static final PacketTranslatorRegistry JAVA_TRANSLATOR = new PacketTranslatorRegistry<>(); public static final PacketTranslatorRegistry BEDROCK_TRANSLATOR = new PacketTranslatorRegistry<>(); @@ -49,9 +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"); - - for (Class clazz : ref.getTypesAnnotatedWith(Translator.class)) { + for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(Translator.class)) { Class packet = clazz.getAnnotation(Translator.class).packet(); GeyserConnector.getInstance().getLogger().debug("Found annotated translator: " + clazz.getCanonicalName() + " : " + packet.getSimpleName()); 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 6e02d4c6b..589fa49d0 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 @@ -232,7 +232,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator= 2 && session.getGameMode() == GameMode.CREATIVE) { // Otherwise insufficient permissions int blockState = session.getBlockMappings().getJavaBlockState(packet.getBlockRuntimeId()); - String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().inverse().getOrDefault(blockState, ""); + String blockName = BlockRegistries.JAVA_IDENTIFIERS.get().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")) { diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java index c116045cb..2603f2a0f 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/bedrock/entity/player/BedrockActionTranslator.java @@ -178,7 +178,7 @@ public class BedrockActionTranslator extends PacketTranslator 1 && (javaBlockString[0].equals("minecraft:chest") || javaBlockString[0].equals("minecraft:trapped_chest")) && !javaBlockString[1].contains("type=single")) { inventory.setHolderPosition(session.getLastInteractionBlockPosition()); 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 c4d098f79..0fdfc3cc7 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 @@ -43,7 +43,6 @@ import org.geysermc.connector.registry.type.ItemMapping; import org.geysermc.connector.registry.type.ItemMappings; import org.geysermc.connector.utils.FileUtils; import org.geysermc.connector.utils.LocaleUtils; -import org.reflections.Reflections; import java.util.*; import java.util.stream.Collectors; @@ -61,10 +60,8 @@ 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"); - Map loadedNbtItemTranslators = new HashMap<>(); - for (Class clazz : ref.getTypesAnnotatedWith(ItemRemapper.class)) { + for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(ItemRemapper.class)) { int priority = clazz.getAnnotation(ItemRemapper.class).priority(); GeyserConnector.getInstance().getLogger().debug("Found annotated item translator: " + clazz.getCanonicalName()); 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 5abe088a9..d144e99b8 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 @@ -101,7 +101,7 @@ public class JavaBlockChangeTranslator extends PacketTranslator JAVA_BLOCKS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); - public static final MappedRegistry> JAVA_IDENTIFIERS = MappedRegistry.create(RegistryLoaders.empty(HashBiMap::create)); + public static final MappedRegistry> JAVA_IDENTIFIERS = MappedRegistry.create(RegistryLoaders.empty(Object2IntBiMap::new)); public static final SimpleMappedRegistry JAVA_CLEAN_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); diff --git a/connector/src/main/java/org/geysermc/connector/registry/Registries.java b/connector/src/main/java/org/geysermc/connector/registry/Registries.java index e3adb2e16..5ad14cb5a 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/Registries.java +++ b/connector/src/main/java/org/geysermc/connector/registry/Registries.java @@ -58,9 +58,9 @@ import java.util.Set; public class Registries { public static final SimpleRegistry BIOMES = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); - public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.connector.network.translators.world.block.entity", BlockEntityRegistryLoader::new); + public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.connector.network.translators.world.block.entity.BlockEntity", BlockEntityRegistryLoader::new); - public static final SimpleMappedRegistry COLLISIONS = SimpleMappedRegistry.create(Pair.of("org.geysermc.connector.network.translators.collision.translators", "mappings/collision.json"), CollisionRegistryLoader::new); + public static final SimpleMappedRegistry COLLISIONS = SimpleMappedRegistry.create(Pair.of("org.geysermc.connector.network.translators.collision.translators.Translator", "mappings/collision.json"), CollisionRegistryLoader::new); public static final VersionedRegistry>> CRAFTING_DATA = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); @@ -80,7 +80,7 @@ public class Registries { public static final SimpleMappedRegistry SOUND_EFFECTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEffectsRegistryLoader::new); - public static final SimpleMappedRegistry> SOUND_HANDLERS = SimpleMappedRegistry.create("org.geysermc.connector.network.translators.sound", SoundHandlerRegistryLoader::new); + public static final SimpleMappedRegistry> SOUND_HANDLERS = SimpleMappedRegistry.create("org.geysermc.connector.network.translators.sound.SoundHandler", SoundHandlerRegistryLoader::new); public static void init() { // no-op diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java index 483bb773b..98e84a5c2 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/AnnotatedRegistryLoader.java @@ -26,9 +26,7 @@ package org.geysermc.connector.registry.loader; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; -import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.utils.FileUtils; -import org.reflections.Reflections; import java.lang.annotation.Annotation; import java.util.Map; @@ -66,8 +64,7 @@ public class AnnotatedRegistryLoader implements Regi @Override public Map load(String input) { Map entries = new Object2ObjectOpenHashMap<>(); - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections(input) : new Reflections(input); - for (Class clazz : ref.getTypesAnnotatedWith(this.annotation)) { + for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(input)) { try { entries.put(this.mapper.apply(clazz.getAnnotation(this.annotation)), (V) clazz.newInstance()); } catch (InstantiationException | IllegalAccessException ex) { diff --git a/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java b/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java index 3b342fba8..56976edb0 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java +++ b/connector/src/main/java/org/geysermc/connector/registry/loader/CollisionRegistryLoader.java @@ -26,10 +26,10 @@ package org.geysermc.connector.registry.loader; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.google.common.collect.BiMap; import it.unimi.dsi.fastutil.Pair; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; import lombok.AllArgsConstructor; import org.geysermc.connector.GeyserConnector; import org.geysermc.connector.network.translators.collision.BoundingBox; @@ -40,11 +40,11 @@ import org.geysermc.connector.network.translators.collision.translators.OtherCol import org.geysermc.connector.network.translators.collision.translators.SolidCollision; import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.utils.FileUtils; -import org.reflections.Reflections; +import org.geysermc.connector.utils.Object2IntBiMap; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; +import java.util.IdentityHashMap; import java.util.Map; import java.util.regex.Pattern; @@ -57,9 +57,8 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader load(Pair input) { Int2ObjectMap collisions = new Int2ObjectOpenHashMap<>(); - Map, CollisionInfo> annotationMap = new HashMap<>(); - Reflections ref = GeyserConnector.getInstance().useXmlReflections() ? FileUtils.getReflections(input.key()) : new Reflections(input.key()); - for (Class clazz : ref.getTypesAnnotatedWith(CollisionRemapper.class)) { + Map, CollisionInfo> annotationMap = new IdentityHashMap<>(); + for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(CollisionRemapper.class.getName())) { GeyserConnector.getInstance().getLogger().debug("Found annotated collision translator: " + clazz.getCanonicalName()); CollisionRemapper collisionRemapper = clazz.getAnnotation(CollisionRemapper.class); @@ -76,16 +75,16 @@ public class CollisionRegistryLoader extends MultiResourceRegistryLoader javaIdBlockMap = BlockRegistries.JAVA_IDENTIFIERS.get(); + Object2IntBiMap javaIdBlockMap = BlockRegistries.JAVA_IDENTIFIERS.get(); // 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(), annotationMap, instantiatedCollision, collisionList); + Map, BlockCollision> instantiatedCollision = new IdentityHashMap<>(); + for (Object2IntMap.Entry entry : javaIdBlockMap.object2IntEntrySet()) { + BlockCollision newCollision = instantiateCollision(entry.getKey(), entry.getIntValue(), annotationMap, instantiatedCollision, collisionList); if (newCollision != null) { instantiatedCollision.put(newCollision.getClass(), newCollision); } - collisions.put(entry.getValue().intValue(), newCollision); + collisions.put(entry.getIntValue(), newCollision); } return collisions; } diff --git a/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java b/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java index d495121c6..7ba3886cb 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java +++ b/connector/src/main/java/org/geysermc/connector/registry/populator/ItemRegistryPopulator.java @@ -49,7 +49,6 @@ import org.geysermc.connector.network.translators.item.StoredItemMappings; import org.geysermc.connector.registry.BlockRegistries; import org.geysermc.connector.registry.Registries; import org.geysermc.connector.registry.type.*; -import org.geysermc.connector.utils.BlockUtils; import org.geysermc.connector.utils.FileUtils; import java.io.ByteArrayInputStream; @@ -124,6 +123,7 @@ public class ItemRegistryPopulator { // Used to get the Bedrock namespaced ID (in instances where there are small differences) Object2IntMap bedrockIdentifierToId = new Object2IntOpenHashMap<>(); + bedrockIdentifierToId.defaultReturnValue(Short.MIN_VALUE); List itemNames = new ArrayList<>(); @@ -268,14 +268,14 @@ public class ItemRegistryPopulator { } String bedrockIdentifier = mappingItem.getBedrockIdentifier(); int bedrockId = bedrockIdentifierToId.getInt(bedrockIdentifier); - if (bedrockIdentifier == null) { - throw new RuntimeException("Missing Bedrock ID in mappings!: " + bedrockId); + if (bedrockId == Short.MIN_VALUE) { + throw new RuntimeException("Missing Bedrock ID in mappings: " + bedrockIdentifier); } - int stackSize = mappingItem.getStackSize() == null ? 64 : mappingItem.getStackSize(); + int stackSize = mappingItem.getStackSize(); int bedrockBlockId = -1; - Integer blockRuntimeIdNode = entry.getValue().getBlockRuntimeId(); - if (blockRuntimeIdNode != null) { + Integer firstBlockRuntimeId = entry.getValue().getFirstBlockRuntimeId(); + if (firstBlockRuntimeId != null) { int blockIdOverride = bedrockBlockIdOverrides.getOrDefault(bedrockIdentifier, -1); if (blockIdOverride != -1) { // Straight from BDS is our best chance of getting an item that doesn't run into issues @@ -285,52 +285,51 @@ public class ItemRegistryPopulator { int aValidBedrockBlockId = blacklistedIdentifiers.getOrDefault(bedrockIdentifier, -1); if (aValidBedrockBlockId == -1) { // Fallback - bedrockBlockId = blockMappings.getBedrockBlockId(blockRuntimeIdNode); + bedrockBlockId = blockMappings.getBedrockBlockId(firstBlockRuntimeId); } else { // As of 1.16.220, every item requires a block runtime ID attached to it. // This is mostly for identifying different blocks with the same item ID - wool, slabs, some walls. // However, in order for some visuals and crafting to work, we need to send the first matching block state // as indexed by Bedrock's block palette // There are exceptions! But, ideally, the block ID override should take care of those. - String javaBlockIdentifier = BlockRegistries.JAVA_BLOCKS.get(blockRuntimeIdNode).getCleanJavaIdentifier(); NbtMapBuilder requiredBlockStatesBuilder = NbtMap.builder(); String correctBedrockIdentifier = blockMappings.getBedrockBlockStates().get(aValidBedrockBlockId).getString("name"); boolean firstPass = true; - for (Map.Entry blockEntry : BlockRegistries.JAVA_IDENTIFIERS.get().entrySet()) { - String aBlockIdentifier = BlockUtils.getCleanIdentifier(blockEntry.getKey()); - if (aBlockIdentifier.equals(javaBlockIdentifier)) { - int bedrockBlockRuntimeId = blockMappings.getBedrockBlockId(blockEntry.getValue()); - NbtMap blockTag = blockMappings.getBedrockBlockStates().get(bedrockBlockRuntimeId); - String bedrockName = blockTag.getString("name"); - if (!bedrockName.equals(correctBedrockIdentifier)) { - continue; - } - NbtMap states = blockTag.getCompound("states"); + // Block states are all grouped together. In the mappings, we store the first block runtime ID in order, + // and the last, if relevant. We then iterate over all those values and get their Bedrock equivalents + Integer lastBlockRuntimeId = entry.getValue().getLastBlockRuntimeId() == null ? firstBlockRuntimeId : entry.getValue().getLastBlockRuntimeId(); + for (int i = firstBlockRuntimeId; i <= lastBlockRuntimeId; i++) { + int bedrockBlockRuntimeId = blockMappings.getBedrockBlockId(i); + NbtMap blockTag = blockMappings.getBedrockBlockStates().get(bedrockBlockRuntimeId); + String bedrockName = blockTag.getString("name"); + if (!bedrockName.equals(correctBedrockIdentifier)) { + continue; + } + NbtMap states = blockTag.getCompound("states"); - if (firstPass) { - firstPass = false; - if (states.size() == 0) { - // No need to iterate and find all block states - this is the one, as there can't be any others - bedrockBlockId = bedrockBlockRuntimeId; - break; - } - requiredBlockStatesBuilder.putAll(states); - continue; - } - for (Map.Entry nbtEntry : states.entrySet()) { - Object value = requiredBlockStatesBuilder.get(nbtEntry.getKey()); - if (value != null && !nbtEntry.getValue().equals(value)) { // Null means this value has already been removed/deemed as unneeded - // This state can change between different block states, and therefore is not required - // to build a successful block state of this - requiredBlockStatesBuilder.remove(nbtEntry.getKey()); - } - } - if (requiredBlockStatesBuilder.size() == 0) { - // There are no required block states - // E.G. there was only a direction property that is no longer in play - // (States that are important include color for glass) + if (firstPass) { + firstPass = false; + if (states.size() == 0) { + // No need to iterate and find all block states - this is the one, as there can't be any others + bedrockBlockId = bedrockBlockRuntimeId; break; } + requiredBlockStatesBuilder.putAll(states); + continue; + } + for (Map.Entry nbtEntry : states.entrySet()) { + Object value = requiredBlockStatesBuilder.get(nbtEntry.getKey()); + if (value != null && !nbtEntry.getValue().equals(value)) { // Null means this value has already been removed/deemed as unneeded + // This state can change between different block states, and therefore is not required + // to build a successful block state of this + requiredBlockStatesBuilder.remove(nbtEntry.getKey()); + } + } + if (requiredBlockStatesBuilder.size() == 0) { + // There are no required block states + // E.G. there was only a direction property that is no longer in play + // (States that are important include color for glass) + break; } } diff --git a/connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java b/connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java index 4533ecc6a..dca743824 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java +++ b/connector/src/main/java/org/geysermc/connector/registry/populator/RecipeRegistryPopulator.java @@ -70,7 +70,7 @@ public class RecipeRegistryPopulator { } int currentRecipeId = LAST_RECIPE_NET_ID; - for (Map.Entry version : Registries.ITEMS.get().entrySet()) { + for (Int2ObjectMap.Entry version : Registries.ITEMS.get().int2ObjectEntrySet()) { // Make a bit of an assumption here that the last recipe net ID will be equivalent between all versions LAST_RECIPE_NET_ID = currentRecipeId; Map> craftingData = new EnumMap<>(RecipeType.class); @@ -116,8 +116,8 @@ public class RecipeRegistryPopulator { c -> new ObjectArrayList<>()).add(getCraftingDataFromJsonNode(entry, recipes, version.getValue())); } - Registries.CRAFTING_DATA.register(version.getKey(), craftingData); - Registries.RECIPES.register(version.getKey(), recipes); + Registries.CRAFTING_DATA.register(version.getIntKey(), craftingData); + Registries.RECIPES.register(version.getIntKey(), recipes); } } diff --git a/connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java b/connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java index 9219a8793..da91c412e 100644 --- a/connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java +++ b/connector/src/main/java/org/geysermc/connector/registry/type/GeyserMappingItem.java @@ -35,8 +35,9 @@ import lombok.Data; public class GeyserMappingItem { @JsonProperty("bedrock_identifier") String bedrockIdentifier; @JsonProperty("bedrock_data") int bedrockData; - Integer blockRuntimeId; - @JsonProperty("stack_size") Integer stackSize; + Integer firstBlockRuntimeId; + Integer lastBlockRuntimeId; + @JsonProperty("stack_size") int stackSize = 64; @JsonProperty("tool_type") String toolType; @JsonProperty("tool_tier") String toolTier; } 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 3fb5c2ebb..3369f16a5 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/FileUtils.java @@ -30,16 +30,15 @@ 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.lang.annotation.Annotation; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.security.MessageDigest; +import java.util.Set; import java.util.function.Function; +import java.util.stream.Collectors; public class FileUtils { @@ -193,24 +192,6 @@ public class FileUtils { 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 ignored) { - } - - return reflections; - } - /** * An android compatible version of {@link Files#readAllBytes} * @@ -242,4 +223,41 @@ public class FileUtils { throw new RuntimeException("Error while trying to read input stream!"); } } + + /** + * Returns a set of all the classes that are annotated by a given annotation. + * Keep in mind that these are from a set of generated annotations generated + * at compile time by the annotation processor, meaning that arbitrary annotations + * cannot be passed into this method and expected to have a set of classes + * returned back. + * + * @param annotationClass the annotation class + * @return a set of all the classes annotated by the given annotation + */ + public static Set> getGeneratedClassesForAnnotation(Class annotationClass) { + return getGeneratedClassesForAnnotation(annotationClass.getName()); + } + + /** + * Returns a set of all the classes that are annotated by a given annotation. + * Keep in mind that these are from a set of generated annotations generated + * at compile time by the annotation processor, meaning that arbitrary annotations + * cannot be passed into this method and expected to have a set of classes + * returned back. + * + * @param input the fully qualified name of the annotation + * @return a set of all the classes annotated by the given annotation + */ + public static Set> getGeneratedClassesForAnnotation(String input) { + InputStream annotatedClass = FileUtils.getResource(input); + BufferedReader reader = new BufferedReader(new InputStreamReader(annotatedClass)); + return reader.lines().map(className -> { + try { + return Class.forName(className); + } catch (ClassNotFoundException ex) { + GeyserConnector.getInstance().getLogger().error("Failed to find class " + className, ex); + throw new RuntimeException(ex); + } + }).collect(Collectors.toSet()); + } } 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 7e32553b6..bd2bb9370 100644 --- a/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java +++ b/connector/src/main/java/org/geysermc/connector/utils/LocaleUtils.java @@ -39,6 +39,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.concurrent.CompletableFuture; import java.util.zip.ZipFile; public class LocaleUtils { @@ -56,53 +57,55 @@ public class LocaleUtils { localesFolder.mkdir(); // Download the latest asset list and cache it - generateAssetCache(); - downloadAndLoadLocale(LanguageUtils.getDefaultLocale()); + generateAssetCache().whenComplete((aVoid, ex) -> downloadAndLoadLocale(LanguageUtils.getDefaultLocale())); } /** * Fetch the latest versions asset cache from Mojang so we can grab the locale files later */ - private static void generateAssetCache() { - try { - // Get the version manifest from Mojang - VersionManifest versionManifest = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); + private static CompletableFuture generateAssetCache() { + return CompletableFuture.supplyAsync(() -> { + try { + // Get the version manifest from Mojang + VersionManifest versionManifest = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class); - // Get the url for the latest version of the games manifest - String latestInfoURL = ""; - for (Version version : versionManifest.getVersions()) { - if (version.getId().equals(MinecraftConstants.GAME_VERSION)) { - latestInfoURL = version.getUrl(); - break; + // Get the url for the latest version of the games manifest + String latestInfoURL = ""; + for (Version version : versionManifest.getVersions()) { + if (version.getId().equals(MinecraftConstants.GAME_VERSION)) { + latestInfoURL = version.getUrl(); + break; + } } + + // Make sure we definitely got a version + if (latestInfoURL.isEmpty()) { + throw new Exception(LanguageUtils.getLocaleStringLog("geyser.locale.fail.latest_version")); + } + + // Get the individual version manifest + VersionInfo versionInfo = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); + + // Get the client jar for use when downloading the en_us locale + GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(versionInfo.getDownloads())); + clientJarInfo = versionInfo.getDownloads().get("client"); + GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(clientJarInfo)); + + // Get the assets list + JsonNode assets = GeyserConnector.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); + + // Put each asset into an array for use later + Iterator> assetIterator = assets.fields(); + while (assetIterator.hasNext()) { + Map.Entry entry = assetIterator.next(); + Asset asset = GeyserConnector.JSON_MAPPER.treeToValue(entry.getValue(), Asset.class); + ASSET_MAP.put(entry.getKey(), asset); + } + } catch (Exception e) { + GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.locale.fail.asset_cache", (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace()))); } - - // Make sure we definitely got a version - if (latestInfoURL.isEmpty()) { - throw new Exception(LanguageUtils.getLocaleStringLog("geyser.locale.fail.latest_version")); - } - - // Get the individual version manifest - VersionInfo versionInfo = GeyserConnector.JSON_MAPPER.readValue(WebUtils.getBody(latestInfoURL), VersionInfo.class); - - // Get the client jar for use when downloading the en_us locale - GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(versionInfo.getDownloads())); - clientJarInfo = versionInfo.getDownloads().get("client"); - GeyserConnector.getInstance().getLogger().debug(GeyserConnector.JSON_MAPPER.writeValueAsString(clientJarInfo)); - - // Get the assets list - JsonNode assets = GeyserConnector.JSON_MAPPER.readTree(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).get("objects"); - - // Put each asset into an array for use later - Iterator> assetIterator = assets.fields(); - while (assetIterator.hasNext()) { - Map.Entry entry = assetIterator.next(); - Asset asset = GeyserConnector.JSON_MAPPER.treeToValue(entry.getValue(), Asset.class); - ASSET_MAP.put(entry.getKey(), asset); - } - } catch (Exception e) { - GeyserConnector.getInstance().getLogger().error(LanguageUtils.getLocaleStringLog("geyser.locale.fail.asset_cache", (!e.getMessage().isEmpty() ? e.getMessage() : e.getStackTrace()))); - } + return null; + }); } /** @@ -311,107 +314,107 @@ public class LocaleUtils { public static void init() { // no-op } -} -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class VersionManifest { - @JsonProperty("latest") - private LatestVersion latestVersion; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class VersionManifest { + @JsonProperty("latest") + private LatestVersion latestVersion; - @JsonProperty("versions") - private List versions; -} + @JsonProperty("versions") + private List versions; + } -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class LatestVersion { - @JsonProperty("release") - private String release; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class LatestVersion { + @JsonProperty("release") + private String release; - @JsonProperty("snapshot") - private String snapshot; -} + @JsonProperty("snapshot") + private String snapshot; + } -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class Version { - @JsonProperty("id") - private String id; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class Version { + @JsonProperty("id") + private String id; - @JsonProperty("type") - private String type; + @JsonProperty("type") + private String type; - @JsonProperty("url") - private String url; + @JsonProperty("url") + private String url; - @JsonProperty("time") - private String time; + @JsonProperty("time") + private String time; - @JsonProperty("releaseTime") - private String releaseTime; -} + @JsonProperty("releaseTime") + private String releaseTime; + } -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class VersionInfo { - @JsonProperty("id") - private String id; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class VersionInfo { + @JsonProperty("id") + private String id; - @JsonProperty("type") - private String type; + @JsonProperty("type") + private String type; - @JsonProperty("time") - private String time; + @JsonProperty("time") + private String time; - @JsonProperty("releaseTime") - private String releaseTime; + @JsonProperty("releaseTime") + private String releaseTime; - @JsonProperty("assetIndex") - private AssetIndex assetIndex; + @JsonProperty("assetIndex") + private AssetIndex assetIndex; - @JsonProperty("downloads") - private Map downloads; -} + @JsonProperty("downloads") + private Map downloads; + } -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class VersionDownload { - @JsonProperty("sha1") - private String sha1; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class VersionDownload { + @JsonProperty("sha1") + private String sha1; - @JsonProperty("size") - private int size; + @JsonProperty("size") + private int size; - @JsonProperty("url") - private String url; -} + @JsonProperty("url") + private String url; + } -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class AssetIndex { - @JsonProperty("id") - private String id; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class AssetIndex { + @JsonProperty("id") + private String id; - @JsonProperty("sha1") - private String sha1; + @JsonProperty("sha1") + private String sha1; - @JsonProperty("size") - private int size; + @JsonProperty("size") + private int size; - @JsonProperty("totalSize") - private int totalSize; + @JsonProperty("totalSize") + private int totalSize; - @JsonProperty("url") - private String url; -} + @JsonProperty("url") + private String url; + } -@JsonIgnoreProperties(ignoreUnknown = true) -@Getter -class Asset { - @JsonProperty("hash") - private String hash; + @JsonIgnoreProperties(ignoreUnknown = true) + @Getter + static class Asset { + @JsonProperty("hash") + private String hash; - @JsonProperty("size") - private int size; + @JsonProperty("size") + private int size; + } } \ No newline at end of file diff --git a/connector/src/main/java/org/geysermc/connector/utils/Object2IntBiMap.java b/connector/src/main/java/org/geysermc/connector/utils/Object2IntBiMap.java new file mode 100644 index 000000000..27277923b --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/Object2IntBiMap.java @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2019-2021 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.connector.utils; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntCollection; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectSet; +import it.unimi.dsi.fastutil.objects.ObjectSets; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Objects; + +/** + * A primitive int BiMap implementation built around fastutil to + * reduce boxing and the memory footprint. Protocol has a + * {@link com.nukkitx.protocol.util.Int2ObjectBiMap} class, but it + * does not extend the Map interface making it difficult to utilize + * it in for loops and the registry system. + * + * @param the value + */ +public class Object2IntBiMap implements Object2IntMap { + private final Object2IntMap forwards; + private final Int2ObjectMap backwards; + + public Object2IntBiMap() { + this(16); + } + + public Object2IntBiMap(int expected) { + this(expected, 0.75F); + } + + public Object2IntBiMap(T defaultForwardsValue) { + this(16, 0.75F, defaultForwardsValue, -1); + } + + public Object2IntBiMap(int expected, float loadFactor) { + this(expected, loadFactor, -1); + } + + public Object2IntBiMap(int expected, float loadFactor, int defaultBackwardsValue) { + this(expected, loadFactor, null, defaultBackwardsValue); + } + + public Object2IntBiMap(int expected, float loadFactor, T defaultForwardsValue, int defaultBackwardsValue) { + this.forwards = new Object2IntOpenHashMap<>(expected, loadFactor); + this.backwards = new Int2ObjectOpenHashMap<>(expected, loadFactor); + this.forwards.defaultReturnValue(defaultBackwardsValue); + this.backwards.defaultReturnValue(defaultForwardsValue); + } + + @Override + public int size() { + return this.forwards.size(); + } + + @Override + public boolean isEmpty() { + return this.forwards.isEmpty(); + } + + @Override + public int getInt(Object o) { + return this.forwards.getInt(o); + } + + public T get(int key) { + return this.backwards.get(key); + } + + @Override + public int getOrDefault(Object key, int defaultValue) { + return this.forwards.getOrDefault(key, defaultValue); + } + + public T getOrDefault(int key, T defaultValue) { + return this.backwards.getOrDefault(key, defaultValue); + } + + @Override + public void defaultReturnValue(int i) { + this.forwards.defaultReturnValue(i); + } + + public void defaultReturnValue(T v) { + this.backwards.defaultReturnValue(v); + } + + @Override + public int defaultReturnValue() { + return this.forwards.defaultReturnValue(); + } + + public T backwardsDefaultReturnValue() { + return this.backwards.defaultReturnValue(); + } + + @Override + public ObjectSet> object2IntEntrySet() { + return ObjectSets.unmodifiable(this.forwards.object2IntEntrySet()); + } + + public ObjectSet> int2ObjectEntrySet() { + return ObjectSets.unmodifiable(this.backwards.int2ObjectEntrySet()); + } + + @Override + public ObjectSet keySet() { + return this.forwards.keySet(); + } + + @Override + public IntCollection values() { + return this.forwards.values(); + } + + @Override + public boolean containsKey(Object o) { + return this.forwards.containsKey(o); + } + + @Override + public boolean containsValue(int i) { + return this.backwards.containsKey(i); + } + + @Override + public int put(T key, int value) { + this.backwards.put(value, key); + return this.forwards.put(key, value); + } + + @Override + public void putAll(@NotNull Map m) { + this.forwards.putAll(m); + for (Map.Entry entry : m.entrySet()) { + this.backwards.put((int) entry.getValue(), entry.getKey()); + } + } + + @Override + public int removeInt(Object key) { + if (!this.forwards.containsKey(key)) { + return this.defaultReturnValue(); + } + + int value = this.forwards.getInt(key); + if (!this.backwards.containsKey(value)) { + return this.defaultReturnValue(); + }; + this.backwards.remove(value); + return this.forwards.removeInt(key); + } + + @Override + public int hashCode() { + return this.forwards.hashCode(); + } + + @Override + public String toString() { + return this.forwards.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Object2IntBiMap that = (Object2IntBiMap) o; + return Objects.equals(this.forwards, that.forwards) && Objects.equals(this.backwards, that.backwards); + } +} diff --git a/connector/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/connector/src/main/resources/META-INF/services/javax.annotation.processing.Processor new file mode 100644 index 000000000..463d1efad --- /dev/null +++ b/connector/src/main/resources/META-INF/services/javax.annotation.processing.Processor @@ -0,0 +1,5 @@ +org.geysermc.processor.BlockEntityProcessor +org.geysermc.processor.CollisionRemapperProcessor +org.geysermc.processor.ItemRemapperProcessor +org.geysermc.processor.PacketTranslatorProcessor +org.geysermc.processor.SoundHandlerProcessor \ No newline at end of file diff --git a/connector/src/main/resources/mappings b/connector/src/main/resources/mappings index 7a67fa9ff..8351b0f5b 160000 --- a/connector/src/main/resources/mappings +++ b/connector/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 7a67fa9ff78496f4fc30b8f72d0eff451f1771e2 +Subproject commit 8351b0f5bb6e9a1d614f84e18c91e82288c34bf6 diff --git a/pom.xml b/pom.xml index c03efb782..f8ab9165f 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ + ap bootstrap common connector