diff --git a/README.md b/README.md index 15aee06..cddca07 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# ViaForge -## For more information switch to the master branch -Startup VM Options: -Dfml.coreMods.load=de.florianmichael.viaforge.mixin.MixinLoader +# Legacy development branch for ViaForge 1.8 + +Upstream changes are merged into this branch every release. \ No newline at end of file diff --git a/build.gradle b/build.gradle index 1353545..d13a1b7 100644 --- a/build.gradle +++ b/build.gradle @@ -18,14 +18,15 @@ apply plugin: "net.minecraftforge.gradle.forge" apply plugin: "org.spongepowered.mixin" apply plugin: "com.github.johnrengelman.shadow" apply plugin: "java" +apply plugin: "idea" -version = "1.8.9-${mod_version}" -group = "${mod_base_package}.${mod_id}" -archivesBaseName = mod_id +version = "1.8.9-${maven_version}" +group = "${maven_group}.${maven_name}" +archivesBaseName = maven_name sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 -compileJava.options.encoding = 'UTF-8' +compileJava.options.encoding = "UTF-8" repositories { mavenCentral() @@ -54,51 +55,47 @@ configurations { implementation.extendsFrom(include) } -def viaLibs = [ - "com.viaversion:viaversion:${project.viaversion_version}", - "com.viaversion:viabackwards:${project.viabackwards_version}", - "com.viaversion:viarewind-universal:${project.viarewind_version}", - "org.yaml:snakeyaml:${project.snake_yml_version}", - - "net.raphimc:ViaLoader:${project.vialoader_version}", - "org.slf4j:slf4j-api:${project.slf4j_version}" -] - dependencies { - compile ("org.spongepowered:mixin:0.7.10-SNAPSHOT") { + include compile ("org.spongepowered:mixin:${project.mixin_version}") { exclude module: "launchwrapper" } - include "org.spongepowered:mixin:0.7.10-SNAPSHOT" - for (final def via in viaLibs) { - include(via) + include "com.viaversion:viaversion:${project.viaversion_version}" + include "com.viaversion:viabackwards:${project.viabackwards_version}" + include "com.viaversion:viarewind-universal:${project.viarewind_version}" + include ("net.raphimc:ViaLegacy:${project.vialegacy_version}") { + exclude group: "com.google.code.gson", module: "gson" } + include "net.raphimc:ViaAprilFools:${project.viaaprilfools_version}" + include "net.raphimc:ViaLoader:${project.vialoader_version}" + + include "org.slf4j:slf4j-api:${project.slf4j_version}" + include "org.yaml:snakeyaml:${project.snake_yml_version}" } processResources { inputs.property "version", project.version - inputs.property "mcversion", project.minecraft.version from(sourceSets.main.resources.srcDirs) { - include 'mcmod.info' + include "mcmod.info" - expand 'version':project.version, 'mcversion':project.minecraft.version + expand "version": project.version } from(sourceSets.main.resources.srcDirs) { - exclude 'mcmod.info' + exclude "mcmod.info" } rename '(.+_at.cfg)', 'META-INF/$1' } mixin { - add sourceSets.main, "mixins.${mod_id}.refmap.json" + add sourceSets.main, "mixins.${maven_name}-mc18.refmap.json" } jar { manifest.attributes( - "MixinConfigs": "mixins.viaforge.json", + "MixinConfigs": "mixins.${maven_name}-mc18.json", "tweakClass": "org.spongepowered.asm.launch.MixinTweaker", "TweakOrder": 0, "FMLCorePluginContainsFMLMod": "de.florianmichael.viaforge.mixin.MixinLoader" @@ -107,8 +104,6 @@ jar { enabled = false } -apply plugin: "idea" - idea { module { inheritOutputDirs = true @@ -117,17 +112,12 @@ idea { shadowJar { archiveName = jar.archiveName - configurations = [project.configurations.include] - compileJava.options.encoding = "UTF-8" - exclude "native-binaries/*" - exclude "META-INF/versions/**" + configurations = [project.configurations.include] // Include the dependencies from the include configuration + duplicatesStrategy DuplicatesStrategy.EXCLUDE - dependencies { - for (final def lib in viaLibs) { - include(dependency(lib)) - } - include(dependency("org.spongepowered:mixin:0.7.10-SNAPSHOT")) - } + // Prevent conflicts with Forge's weird service loading + exclude("META-INF/maven/**") + exclude("META-INF/versions/**") } reobf { diff --git a/gradle.properties b/gradle.properties index ca3bcdd..320e621 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,20 +1,22 @@ -# java -org.gradle.jvmargs=-Xmx3G +# Gradle Properties +org.gradle.jvmargs=-Xmx3G -XX:+UseG1GC org.gradle.daemon=false -# forge -mod_id=viaforge -mod_name=ViaForge -mod_version=3.5.0-SNAPSHOT -mod_base_package=de.florianmichael +# Project Details +maven_name=viaforge +maven_version=3.5.0-SNAPSHOT +maven_group=de.florianmichael -# via-version -vialoader_version=2.2.11-SNAPSHOT -viaversion_version=4.9.0-23w42a-SNAPSHOT -viabackwards_version=4.9.0-23w42a-SNAPSHOT +# ViaVersion +viaversion_version=4.9.0-1.20.3-rc1-SNAPSHOT +viabackwards_version=4.9.0-1.20.3-rc1-SNAPSHOT viarewind_version=3.0.3-SNAPSHOT +vialegacy_version=2.2.21-SNAPSHOT +viaaprilfools_version=2.0.10-SNAPSHOT +vialoader_version=2.2.11-SNAPSHOT + snake_yml_version=2.2 -# libs +# Misc Libraries slf4j_version=2.0.7 -mixin_version=0.8.3 +mixin_version=0.7.10-SNAPSHOT diff --git a/src/main/java/de/florianmichael/viaforge/ViaForge.java b/src/main/java/de/florianmichael/viaforge/ViaForge.java deleted file mode 100644 index 1fbc27e..0000000 --- a/src/main/java/de/florianmichael/viaforge/ViaForge.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge - * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package de.florianmichael.viaforge; - -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.version.VersionProvider; -import com.viaversion.viaversion.protocols.base.BaseVersionProvider; -import net.minecraft.client.Minecraft; -import net.raphimc.vialoader.ViaLoader; -import net.raphimc.vialoader.impl.platform.ViaBackwardsPlatformImpl; -import net.raphimc.vialoader.impl.platform.ViaRewindPlatformImpl; -import net.raphimc.vialoader.impl.viaversion.VLInjector; -import net.raphimc.vialoader.impl.viaversion.VLLoader; -import net.raphimc.vialoader.netty.VLLegacyPipeline; -import net.raphimc.vialoader.util.VersionEnum; - -public class ViaForge { - public final static VersionEnum NATIVE_VERSION = VersionEnum.r1_8; - - public static VersionEnum targetVersion = VersionEnum.r1_8; - - public static void start() { - VersionEnum.SORTED_VERSIONS.remove(VersionEnum.r1_7_6tor1_7_10); - VersionEnum.SORTED_VERSIONS.remove(VersionEnum.r1_7_2tor1_7_5); - - ViaLoader.init( - null, - new VLLoader() { - @Override - public void load() { - super.load(); - Via.getManager().getProviders().use(VersionProvider.class, new BaseVersionProvider() { - @Override - public int getClosestServerProtocol(UserConnection connection) throws Exception { - if (connection.isClientSide() && !Minecraft.getMinecraft().isSingleplayer()) { - return targetVersion.getVersion(); - } - return super.getClosestServerProtocol(connection); - } - }); - } - }, - new VLInjector() { - @Override - public String getDecoderName() { - return VLLegacyPipeline.VIA_DECODER_NAME; - } - - @Override - public String getEncoderName() { - return VLLegacyPipeline.VIA_ENCODER_NAME; - } - }, - null, - ViaBackwardsPlatformImpl::new, ViaRewindPlatformImpl::new - ); - } -} diff --git a/src/main/java/de/florianmichael/viaforge/ViaForge18.java b/src/main/java/de/florianmichael/viaforge/ViaForge18.java new file mode 100644 index 0000000..3a5a2b5 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/ViaForge18.java @@ -0,0 +1,61 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge; + +import de.florianmichael.viaforge.common.platform.VFPlatform; +import de.florianmichael.viaforge.provider.ViaForgeGameProfileFetcher; +import net.minecraft.client.Minecraft; +import net.minecraft.realms.RealmsSharedConstants; +import net.minecraft.util.Session; +import net.minecraftforge.fml.common.Mod; +import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher; + +import java.io.File; +import java.util.function.Supplier; + +@Mod(modid = "viaforge") +public class ViaForge18 implements VFPlatform { + public final static ViaForge18 PLATFORM = new ViaForge18(); + + @Override + public int getGameVersion() { + return RealmsSharedConstants.NETWORK_PROTOCOL_VERSION; + } + + @Override + public Supplier isSingleplayer() { + return () -> Minecraft.getMinecraft().isSingleplayer(); + } + + @Override + public File getLeadingDirectory() { + return Minecraft.getMinecraft().mcDataDir; + } + + @Override + public void joinServer(String serverId) throws Throwable { + final Session session = Minecraft.getMinecraft().getSession(); + + Minecraft.getMinecraft().getSessionService().joinServer(session.getProfile(), session.getToken(), serverId); + } + + @Override + public GameProfileFetcher getGameProfileFetcher() { + return new ViaForgeGameProfileFetcher(); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/ViaForgeCommon.java b/src/main/java/de/florianmichael/viaforge/common/ViaForgeCommon.java new file mode 100644 index 0000000..4739071 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/ViaForgeCommon.java @@ -0,0 +1,147 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.common; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.connection.UserConnectionImpl; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import de.florianmichael.viaforge.common.platform.VFPlatform; +import de.florianmichael.viaforge.common.platform.ViaForgeConfig; +import de.florianmichael.viaforge.common.protocolhack.ViaForgeVLInjector; +import de.florianmichael.viaforge.common.protocolhack.netty.VFNetworkManager; +import de.florianmichael.viaforge.common.protocolhack.netty.ViaForgeVLLegacyPipeline; +import de.florianmichael.viaforge.common.protocolhack.ViaForgeVLLoader; +import io.netty.channel.Channel; +import io.netty.channel.socket.SocketChannel; +import io.netty.util.AttributeKey; +import net.raphimc.vialoader.ViaLoader; +import net.raphimc.vialoader.impl.platform.*; +import net.raphimc.vialoader.netty.CompressionReorderEvent; +import net.raphimc.vialoader.util.VersionEnum; + +import java.io.File; + +/** + * This class is used to manage the common code between the different ViaForge versions. + * It is used to inject the ViaVersion pipeline into the netty pipeline. It also manages the target version. + */ +public class ViaForgeCommon { + public final static AttributeKey LOCAL_VIA_USER = AttributeKey.valueOf("local_via_user"); + public final static AttributeKey VF_NETWORK_MANAGER = AttributeKey.valueOf("encryption_setup"); + + private static ViaForgeCommon manager; + + private final VFPlatform platform; + private VersionEnum targetVersion; + + private ViaForgeConfig config; + + public ViaForgeCommon(VFPlatform platform) { + this.platform = platform; + } + + /** + * Initializes the manager. + * + * @param platform the platform fields + */ + public static void init(final VFPlatform platform) { + if (manager != null) { + return; // Already initialized, ignore it then :tm: + } + final VersionEnum version = VersionEnum.fromProtocolId(platform.getGameVersion()); + if (version == VersionEnum.UNKNOWN) { + throw new IllegalArgumentException("Unknown version " + platform.getGameVersion()); + } + + manager = new ViaForgeCommon(platform); + + final File mainFolder = new File(platform.getLeadingDirectory(), "ViaForge"); + + ViaLoader.init(new ViaVersionPlatformImpl(mainFolder), new ViaForgeVLLoader(platform), new ViaForgeVLInjector(), null, ViaBackwardsPlatformImpl::new, ViaRewindPlatformImpl::new, ViaLegacyPlatformImpl::new, ViaAprilFoolsPlatformImpl::new); + manager.config = new ViaForgeConfig(new File(mainFolder, "viaforge.yml")); + + final VersionEnum configVersion = VersionEnum.fromProtocolId(manager.config.getClientSideVersion()); + if (configVersion != VersionEnum.UNKNOWN) { + manager.setTargetVersion(configVersion); + } else { + manager.setTargetVersion(version); + } + } + + /** + * Injects the ViaVersion pipeline into the netty pipeline. + * + * @param channel the channel to inject the pipeline into + */ + public void inject(final Channel channel, final VFNetworkManager networkManager) { + if (channel instanceof SocketChannel) { + final UserConnection user = new UserConnectionImpl(channel, true); + new ProtocolPipelineImpl(user); + + channel.attr(LOCAL_VIA_USER).set(user); + channel.attr(VF_NETWORK_MANAGER).set(networkManager); + + channel.pipeline().addLast(new ViaForgeVLLegacyPipeline(user, targetVersion)); + } + } + + /** + * Reorders the compression channel. + * + * @param channel the channel to reorder the compression for + */ + public void reorderCompression(final Channel channel) { + // When Minecraft enables compression, we need to reorder the pipeline + // to match the counterparts of via-decoder <-> encoder and via-encoder <-> encoder + channel.pipeline().fireUserEventTriggered(CompressionReorderEvent.INSTANCE); + } + + public VersionEnum getNativeVersion() { + return VersionEnum.fromProtocolId(platform.getGameVersion()); + } + + public VersionEnum getTargetVersion() { + return targetVersion; + } + + public void restoreVersion() { + this.targetVersion = VersionEnum.fromProtocolId(config.getClientSideVersion()); + } + + public void setTargetVersionSilent(final VersionEnum targetVersion) { + this.targetVersion = targetVersion; + } + + public void setTargetVersion(final VersionEnum targetVersion) { + this.targetVersion = targetVersion; + config.setClientSideVersion(targetVersion.getVersion()); + } + + public VFPlatform getPlatform() { + return platform; + } + + public ViaForgeConfig getConfig() { + return config; + } + + public static ViaForgeCommon getManager() { + return manager; + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/gui/ExtendedServerData.java b/src/main/java/de/florianmichael/viaforge/common/gui/ExtendedServerData.java new file mode 100644 index 0000000..97ca061 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/gui/ExtendedServerData.java @@ -0,0 +1,30 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.common.gui; + +import net.raphimc.vialoader.util.VersionEnum; + +/** + * This interface is used to store the target version for a specific server in the server list. + */ +public interface ExtendedServerData { + + VersionEnum viaForge$getVersion(); + + void viaForge$setVersion(final VersionEnum version); +} diff --git a/src/main/java/de/florianmichael/viaforge/common/platform/VFPlatform.java b/src/main/java/de/florianmichael/viaforge/common/platform/VFPlatform.java new file mode 100644 index 0000000..33a54b3 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/platform/VFPlatform.java @@ -0,0 +1,57 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.common.platform; + +import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher; +import net.raphimc.vialoader.util.VersionEnum; + +import java.io.File; +import java.util.function.Supplier; + +/** + * This interface is used to access platform specific fields. + */ +public interface VFPlatform { + + /** + * @return the native version of the platform + */ + int getGameVersion(); + + /** + * @return if the client is in singleplayer + */ + Supplier isSingleplayer(); + + /** + * @return the leading directory of the platform + */ + File getLeadingDirectory(); + + /** + * Sends the joinServer API request to Mojang's authentication servers. + * + * @param serverId the server id of the server + */ + void joinServer(final String serverId) throws Throwable; + + /** + * @return the game profile fetcher of the platform for ViaLegacy + */ + GameProfileFetcher getGameProfileFetcher(); +} diff --git a/src/main/java/de/florianmichael/viaforge/common/platform/ViaForgeConfig.java b/src/main/java/de/florianmichael/viaforge/common/platform/ViaForgeConfig.java new file mode 100644 index 0000000..18dae76 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/platform/ViaForgeConfig.java @@ -0,0 +1,122 @@ +package de.florianmichael.viaforge.common.platform; + +import com.viaversion.viaversion.util.Config; +import com.viaversion.viaversion.util.Pair; + +import java.io.File; +import java.net.URL; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +public class ViaForgeConfig extends Config { + public final static String CLIENT_SIDE_VERSION = "client-side-version"; + public final static String VERIFY_SESSION_IN_OLD_VERSIONS = "verify-session-in-old-versions"; + public final static String ALLOW_BETACRAFT_AUTHENTICATION = "allow-betacraft-authentication"; + public final static String SHOW_PROTOCOL_VERSION_IN_F3 = "show-protocol-version-in-f3"; + + public final static String SHOW_MAIN_MENU_BUTTON = "show-main-menu-button"; + public final static String SHOW_MULTIPLAYER_BUTTON = "show-multiplayer-button"; + public final static String SHOW_DIRECT_CONNECT_BUTTON = "show-direct-connect-button"; + public final static String SHOW_ADD_SERVER_BUTTON = "show-add-server-button"; + + public final static String VIA_FORGE_BUTTON_POSITION = "via-forge-button-position"; + public final static String ADD_SERVER_SCREEN_BUTTON_POSITION = "add-server-screen-button-position"; + + /** + * @param configFile The location of where the config is loaded/saved. + */ + public ViaForgeConfig(File configFile) { + super(configFile); + reload(); + } + + @Override + public URL getDefaultConfigURL() { + return getClass().getClassLoader().getResource("assets/viaforge/config.yml"); + } + + @Override + protected void handleConfig(Map config) { + } + + @Override + public List getUnsupportedOptions() { + return Collections.emptyList(); + } + + @Override + public void set(String path, Object value) { + super.set(path, value); + save(); // Automatically save the config when something changes + } + + public int getClientSideVersion() { + return getInt(CLIENT_SIDE_VERSION, 0); + } + + public void setClientSideVersion(final int version) { + set(CLIENT_SIDE_VERSION, version); + } + + public boolean isVerifySessionInOldVersions() { + return getBoolean(VERIFY_SESSION_IN_OLD_VERSIONS, true); + } + + public boolean isAllowBetacraftAuthentication() { + return getBoolean(ALLOW_BETACRAFT_AUTHENTICATION, true); + } + + public boolean isShowProtocolVersionInF3() { + return getBoolean(SHOW_PROTOCOL_VERSION_IN_F3, true); + } + + public boolean isShowMainMenuButton() { + return getBoolean(SHOW_MAIN_MENU_BUTTON, true); + } + + public boolean isShowMultiplayerButton() { + return getBoolean(SHOW_MULTIPLAYER_BUTTON, true); + } + + public boolean isShowDirectConnectButton() { + return getBoolean(SHOW_DIRECT_CONNECT_BUTTON, true); + } + + public boolean isShowAddServerButton() { + return getBoolean(SHOW_ADD_SERVER_BUTTON, true); + } + + public ButtonPosition getViaForgeButtonPosition() { + return ButtonPosition.valueOf(getString(VIA_FORGE_BUTTON_POSITION, ButtonPosition.TOP_LEFT.name())); + } + + public ButtonPosition getAddServerScreenButtonPosition() { + return ButtonPosition.valueOf(getString(ADD_SERVER_SCREEN_BUTTON_POSITION, ButtonPosition.TOP_LEFT.name())); + } + + public enum ButtonPosition { + // Button width: 100 + // Button height: 20 + // Button margin for both coordinates: 5 + TOP_LEFT((width, height) -> new Pair<>(5, 5)), + TOP_RIGHT((width, height) -> new Pair<>(width - 100 - 5, 5)), + BOTTOM_LEFT((width, height) -> new Pair<>(5, height - 20 - 5)), + BOTTOM_RIGHT((width, height) -> new Pair<>(width - 100 - 5, height - 20 - 5)); + + private final PositionInvoker invoker; + + ButtonPosition(final PositionInvoker invoker) { + this.invoker = invoker; + } + + public Pair getPosition(int width, int height) { + return invoker.invoke(width, height); + } + + public interface PositionInvoker { + + Pair invoke(int width, int height); + } + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinMinecraft.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/ViaForgeVLInjector.java similarity index 57% rename from src/main/java/de/florianmichael/viaforge/mixin/impl/MixinMinecraft.java rename to src/main/java/de/florianmichael/viaforge/common/protocolhack/ViaForgeVLInjector.java index 0587739..fbb2ec4 100644 --- a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinMinecraft.java +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/ViaForgeVLInjector.java @@ -15,21 +15,20 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package de.florianmichael.viaforge.mixin.impl; +package de.florianmichael.viaforge.common.protocolhack; -import de.florianmichael.viaforge.ViaForge; -import net.minecraft.client.Minecraft; -import net.minecraft.client.main.GameConfiguration; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import net.raphimc.vialoader.impl.viaversion.VLInjector; +import net.raphimc.vialoader.netty.VLLegacyPipeline; -@Mixin(Minecraft.class) -public class MixinMinecraft { +public class ViaForgeVLInjector extends VLInjector { - @Inject(method = "", at = @At("RETURN")) - public void startVia(GameConfiguration p_i45547_1_, CallbackInfo ci) { - ViaForge.start(); + @Override + public String getDecoderName() { + return VLLegacyPipeline.VIA_DECODER_NAME; + } + + @Override + public String getEncoderName() { + return VLLegacyPipeline.VIA_ENCODER_NAME; } } diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/ViaForgeVLLoader.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/ViaForgeVLLoader.java new file mode 100644 index 0000000..ff75d21 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/ViaForgeVLLoader.java @@ -0,0 +1,53 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.common.protocolhack; + +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.platform.providers.ViaProviders; +import com.viaversion.viaversion.api.protocol.version.VersionProvider; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; +import de.florianmichael.viaforge.common.platform.VFPlatform; +import de.florianmichael.viaforge.common.protocolhack.provider.*; +import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicMPPassProvider; +import net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.providers.OldAuthProvider; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.providers.EncryptionProvider; +import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher; +import net.raphimc.vialoader.impl.viaversion.VLLoader; + +public class ViaForgeVLLoader extends VLLoader { + + private final VFPlatform platform; + + public ViaForgeVLLoader(VFPlatform platform) { + this.platform = platform; + } + + @Override + public void load() { + super.load(); + + final ViaProviders providers = Via.getManager().getProviders(); + + providers.use(VersionProvider.class, new ViaForgeVersionProvider()); + providers.use(MovementTransmitterProvider.class, new DummyMovementTransmitter()); + providers.use(OldAuthProvider.class, new ViaForgeOldAuthProvider()); + providers.use(GameProfileFetcher.class, platform.getGameProfileFetcher()); + providers.use(EncryptionProvider.class, new ViaForgeEncryptionProvider()); + providers.use(ClassicMPPassProvider.class, new ViaForgeClassicMPPassProvider()); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/netty/VFNetworkManager.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/netty/VFNetworkManager.java new file mode 100644 index 0000000..0ae8b54 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/netty/VFNetworkManager.java @@ -0,0 +1,24 @@ +package de.florianmichael.viaforge.common.protocolhack.netty; + +import net.raphimc.vialoader.util.VersionEnum; + +public interface VFNetworkManager { + + /** + * API method to setup the decryption side of the pipeline. + * This method is called by the {@link de.florianmichael.viaforge.common.protocolhack.provider.ViaForgeEncryptionProvider} class. + */ + void viaForge$setupPreNettyDecryption(); + + /** + * @return the target version of the connection + */ + VersionEnum viaForge$getTrackedVersion(); + + /** + * Sets the target version of the connection. + * + * @param version the target version + */ + void viaForge$setTrackedVersion(final VersionEnum version); +} diff --git a/src/main/java/de/florianmichael/viaforge/ViaForgeVLLegacyPipeline.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/netty/ViaForgeVLLegacyPipeline.java similarity index 96% rename from src/main/java/de/florianmichael/viaforge/ViaForgeVLLegacyPipeline.java rename to src/main/java/de/florianmichael/viaforge/common/protocolhack/netty/ViaForgeVLLegacyPipeline.java index b1a77f2..ea0427f 100644 --- a/src/main/java/de/florianmichael/viaforge/ViaForgeVLLegacyPipeline.java +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/netty/ViaForgeVLLegacyPipeline.java @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package de.florianmichael.viaforge; +package de.florianmichael.viaforge.common.protocolhack.netty; import com.viaversion.viaversion.api.connection.UserConnection; import net.raphimc.vialoader.netty.VLLegacyPipeline; diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/DummyMovementTransmitter.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/DummyMovementTransmitter.java new file mode 100644 index 0000000..e4e046e --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/DummyMovementTransmitter.java @@ -0,0 +1,12 @@ +package de.florianmichael.viaforge.common.protocolhack.provider; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.MovementTransmitterProvider; + +public class DummyMovementTransmitter extends MovementTransmitterProvider { + + @Override + public void sendPlayer(UserConnection userConnection) { + // We are on the client side, so we can handle the idle packet properly + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeClassicMPPassProvider.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeClassicMPPassProvider.java new file mode 100644 index 0000000..4eac934 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeClassicMPPassProvider.java @@ -0,0 +1,69 @@ +package de.florianmichael.viaforge.common.protocolhack.provider; + +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.UserConnection; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.raphimc.vialegacy.protocols.classic.protocola1_0_15toc0_28_30.providers.ClassicMPPassProvider; +import net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.providers.OldAuthProvider; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.storage.HandshakeStorage; + +import java.io.InputStream; +import java.net.InetAddress; +import java.net.URL; +import java.security.MessageDigest; +import java.util.Formatter; +import java.util.Scanner; +import java.util.logging.Level; + +public class ViaForgeClassicMPPassProvider extends ClassicMPPassProvider { + + @Override + public String getMpPass(UserConnection user) { + if (ViaForgeCommon.getManager().getConfig().isAllowBetacraftAuthentication()) { + final HandshakeStorage handshakeStorage = user.get(HandshakeStorage.class); + + return getBetacraftMpPass(user, user.getProtocolInfo().getUsername(), handshakeStorage.getHostname(), handshakeStorage.getPort()); + } + return super.getMpPass(user); + } + + /* + Stolen from https://github.com/FlorianMichael/Classic4J/blob/main/src/main/java/de/florianmichael/classic4j/BetaCraftHandler.java :tm: + */ + + private static String getBetacraftMpPass(final UserConnection user, final String username, final String ip, final int port) { + try { + final String server = InetAddress.getByName(ip).getHostAddress() + ":" + port; + + Via.getManager().getProviders().get(OldAuthProvider.class).sendAuthRequest(user, sha1(server.getBytes())); + + final InputStream connection = new URL("https://api.betacraft.uk/getmppass.jsp?user=" + username + "&server=" + server).openStream(); + Scanner scanner = new Scanner(connection); + StringBuilder response = new StringBuilder(); + while (scanner.hasNext()) { + response.append(scanner.next()); + } + connection.close(); + + if (response.toString().contains("FAILED") || response.toString().contains("SERVER NOT FOUND")) return "0"; + + return response.toString(); + } catch (Throwable t) { + Via.getPlatform().getLogger().log(Level.WARNING, "An unknown error occurred while authenticating with BetaCraft", t); + return "0"; + } + } + + private static String sha1(final byte[] input) { + try { + Formatter formatter = new Formatter(); + final byte[] hash = MessageDigest.getInstance("SHA-1").digest(input); + for (byte b : hash) { + formatter.format("%02x", b); + } + return formatter.toString(); + } catch (Exception e) { + return null; + } + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeEncryptionProvider.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeEncryptionProvider.java new file mode 100644 index 0000000..dc550a4 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeEncryptionProvider.java @@ -0,0 +1,13 @@ +package de.florianmichael.viaforge.common.protocolhack.provider; + +import com.viaversion.viaversion.api.connection.UserConnection; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.providers.EncryptionProvider; + +public class ViaForgeEncryptionProvider extends EncryptionProvider { + + @Override + public void enableDecryption(UserConnection user) { + user.getChannel().attr(ViaForgeCommon.VF_NETWORK_MANAGER).getAndRemove().viaForge$setupPreNettyDecryption(); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeOldAuthProvider.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeOldAuthProvider.java new file mode 100644 index 0000000..a075758 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeOldAuthProvider.java @@ -0,0 +1,18 @@ +package de.florianmichael.viaforge.common.protocolhack.provider; + +import com.viaversion.viaversion.api.connection.UserConnection; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.raphimc.vialegacy.protocols.release.protocol1_3_1_2to1_2_4_5.providers.OldAuthProvider; + +public class ViaForgeOldAuthProvider extends OldAuthProvider { + + @Override + public void sendAuthRequest(UserConnection user, String serverId) throws Throwable { + final ViaForgeCommon common = ViaForgeCommon.getManager(); + if (!common.getConfig().isVerifySessionInOldVersions()) { + return; + } + + common.getPlatform().joinServer(serverId); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeVersionProvider.java b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeVersionProvider.java new file mode 100644 index 0000000..ab650a1 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/common/protocolhack/provider/ViaForgeVersionProvider.java @@ -0,0 +1,40 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.common.protocolhack.provider; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.base.BaseVersionProvider; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.raphimc.vialoader.util.VersionEnum; + +public class ViaForgeVersionProvider extends BaseVersionProvider { + + @Override + public int getClosestServerProtocol(UserConnection connection) throws Exception { + if (connection.isClientSide() && !ViaForgeCommon.getManager().getPlatform().isSingleplayer().get()) { + try { + System.out.println(connection.getChannel().attr(ViaForgeCommon.VF_NETWORK_MANAGER).get()); + } catch (Exception e) { + e.printStackTrace(); + } + return connection.getChannel().attr(ViaForgeCommon.VF_NETWORK_MANAGER).get().viaForge$getTrackedVersion().getVersion(); + } + + return super.getClosestServerProtocol(connection); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/gui/GuiProtocolSelector.java b/src/main/java/de/florianmichael/viaforge/gui/GuiProtocolSelector.java index e88a0f6..cbe6082 100644 --- a/src/main/java/de/florianmichael/viaforge/gui/GuiProtocolSelector.java +++ b/src/main/java/de/florianmichael/viaforge/gui/GuiProtocolSelector.java @@ -18,47 +18,85 @@ package de.florianmichael.viaforge.gui; import com.mojang.realmsclient.gui.ChatFormatting; -import de.florianmichael.viaforge.ViaForge; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.util.DumpUtil; +import de.florianmichael.viaforge.common.ViaForgeCommon; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiSlot; import net.raphimc.vialoader.util.VersionEnum; +import org.lwjgl.input.Keyboard; import org.lwjgl.opengl.GL11; import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.ExecutionException; public class GuiProtocolSelector extends GuiScreen { private final GuiScreen parent; + private final boolean simple; + private final FinishedCallback finishedCallback; - public SlotList list; + private SlotList list; - public GuiProtocolSelector(GuiScreen parent) { + private String status; + private long time; + + public GuiProtocolSelector(final GuiScreen parent) { + this(parent, false, (version, unused) -> { + // Default action is to set the target version and go back to the parent screen. + ViaForgeCommon.getManager().setTargetVersion(version); + }); + } + + public GuiProtocolSelector(final GuiScreen parent, final boolean simple, final FinishedCallback finishedCallback) { this.parent = parent; + this.simple = simple; + this.finishedCallback = finishedCallback; } @Override public void initGui() { super.initGui(); - buttonList.add(new GuiButton(1, width / 2 - 100, height - 27, 200, - 20, "Back")); + buttonList.add(new GuiButton(1, 5, height - 25, 20, 20, "<-")); + if (!this.simple) { + buttonList.add(new GuiButton(2, width - 105, 5, 100, 20, "Create dump")); + buttonList.add(new GuiButton(3, width - 105, height - 25, 100, 20, "Reload configs")); + } - list = new SlotList(mc, width, height, 32, height - 32, 10); + list = new SlotList(mc, width, height, 3 + 3 /* start offset */ + (fontRendererObj.FONT_HEIGHT + 2) * 3 /* title is 2 */, height - 30, fontRendererObj.FONT_HEIGHT + 2); + } + + public void setStatus(final String status) { + this.status = status; + this.time = System.currentTimeMillis(); } @Override - protected void actionPerformed(GuiButton p_actionPerformed_1_) throws IOException { - list.actionPerformed(p_actionPerformed_1_); + protected void actionPerformed(GuiButton button) { + list.actionPerformed(button); - if (p_actionPerformed_1_.id == 1) + if (button.id == 1) { mc.displayGuiScreen(parent); + } else if (button.id == 2) { + try { + GuiScreen.setClipboardString(DumpUtil.postDump(UUID.randomUUID()).get()); + setStatus(ChatFormatting.GREEN + "Dump created and copied to clipboard"); + } catch (InterruptedException | ExecutionException e) { + setStatus(ChatFormatting.RED + "Failed to create dump: " + e.getMessage()); + } + } else { + Via.getManager().getConfigurationProvider().reloadConfigs(); + } } @Override - protected void keyTyped(char p_keyTyped_1_, int p_keyTyped_2_) throws IOException { - if (p_keyTyped_2_ == 1) //esc key - this.mc.displayGuiScreen(parent); + protected void keyTyped(char typedChar, int keyCode) { + if (keyCode == Keyboard.KEY_ESCAPE) { + mc.displayGuiScreen(parent); + } } @Override @@ -68,24 +106,28 @@ public class GuiProtocolSelector extends GuiScreen { } @Override - public void drawScreen(int p_drawScreen_1_, int p_drawScreen_2_, float p_drawScreen_3_) { - list.drawScreen(p_drawScreen_1_, p_drawScreen_2_, p_drawScreen_3_); + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + if (System.currentTimeMillis() - this.time >= 10_000) { + this.status = null; + } + + list.drawScreen(mouseX, mouseY, partialTicks); GL11.glPushMatrix(); GL11.glScalef(2.0F, 2.0F, 2.0F); - this.drawCenteredString(this.fontRendererObj, ChatFormatting.GOLD + "ViaForge", this.width / 4, 6, 16777215); + drawCenteredString(fontRendererObj, ChatFormatting.GOLD + "ViaForge", width / 4, 3, 16777215); GL11.glPopMatrix(); - drawString(this.fontRendererObj, "https://github.com/FlorianMichael/ViaForge", 1, 1, -1); - drawString(this.fontRendererObj, "Discord: EnZaXD#6257", 1, 11, -1); + drawCenteredString(fontRendererObj, "https://github.com/ViaVersion/ViaForge", width / 2, (fontRendererObj.FONT_HEIGHT + 2) * 2 + 3, -1); + drawString(fontRendererObj, status != null ? status : "Discord: florianmichael", 3, 3, -1); - super.drawScreen(p_drawScreen_1_, p_drawScreen_2_, p_drawScreen_3_); + super.drawScreen(mouseX, mouseY, partialTicks); } class SlotList extends GuiSlot { - public SlotList(Minecraft p_i1052_1_, int p_i1052_2_, int p_i1052_3_, int p_i1052_4_, int p_i1052_5_, int p_i1052_6_) { - super(p_i1052_1_, p_i1052_2_, p_i1052_3_, p_i1052_4_, p_i1052_5_, p_i1052_6_); + public SlotList(Minecraft client, int width, int height, int top, int bottom, int slotHeight) { + super(client, width, height, top, bottom, slotHeight); } @Override @@ -94,12 +136,12 @@ public class GuiProtocolSelector extends GuiScreen { } @Override - protected void elementClicked(int i, boolean b, int i1, int i2) { - ViaForge.targetVersion = VersionEnum.SORTED_VERSIONS.get(i); + protected void elementClicked(int index, boolean b, int i1, int i2) { + finishedCallback.finished(VersionEnum.SORTED_VERSIONS.get(index), parent); } @Override - protected boolean isSelected(int i) { + protected boolean isSelected(int index) { return false; } @@ -109,10 +151,23 @@ public class GuiProtocolSelector extends GuiScreen { } @Override - protected void drawSlot(int i, int i1, int i2, int i3, int i4, int i5) { - final VersionEnum version = VersionEnum.SORTED_VERSIONS.get(i); + protected void drawSlot(int index, int x, int y, int slotHeight, int mouseX, int mouseY) { + final VersionEnum targetVersion = ViaForgeCommon.getManager().getTargetVersion(); + final VersionEnum version = VersionEnum.SORTED_VERSIONS.get(index); - drawCenteredString(mc.fontRendererObj, (ViaForge.targetVersion.getVersion() == version.getVersion() ? ChatFormatting.GREEN.toString() : ChatFormatting.DARK_RED.toString()) + version.getName(), width / 2, i2, -1); + String color; + if (targetVersion == version) { + color = GuiProtocolSelector.this.simple ? ChatFormatting.GOLD.toString() : ChatFormatting.GREEN.toString(); + } else { + color = GuiProtocolSelector.this.simple ? ChatFormatting.WHITE.toString() : ChatFormatting.DARK_RED.toString(); + } + + drawCenteredString(mc.fontRendererObj,(color) + version.getName(), width / 2, y, -1); } } + + public interface FinishedCallback { + + void finished(final VersionEnum version, final GuiScreen parent); + } } diff --git a/src/main/java/de/florianmichael/viaforge/mixin/MixinLoader.java b/src/main/java/de/florianmichael/viaforge/mixin/MixinLoader.java index 215a971..6f4d644 100644 --- a/src/main/java/de/florianmichael/viaforge/mixin/MixinLoader.java +++ b/src/main/java/de/florianmichael/viaforge/mixin/MixinLoader.java @@ -27,9 +27,8 @@ import java.util.Map; public class MixinLoader implements IFMLLoadingPlugin { public MixinLoader() { - System.out.println("Starting MixinBootstrap from IFMLLoadingPlugin"); MixinBootstrap.init(); - Mixins.addConfiguration("mixins.viaforge.json"); + Mixins.addConfiguration("mixins.viaforge-mc18.json"); MixinEnvironment.getDefaultEnvironment().setSide(MixinEnvironment.Side.CLIENT); } @@ -49,7 +48,8 @@ public class MixinLoader implements IFMLLoadingPlugin { } @Override - public void injectData(Map data) { } + public void injectData(Map data) { + } @Override public String getAccessTransformerClass() { diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiConnecting_1.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiConnecting_1.java new file mode 100644 index 0000000..8160438 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiConnecting_1.java @@ -0,0 +1,35 @@ +package de.florianmichael.viaforge.mixin.impl; + +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.gui.ExtendedServerData; +import net.minecraft.client.Minecraft; +import net.minecraft.network.NetworkManager; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.net.InetAddress; + +@Mixin(targets = "net.minecraft.client.multiplayer.GuiConnecting$1") +public class MixinGuiConnecting_1 { + + @Redirect(method = "run", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkManager;func_181124_a(Ljava/net/InetAddress;IZ)Lnet/minecraft/network/NetworkManager;")) + public NetworkManager trackVersion(InetAddress address, int i, boolean b) { + // We need to track the version of the server we are connecting to, so we can later + // use it to determine the protocol version to use. + // We hope that the current server data is not null + if (Minecraft.getMinecraft().getCurrentServerData() instanceof ExtendedServerData) { + final VersionEnum version = ((ExtendedServerData) Minecraft.getMinecraft().getCurrentServerData()).viaForge$getVersion(); + if (version != null) { + ViaForgeCommon.getManager().setTargetVersionSilent(version); + } else { + // If the server data does not contain a version, we need to restore the version + // we had before, so we don't use the wrong version. + ViaForgeCommon.getManager().restoreVersion(); + } + } + + return NetworkManager.func_181124_a(address, i, b); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMainMenuGuiMultiplayerGuiServerList.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMainMenu.java similarity index 54% rename from src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMainMenuGuiMultiplayerGuiServerList.java rename to src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMainMenu.java index 7cd1a25..d8be098 100644 --- a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMainMenuGuiMultiplayerGuiServerList.java +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMainMenu.java @@ -17,6 +17,10 @@ */ package de.florianmichael.viaforge.mixin.impl; +import com.viaversion.viaversion.util.Pair; +import de.florianmichael.viaforge.ViaForge18; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.platform.ViaForgeConfig; import de.florianmichael.viaforge.gui.GuiProtocolSelector; import net.minecraft.client.gui.*; import org.spongepowered.asm.mixin.Mixin; @@ -24,20 +28,27 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(value = { - GuiMainMenu.class, GuiMultiplayer.class, GuiScreenServerList.class -}) -public class MixinGuiMainMenuGuiMultiplayerGuiServerList extends GuiScreen { +@Mixin(GuiMainMenu.class) +public class MixinGuiMainMenu extends GuiScreen { @Inject(method = "initGui", at = @At("RETURN")) - public void hookCustomButton(CallbackInfo ci) { - buttonList.add(new GuiButton(1337, 5, 6, 98, 20, "ViaForge")); + public void hookViaForgeButton(CallbackInfo ci) { + ViaForgeCommon.init(ViaForge18.PLATFORM); + + final ViaForgeConfig config = ViaForgeCommon.getManager().getConfig(); + if (config.isShowMainMenuButton()) { + final Pair pos = config.getViaForgeButtonPosition().getPosition(this.width, this.height); + + buttonList.add(new GuiButton(1_000_000_000, pos.key(), pos.value(), 100, 20, "ViaForge")); + } } @Inject(method = "actionPerformed", at = @At("RETURN")) - public void handleCustomButtonAction(GuiButton p_actionPerformed_1_, CallbackInfo ci) { - if (p_actionPerformed_1_.id == 1337) { - mc.displayGuiScreen(new GuiProtocolSelector(this)); + public void handleViaForgeButtonClicking(GuiButton p_actionPerformed_1_, CallbackInfo ci) { + if (ViaForgeCommon.getManager().getConfig().isShowMainMenuButton()) { + if (p_actionPerformed_1_.id == 1_000_000_000) { + mc.displayGuiScreen(new GuiProtocolSelector(this)); + } } } } diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMultiplayer.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMultiplayer.java new file mode 100644 index 0000000..c2d57d6 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiMultiplayer.java @@ -0,0 +1,53 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.mixin.impl; + +import com.viaversion.viaversion.util.Pair; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.platform.ViaForgeConfig; +import de.florianmichael.viaforge.gui.GuiProtocolSelector; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiMultiplayer; +import net.minecraft.client.gui.GuiScreen; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiMultiplayer.class) +public class MixinGuiMultiplayer extends GuiScreen { + + @Inject(method = "initGui", at = @At("RETURN")) + public void hookViaForgeButton(CallbackInfo ci) { + final ViaForgeConfig config = ViaForgeCommon.getManager().getConfig(); + if (config.isShowMultiplayerButton()) { + final Pair pos = config.getViaForgeButtonPosition().getPosition(this.width, this.height); + + buttonList.add(new GuiButton(1_000_000_000, pos.key(), pos.value(), 100, 20, "ViaForge")); + } + } + + @Inject(method = "actionPerformed", at = @At("RETURN")) + public void handleViaForgeButtonClicking(GuiButton p_actionPerformed_1_, CallbackInfo ci) { + if (ViaForgeCommon.getManager().getConfig().isShowMultiplayerButton()) { + if (p_actionPerformed_1_.id == 1_000_000_000) { + mc.displayGuiScreen(new GuiProtocolSelector(this)); + } + } + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiOverlayDebug.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiOverlayDebug.java new file mode 100644 index 0000000..da7ad59 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiOverlayDebug.java @@ -0,0 +1,35 @@ +package de.florianmichael.viaforge.mixin.impl; + +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.minecraft.client.gui.GuiOverlayDebug; +import net.raphimc.vialegacy.api.LegacyProtocolVersion; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import java.util.List; + +@Mixin(GuiOverlayDebug.class) +public class MixinGuiOverlayDebug { + + @Inject(method = "getDebugInfoRight", at = @At(value = "TAIL")) + public void addViaForgeVersion(CallbackInfoReturnable> cir) { + final ViaForgeCommon common = ViaForgeCommon.getManager(); + final VersionEnum version = ViaForgeCommon.getManager().getTargetVersion(); + + if (common.getConfig().isShowProtocolVersionInF3() && version != common.getNativeVersion() && !common.getPlatform().isSingleplayer().get()) { + cir.getReturnValue().add(""); + + int protocolVersion = version.getVersion(); + if (version.isOlderThanOrEqualTo(VersionEnum.r1_6_4)) { + // Older versions (<= 1.6.4) are using fake ids in ViaLegacy to prevent version duplications / mismatches + // So we need to unmap the version to get the real protocol version id + protocolVersion = LegacyProtocolVersion.getRealProtocolVersion(protocolVersion); + } + + cir.getReturnValue().add("ViaForge: " + version.getName() + " (" + protocolVersion + ")"); + } + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiScreenAddServer.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiScreenAddServer.java new file mode 100644 index 0000000..8de1b8d --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiScreenAddServer.java @@ -0,0 +1,66 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.mixin.impl; + +import com.viaversion.viaversion.util.Pair; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.gui.ExtendedServerData; +import de.florianmichael.viaforge.common.platform.ViaForgeConfig; +import de.florianmichael.viaforge.gui.GuiProtocolSelector; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiScreenAddServer; +import net.minecraft.client.multiplayer.ServerData; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiScreenAddServer.class) +public class MixinGuiScreenAddServer extends GuiScreen { + + @Shadow @Final private ServerData serverData; + + @Inject(method = "initGui", at = @At("RETURN")) + public void initGui(CallbackInfo ci) { + final ViaForgeConfig config = ViaForgeCommon.getManager().getConfig(); + + if (config.isShowAddServerButton()) { + final Pair pos = config.getAddServerScreenButtonPosition().getPosition(this.width, this.height); + + final VersionEnum target = ((ExtendedServerData) serverData).viaForge$getVersion(); + buttonList.add(new GuiButton(1_000_000_000, pos.key(), pos.value(), 100, 20, target != null ? target.getName() : "Set Version")); + } + } + + @Inject(method = "actionPerformed", at = @At("HEAD")) + public void actionPerformed(GuiButton button, CallbackInfo ci) { + if (ViaForgeCommon.getManager().getConfig().isShowAddServerButton()) { + if (button.id == 1_000_000_000) { + mc.displayGuiScreen(new GuiProtocolSelector(this, true, (version, parent) -> { + // Set version and go back to the parent screen. + ((ExtendedServerData) serverData).viaForge$setVersion(version); + mc.displayGuiScreen(parent); + })); + } + } + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiScreenServerList.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiScreenServerList.java new file mode 100644 index 0000000..c4d1546 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinGuiScreenServerList.java @@ -0,0 +1,53 @@ +/* + * This file is part of ViaForge - https://github.com/FlorianMichael/ViaForge + * Copyright (C) 2021-2023 FlorianMichael/EnZaXD and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package de.florianmichael.viaforge.mixin.impl; + +import com.viaversion.viaversion.util.Pair; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.platform.ViaForgeConfig; +import de.florianmichael.viaforge.gui.GuiProtocolSelector; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiScreenServerList; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(GuiScreenServerList.class) +public class MixinGuiScreenServerList extends GuiScreen { + + @Inject(method = "initGui", at = @At("RETURN")) + public void hookViaForgeButton(CallbackInfo ci) { + final ViaForgeConfig config = ViaForgeCommon.getManager().getConfig(); + if (config.isShowDirectConnectButton()) { + final Pair pos = config.getViaForgeButtonPosition().getPosition(this.width, this.height); + + buttonList.add(new GuiButton(1_000_000_000, pos.key(), pos.value(), 100, 20, "ViaForge")); + } + } + + @Inject(method = "actionPerformed", at = @At("RETURN")) + public void handleViaForgeButtonClicking(GuiButton p_actionPerformed_1_, CallbackInfo ci) { + if (ViaForgeCommon.getManager().getConfig().isShowDirectConnectButton()) { + if (p_actionPerformed_1_.id == 1_000_000_000) { + mc.displayGuiScreen(new GuiProtocolSelector(this)); + } + } + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetHandlerLoginClient.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetHandlerLoginClient.java new file mode 100644 index 0000000..19610fc --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetHandlerLoginClient.java @@ -0,0 +1,37 @@ +package de.florianmichael.viaforge.mixin.impl; + +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.exceptions.AuthenticationException; +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.viaversion.viaversion.api.connection.UserConnection; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.minecraft.client.network.NetHandlerLoginClient; +import net.minecraft.network.NetworkManager; +import net.raphimc.vialegacy.protocols.release.protocol1_7_2_5to1_6_4.storage.ProtocolMetadataStorage; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@SuppressWarnings("DataFlowIssue") +@Mixin(NetHandlerLoginClient.class) +public class MixinNetHandlerLoginClient { + + @Shadow @Final private NetworkManager networkManager; + + @Redirect(method = "handleEncryptionRequest", at = @At(value = "INVOKE", target = "Lcom/mojang/authlib/minecraft/MinecraftSessionService;joinServer(Lcom/mojang/authlib/GameProfile;Ljava/lang/String;Ljava/lang/String;)V")) + public void onlyJoinServerIfPremium(MinecraftSessionService instance, GameProfile profile, String authenticationToken, String serverId) throws AuthenticationException { + if (ViaForgeCommon.getManager().getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_6_4)) { + final UserConnection user = networkManager.channel().attr(ViaForgeCommon.LOCAL_VIA_USER).get(); + if (user != null && user.has(ProtocolMetadataStorage.class) && !user.get(ProtocolMetadataStorage.class).authenticate) { + // We are in the 1.7 -> 1.6 protocol, so we need to skip the joinServer call + // if the server is in offline mode, due the packet changes <-> networking changes + // Minecraft's networking code is bad for us. + return; + } + } + instance.joinServer(profile, authenticationToken, serverId); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager.java index 125b249..fb71119 100644 --- a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager.java +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager.java @@ -17,22 +17,90 @@ */ package de.florianmichael.viaforge.mixin.impl; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.protocolhack.netty.VFNetworkManager; import io.netty.channel.Channel; +import net.minecraft.network.NettyEncryptingDecoder; +import net.minecraft.network.NettyEncryptingEncoder; import net.minecraft.network.NetworkManager; -import net.raphimc.vialoader.netty.CompressionReorderEvent; +import net.minecraft.util.CryptManager; +import net.minecraft.util.IChatComponent; +import net.minecraft.util.LazyLoadBase; +import net.raphimc.vialoader.netty.VLLegacyPipeline; +import net.raphimc.vialoader.util.VersionEnum; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import java.net.InetAddress; @Mixin(NetworkManager.class) -public class MixinNetworkManager { +public class MixinNetworkManager implements VFNetworkManager { @Shadow private Channel channel; + @Unique + private Cipher viaForge$decryptionCipher; + + @Unique + private VersionEnum viaForge$targetVersion; + + @Inject(method = "func_181124_a", at = @At(value = "INVOKE", target = "Lio/netty/bootstrap/Bootstrap;group(Lio/netty/channel/EventLoopGroup;)Lio/netty/bootstrap/AbstractBootstrap;"), locals = LocalCapture.CAPTURE_FAILHARD) + private static void trackSelfTarget(InetAddress address, int serverPort, boolean useNativeTransport, CallbackInfoReturnable cir, NetworkManager networkmanager, Class oclass, LazyLoadBase lazyloadbase) { + // The connecting screen and server pinger are setting the main target version when a specific version for a server is set, + // This works for joining perfect since we can simply restore the version when the server doesn't have a specific one set, + // but for the server pinger we need to store the target version and force the pinging to use the target version. + // Due to the fact that the server pinger is being called multiple times. + ((VFNetworkManager) networkmanager).viaForge$setTrackedVersion(ViaForgeCommon.getManager().getTargetVersion()); + } + + @Inject(method = "enableEncryption", at = @At("HEAD"), cancellable = true) + private void storeEncryptionCiphers(SecretKey key, CallbackInfo ci) { + if (ViaForgeCommon.getManager().getTargetVersion().isOlderThanOrEqualTo(VersionEnum.r1_6_4)) { + // Minecraft's encryption code is bad for us, we need to reorder the pipeline + ci.cancel(); + + // Minecraft 1.6.4 supports tile encryption which means the server can only disable one side of the encryption + // So we only enable the encryption side and later enable the decryption side if the 1.7 -> 1.6 protocol + // tells us to do, therefore we need to store the cipher instance. + this.viaForge$decryptionCipher = CryptManager.createNetCipherInstance(2, key); + + // Enabling the encryption side + this.channel.pipeline().addBefore(VLLegacyPipeline.VIALEGACY_PRE_NETTY_LENGTH_REMOVER_NAME, "encrypt", new NettyEncryptingEncoder(CryptManager.createNetCipherInstance(1, key))); + } + } + + @Inject(method = "closeChannel", at = @At("HEAD")) + public void restoreTargetVersion(IChatComponent message, CallbackInfo ci) { + // If the previous server forced a version, we need to restore the version to the default one. + ViaForgeCommon.getManager().restoreVersion(); + } + @Inject(method = "setCompressionTreshold", at = @At("RETURN")) - public void reOrderPipeline(int p_setCompressionTreshold_1_, CallbackInfo ci) { - channel.pipeline().fireUserEventTriggered(CompressionReorderEvent.INSTANCE); + public void reorderPipeline(int p_setCompressionTreshold_1_, CallbackInfo ci) { + ViaForgeCommon.getManager().reorderCompression(channel); + } + + @Override + public void viaForge$setupPreNettyDecryption() { + // Enabling the decryption side for 1.6.4 if the 1.7 -> 1.6 protocol tells us to do + this.channel.pipeline().addBefore(VLLegacyPipeline.VIALEGACY_PRE_NETTY_LENGTH_REMOVER_NAME, "decrypt", new NettyEncryptingDecoder(this.viaForge$decryptionCipher)); + } + + @Override + public VersionEnum viaForge$getTrackedVersion() { + return viaForge$targetVersion; + } + + @Override + public void viaForge$setTrackedVersion(VersionEnum version) { + viaForge$targetVersion = version; } } diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager_5.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager_5.java index 63c484d..35182c8 100644 --- a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager_5.java +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinNetworkManager_5.java @@ -17,14 +17,11 @@ */ package de.florianmichael.viaforge.mixin.impl; -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.connection.UserConnectionImpl; -import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; -import de.florianmichael.viaforge.ViaForge; -import de.florianmichael.viaforge.ViaForgeVLLegacyPipeline; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.protocolhack.netty.VFNetworkManager; import io.netty.channel.Channel; -import io.netty.channel.socket.SocketChannel; -import org.spongepowered.asm.mixin.Mixin; +import net.minecraft.network.NetworkManager; +import org.spongepowered.asm.mixin.*; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -32,13 +29,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(targets = "net.minecraft.network.NetworkManager$5") public class MixinNetworkManager_5 { + @Final + @Mutable + NetworkManager val$networkmanager; + @Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false) private void onInitChannel(Channel channel, CallbackInfo ci) { - if (channel instanceof SocketChannel && ViaForge.targetVersion != ViaForge.NATIVE_VERSION) { - final UserConnection user = new UserConnectionImpl(channel, true); - new ProtocolPipelineImpl(user); - - channel.pipeline().addLast(new ViaForgeVLLegacyPipeline(user, ViaForge.targetVersion)); - } + ViaForgeCommon.getManager().inject(channel, (VFNetworkManager) val$networkmanager); } } diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinServerData.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinServerData.java new file mode 100644 index 0000000..31f64a0 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinServerData.java @@ -0,0 +1,51 @@ +package de.florianmichael.viaforge.mixin.impl; + +import de.florianmichael.viaforge.common.gui.ExtendedServerData; +import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.nbt.NBTTagCompound; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(ServerData.class) +public class MixinServerData implements ExtendedServerData { + + @Unique + private VersionEnum viaForge$version; + + @Inject(method = "getNBTCompound", at = @At(value = "INVOKE", target = "Lnet/minecraft/nbt/NBTTagCompound;setString(Ljava/lang/String;Ljava/lang/String;)V", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) + public void saveVersion(CallbackInfoReturnable cir, NBTTagCompound nbttagcompound) { + if (viaForge$version != null) { + nbttagcompound.setInteger("viaForge$version", viaForge$version.getVersion()); + } + } + + @Inject(method = "getServerDataFromNBTCompound", at = @At(value = "TAIL")) + private static void getVersion(NBTTagCompound nbtCompound, CallbackInfoReturnable cir) { + if (nbtCompound.hasKey("viaForge$version")) { + ((ExtendedServerData) cir.getReturnValue()).viaForge$setVersion(VersionEnum.fromProtocolId(nbtCompound.getInteger("viaForge$version"))); + } + } + + @Inject(method = "copyFrom", at = @At("HEAD")) + public void track(ServerData serverDataIn, CallbackInfo ci) { + if (serverDataIn instanceof ExtendedServerData) { + viaForge$version = ((ExtendedServerData) serverDataIn).viaForge$getVersion(); + } + } + + @Override + public VersionEnum viaForge$getVersion() { + return viaForge$version; + } + + @Override + public void viaForge$setVersion(VersionEnum version) { + viaForge$version = version; + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinServerPinger.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinServerPinger.java new file mode 100644 index 0000000..49c7808 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/MixinServerPinger.java @@ -0,0 +1,50 @@ +package de.florianmichael.viaforge.mixin.impl; + +import de.florianmichael.viaforge.common.ViaForgeCommon; +import de.florianmichael.viaforge.common.gui.ExtendedServerData; +import net.minecraft.client.multiplayer.ServerData; +import net.minecraft.client.network.OldServerPinger; +import net.minecraft.network.NetworkManager; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.net.InetAddress; + +@Mixin(OldServerPinger.class) +public class MixinServerPinger { + + @Unique + private ServerData viaForge$serverData; + + @Inject(method = "ping", at = @At("HEAD")) + public void trackServerData(ServerData server, CallbackInfo ci) { + viaForge$serverData = server; + } + + @Redirect(method = "ping", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkManager;func_181124_a(Ljava/net/InetAddress;IZ)Lnet/minecraft/network/NetworkManager;")) + public NetworkManager trackVersion(InetAddress address, int i, boolean b) { + // We need to track the version of the server we are connecting to, so we can later + // use it to determine the protocol version to use. + // We hope that the current server data is not null + + if (viaForge$serverData instanceof ExtendedServerData) { + final VersionEnum version = ((ExtendedServerData) viaForge$serverData).viaForge$getVersion(); + if (version != null) { + ViaForgeCommon.getManager().setTargetVersionSilent(version); + } else { + // If the server data does not contain a version, we need to restore the version + // we had before, so we don't use the wrong version. + ViaForgeCommon.getManager().restoreVersion(); + } + + viaForge$serverData = null; + } + + return NetworkManager.func_181124_a(address, i, b); + } +} diff --git a/src/main/java/de/florianmichael/viaforge/mixin/impl/fixes/MixinEntityPlayerSP.java b/src/main/java/de/florianmichael/viaforge/mixin/impl/fixes/MixinEntityPlayerSP.java new file mode 100644 index 0000000..452a684 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/mixin/impl/fixes/MixinEntityPlayerSP.java @@ -0,0 +1,44 @@ +package de.florianmichael.viaforge.mixin.impl.fixes; + +import com.mojang.authlib.GameProfile; +import de.florianmichael.viaforge.common.ViaForgeCommon; +import net.minecraft.client.entity.AbstractClientPlayer; +import net.minecraft.client.entity.EntityPlayerSP; +import net.minecraft.client.network.NetHandlerPlayClient; +import net.minecraft.network.Packet; +import net.minecraft.world.World; +import net.raphimc.vialoader.util.VersionEnum; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(EntityPlayerSP.class) +public class MixinEntityPlayerSP extends AbstractClientPlayer { + + public MixinEntityPlayerSP(World worldIn, GameProfile playerProfile) { + super(worldIn, playerProfile); + } + + @Unique + private boolean viaForge$prevOnGround; + + @Redirect(method = "onUpdateWalkingPlayer", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/NetHandlerPlayClient;addToSendQueue(Lnet/minecraft/network/Packet;)V", ordinal = 7)) + public void emulateIdlePacket(NetHandlerPlayClient instance, Packet p_addToSendQueue_1_) { + if (ViaForgeCommon.getManager().getTargetVersion().isNewerThan(VersionEnum.r1_8)) { + // <= 1.8 spams the idle packet instead of only sending it when the ground state changes + if (this.viaForge$prevOnGround == this.onGround) { + return; + } + } + instance.addToSendQueue(p_addToSendQueue_1_); + } + + @Inject(method = "onUpdateWalkingPlayer", at = @At("RETURN")) + public void saveGroundState(CallbackInfo ci) { + this.viaForge$prevOnGround = this.onGround; + } +} diff --git a/src/main/java/de/florianmichael/viaforge/provider/ViaForgeGameProfileFetcher.java b/src/main/java/de/florianmichael/viaforge/provider/ViaForgeGameProfileFetcher.java new file mode 100644 index 0000000..2d06f53 --- /dev/null +++ b/src/main/java/de/florianmichael/viaforge/provider/ViaForgeGameProfileFetcher.java @@ -0,0 +1,57 @@ +package de.florianmichael.viaforge.provider; + +import com.mojang.authlib.Agent; +import com.mojang.authlib.GameProfileRepository; +import com.mojang.authlib.HttpAuthenticationService; +import com.mojang.authlib.ProfileLookupCallback; +import com.mojang.authlib.minecraft.MinecraftSessionService; +import com.mojang.authlib.properties.Property; +import com.mojang.authlib.yggdrasil.ProfileNotFoundException; +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService; +import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.model.GameProfile; +import net.raphimc.vialegacy.protocols.release.protocol1_8to1_7_6_10.providers.GameProfileFetcher; + +import java.net.Proxy; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +public class ViaForgeGameProfileFetcher extends GameProfileFetcher { + public final static HttpAuthenticationService AUTHENTICATION_SERVICE = new YggdrasilAuthenticationService(Proxy.NO_PROXY, ""); + public final static MinecraftSessionService SESSION_SERVICE = AUTHENTICATION_SERVICE.createMinecraftSessionService(); + public final static GameProfileRepository GAME_PROFILE_REPOSITORY = AUTHENTICATION_SERVICE.createProfileRepository(); + + @Override + public UUID loadMojangUUID(String playerName) throws Exception { + final CompletableFuture future = new CompletableFuture<>(); + GAME_PROFILE_REPOSITORY.findProfilesByNames(new String[]{playerName}, Agent.MINECRAFT, new ProfileLookupCallback() { + @Override + public void onProfileLookupSucceeded(com.mojang.authlib.GameProfile profile) { + future.complete(profile); + } + + @Override + public void onProfileLookupFailed(com.mojang.authlib.GameProfile profile, Exception exception) { + future.completeExceptionally(exception); + } + }); + if (!future.isDone()) { + future.completeExceptionally(new ProfileNotFoundException()); + } + return future.get().getId(); + } + + @Override + public GameProfile loadGameProfile(UUID uuid) throws Exception { + final com.mojang.authlib.GameProfile inProfile = new com.mojang.authlib.GameProfile(uuid, null); + final com.mojang.authlib.GameProfile mojangProfile = SESSION_SERVICE.fillProfileProperties(inProfile, true); + if (mojangProfile.equals(inProfile)) throw new ProfileNotFoundException(); + + final GameProfile gameProfile = new GameProfile(mojangProfile.getName(), mojangProfile.getId()); + for (final java.util.Map.Entry entry : mojangProfile.getProperties().entries()) { + final Property prop = entry.getValue(); + gameProfile.addProperty(new GameProfile.Property(prop.getName(), prop.getValue(), prop.getSignature())); + } + + return gameProfile; + } +} diff --git a/src/main/resources/mcmod.info b/src/main/resources/mcmod.info new file mode 100644 index 0000000..17fe0d6 --- /dev/null +++ b/src/main/resources/mcmod.info @@ -0,0 +1,18 @@ +[ + { + "modid": "viaforge", + "name": "ViaForge", + "description": "Client-side Implementation of the Via* projects for Minecraft Forge", + "version": "${version}", + "mcversion": "[1.8]", + "url": "https://github.com/ViaVersion/ViaForge", + "updateUrl": "", + "authorList": [ + "FlorianMichael/EnZaXD" + ], + "credits": "https://github.com/FlorianMichael/", + "logoFile": "", + "screenshots": [], + "dependencies": [] + } +] diff --git a/src/main/resources/mixins.viaforge-mc18.json b/src/main/resources/mixins.viaforge-mc18.json new file mode 100644 index 0000000..832ee6e --- /dev/null +++ b/src/main/resources/mixins.viaforge-mc18.json @@ -0,0 +1,23 @@ +{ + "required": true, + "minVersion": "0.7.5", + "compatibilityLevel": "JAVA_8", + "package": "de.florianmichael.viaforge.mixin.impl", + "refmap": "mixins.viaforge.refmap.json", + "client": [ + "MixinGuiMainMenu", + "MixinGuiMultiplayer", + "MixinGuiOverlayDebug", + "MixinGuiScreenAddServer", + "MixinGuiScreenServerList", + "MixinNetHandlerLoginClient", + "MixinNetworkManager", + "MixinNetworkManager_5", + "MixinServerPinger", + "fixes.MixinEntityPlayerSP" + ], + "verbose": true, + "mixins": [ + "MixinGuiConnecting_1" + ] +} diff --git a/src/main/resources/mixins.viaforge.json b/src/main/resources/mixins.viaforge.json deleted file mode 100644 index c87fcbc..0000000 --- a/src/main/resources/mixins.viaforge.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "required": true, - "minVersion": "0.7.5", - "compatibilityLevel": "JAVA_8", - "package": "de.florianmichael.viaforge.mixin.impl", - "refmap": "mixins.viaforge.refmap.json", - "mixins": [ - "MixinNetworkManager", - "MixinNetworkManager_5" - ], - "verbose": true, - "client": [ - "MixinGuiMainMenuGuiMultiplayerGuiServerList", - "MixinMinecraft" - ] -}