From 75fd16de9dadf317c9554b566f97d95a7c40488c Mon Sep 17 00:00:00 2001 From: FlorianMichael <60033407+FlorianMichael@users.noreply.github.com> Date: Wed, 24 Apr 2024 08:34:19 +0200 Subject: [PATCH] 1.20.1 support Starting with this commit, VF will now support LTS or generally common versions (besides the latest minor of every major version). Many people have requested this in the past and there is no reason to not just provide it, now 1.20.1 users don't have to use ViaProxy if they are using Fabric anyway. --- gradle.properties | 2 +- settings.gradle.kts | 1 + src/main/resources/fabric.mod.json | 2 +- viafabric-mc1201/build.gradle.kts | 11 ++ .../viaversion/fabric/mc1201/ViaFabric.java | 119 ++++++++++++ .../fabric/mc1201/ViaFabricClient.java | 56 ++++++ .../mc1201/commands/NMSCommandSender.java | 78 ++++++++ .../mc1201/commands/VFCommandHandler.java | 72 +++++++ .../fabric/mc1201/gui/ModMenuConfig.java | 36 ++++ .../fabric/mc1201/gui/ViaConfigScreen.java | 176 ++++++++++++++++++ .../client/MixinAllowedAddressResolver.java | 63 +++++++ .../debug/client/MixinClientConnection.java | 41 ++++ .../client/MixinClientConnectionAccessor.java | 29 +++ .../mixin/debug/client/MixinDebugHud.java | 54 ++++++ ...inMultiplayerServerListPingerListener.java | 50 +++++ .../mixin/gui/client/MixinServerEntry.java | 65 +++++++ .../mixin/gui/client/MixinServerInfo.java | 52 ++++++ .../mixin/pipeline/MixinClientConnection.java | 39 ++++ .../pipeline/MixinServerNetworkIoChInit.java | 45 +++++ .../client/MixinClientConnection.java | 43 +++++ .../client/MixinClientConnectionChInit.java | 47 +++++ .../platform/FabricNativeVersionProvider.java | 28 +++ .../mc1201/platform/FabricPlatform.java | 140 ++++++++++++++ .../fabric/mc1201/platform/VFLoader.java | 54 ++++++ .../providers/FabricVersionProvider.java | 52 ++++++ .../mc1201/providers/VFHandItemProvider.java | 74 ++++++++ .../providers/VFPlayerAbilitiesProvider.java | 39 ++++ .../providers/VFPlayerLookTargetProvider.java | 39 ++++ .../mc1201/service/ProtocolAutoDetector.java | 141 ++++++++++++++ .../src/main/resources/fabric.mod.json | 78 ++++++++ .../mixins.viafabric1201.address.json | 13 ++ .../resources/mixins.viafabric1201.debug.json | 15 ++ .../resources/mixins.viafabric1201.gui.json | 15 ++ .../mixins.viafabric1201.pipeline.json | 16 ++ 34 files changed, 1783 insertions(+), 2 deletions(-) create mode 100644 viafabric-mc1201/build.gradle.kts create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabric.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabricClient.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/NMSCommandSender.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/VFCommandHandler.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ModMenuConfig.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ViaConfigScreen.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/address/client/MixinAllowedAddressResolver.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnection.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnectionAccessor.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinDebugHud.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinMultiplayerServerListPingerListener.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerEntry.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerInfo.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinClientConnection.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinServerNetworkIoChInit.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnection.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnectionChInit.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricNativeVersionProvider.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricPlatform.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/VFLoader.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/FabricVersionProvider.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFHandItemProvider.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerAbilitiesProvider.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerLookTargetProvider.java create mode 100644 viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/service/ProtocolAutoDetector.java create mode 100644 viafabric-mc1201/src/main/resources/fabric.mod.json create mode 100644 viafabric-mc1201/src/main/resources/mixins.viafabric1201.address.json create mode 100644 viafabric-mc1201/src/main/resources/mixins.viafabric1201.debug.json create mode 100644 viafabric-mc1201/src/main/resources/mixins.viafabric1201.gui.json create mode 100644 viafabric-mc1201/src/main/resources/mixins.viafabric1201.pipeline.json diff --git a/gradle.properties b/gradle.properties index 5df8251..ce80272 100644 --- a/gradle.properties +++ b/gradle.properties @@ -5,7 +5,7 @@ loader_version=0.15.10 viaver_version=4.10.0-24w09a-SNAPSHOT yaml_version=2.2 -publish_mc_versions=1.20.5, 1.20.4, 1.19.4, 1.18.2, 1.17.1, 1.16.5, 1.15.2, 1.14.4, 1.12.2, 1.8.9 +publish_mc_versions=1.20.5, 1.20.4, 1.20.1, 1.19.4, 1.18.2, 1.17.1, 1.16.5, 1.15.2, 1.14.4, 1.12.2, 1.8.9 # example: 1.19.1-rc1. Can be a blank value modrinth_mc_snapshot= # example: 1.19-Snapshot. Can be a blank value diff --git a/settings.gradle.kts b/settings.gradle.kts index 8d53e5f..c8daab4 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -15,6 +15,7 @@ include("viafabric-mc1165") include("viafabric-mc1171") include("viafabric-mc1182") include("viafabric-mc1194") +include("viafabric-mc1201") include("viafabric-mc1204") include("viafabric-mc1205") diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b59a7aa..b1cf0df 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -13,7 +13,7 @@ }, "depends": { "fabricloader": ">=0.14.0", - "minecraft": ["1.8.9", "1.12.2", "1.14.4", "1.15.2", "1.16.5", "1.17.1", "1.18.2", "1.19.4", ">=1.20.3"], + "minecraft": ["1.8.9", "1.12.2", "1.14.4", "1.15.2", "1.16.5", "1.17.1", "1.18.2", "1.19.4", "1.20.1", "1.20.3", "1.20.4", "1.20.5"], "viaversion": ">=4.9.3" }, "breaks": { diff --git a/viafabric-mc1201/build.gradle.kts b/viafabric-mc1201/build.gradle.kts new file mode 100644 index 0000000..24a891c --- /dev/null +++ b/viafabric-mc1201/build.gradle.kts @@ -0,0 +1,11 @@ +dependencies { + minecraft("com.mojang:minecraft:1.20.1") + mappings("net.fabricmc:yarn:1.20.1+build.2:v2") + + modImplementation("net.fabricmc.fabric-api:fabric-api:0.83.1+1.20.1") + modImplementation("com.terraformersmc:modmenu:7.1.0") +} + +tasks.compileJava { + options.release.set(17) +} \ No newline at end of file diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabric.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabric.java new file mode 100644 index 0000000..e004720 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabric.java @@ -0,0 +1,119 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import com.mojang.brigadier.builder.RequiredArgumentBuilder; +import com.viaversion.fabric.common.config.VFConfig; +import com.viaversion.fabric.common.platform.FabricInjector; +import com.viaversion.fabric.common.protocol.HostnameParserProtocol; +import com.viaversion.fabric.common.util.JLoggerToLog4j; +import com.viaversion.fabric.mc1201.commands.VFCommandHandler; +import com.viaversion.fabric.mc1201.platform.FabricPlatform; +import com.viaversion.fabric.mc1201.platform.VFLoader; +import com.viaversion.viaversion.ViaManagerImpl; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import io.netty.channel.DefaultEventLoop; +import io.netty.channel.EventLoop; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback; +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.command.CommandSource; +import org.apache.logging.log4j.LogManager; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; +import java.util.logging.Logger; + +public class ViaFabric implements ModInitializer { + public static final Logger JLOGGER = new JLoggerToLog4j(LogManager.getLogger("ViaFabric")); + public static final ExecutorService ASYNC_EXECUTOR; + public static final EventLoop EVENT_LOOP; + public static final CompletableFuture INIT_FUTURE = new CompletableFuture<>(); + public static VFConfig config; + + static { + ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ViaFabric-%d").build(); + ASYNC_EXECUTOR = Executors.newFixedThreadPool(8, factory); + EVENT_LOOP = new DefaultEventLoop(factory); + EVENT_LOOP.submit(INIT_FUTURE::join); // https://github.com/ViaVersion/ViaFabric/issues/53 ugly workaround code but works tm + } + + public static LiteralArgumentBuilder command(String commandName) { + return LiteralArgumentBuilder.literal(commandName) + .then( + RequiredArgumentBuilder + .argument("args", StringArgumentType.greedyString()) + .executes(((VFCommandHandler) Via.getManager().getCommandHandler())::execute) + .suggests(((VFCommandHandler) Via.getManager().getCommandHandler())::suggestion) + ) + .executes(((VFCommandHandler) Via.getManager().getCommandHandler())::execute); + } + + @Override + public void onInitialize() { + FabricPlatform platform = new FabricPlatform(); + + Via.init(ViaManagerImpl.builder() + .injector(new FabricInjector()) + .loader(new VFLoader()) + .commandHandler(new VFCommandHandler()) + .platform(platform).build()); + + platform.init(); + + ViaManagerImpl manager = (ViaManagerImpl) Via.getManager(); + manager.init(); + + HostnameParserProtocol.INSTANCE.initialize(); + HostnameParserProtocol.INSTANCE.register(Via.getManager().getProviders()); + ProtocolVersion.register(-2, "AUTO"); + + FabricLoader.getInstance().getEntrypoints("viafabric:via_api_initialized", Runnable.class).forEach(Runnable::run); + + registerCommandsV1(); + + config = new VFConfig(FabricLoader.getInstance().getConfigDir().resolve("ViaFabric") + .resolve("viafabric.yml").toFile()); + + manager.onServerLoaded(); + + INIT_FUTURE.complete(null); + } + + + private void registerCommandsV1() { + try { + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated, env) -> dispatcher.register(command("viaversion"))); + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated, env) -> dispatcher.register(command("viaver"))); + CommandRegistrationCallback.EVENT.register((dispatcher, dedicated, env) -> dispatcher.register(command("vvfabric"))); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(command("viafabricclient"))); + } + } catch (NoClassDefFoundError ignored) { + JLOGGER.info("Couldn't register command as Fabric Commands V1 isn't installed"); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabricClient.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabricClient.java new file mode 100644 index 0000000..632c7e7 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/ViaFabricClient.java @@ -0,0 +1,56 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201; + +import com.viaversion.fabric.mc1201.gui.ViaConfigScreen; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.screen.v1.ScreenEvents; +import net.fabricmc.fabric.api.client.screen.v1.Screens; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TexturedButtonWidget; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; + +public class ViaFabricClient implements ClientModInitializer { + @Override + public void onInitializeClient() { + registerGui(); + } + + private void registerGui() { + try { + ScreenEvents.AFTER_INIT.register((client, screen, scaledWidth, scaledHeight) -> { + if (!(screen instanceof MultiplayerScreen)) return; + ButtonWidget enableClientSideViaVersion = new TexturedButtonWidget(scaledWidth / 2 + 113, 10, + 40, 20, // Size + 0, 0, // Start pos of texture + 20, // v Hover offset + new Identifier("viafabric:textures/gui/widgets.png"), + 256, 256, // Texture size + it -> MinecraftClient.getInstance().setScreen(new ViaConfigScreen(screen)), + Text.translatable("gui.via_button")); + if (ViaFabric.config.isHideButton()) enableClientSideViaVersion.visible = false; + Screens.getButtons(screen).add(enableClientSideViaVersion); + }); + } catch (NoClassDefFoundError ignored) { + ViaFabric.JLOGGER.info("Couldn't register screen handler as Fabric Screen isn't installed"); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/NMSCommandSender.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/NMSCommandSender.java new file mode 100644 index 0000000..7b883db --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/NMSCommandSender.java @@ -0,0 +1,78 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.commands; + +import com.viaversion.viaversion.util.ComponentUtil; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandSource; +import net.minecraft.entity.Entity; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import com.viaversion.viaversion.api.command.ViaCommandSender; + +import java.nio.charset.StandardCharsets; +import java.util.UUID; + +public class NMSCommandSender implements ViaCommandSender { + private final CommandSource source; + + public NMSCommandSender(CommandSource source) { + this.source = source; + } + + @Override + public boolean hasPermission(String s) { + // https://gaming.stackexchange.com/questions/138602/what-does-op-permission-level-do + return source.hasPermissionLevel(3); + } + + public static MutableText fromLegacy(String legacy) { + return Text.Serializer.fromJson(ComponentUtil.legacyToJsonString(legacy)); + } + + @Override + public void sendMessage(String s) { + if (source instanceof ServerCommandSource) { + ((ServerCommandSource) source).sendFeedback(() -> fromLegacy(s), false); + } else if (source instanceof FabricClientCommandSource) { + ((FabricClientCommandSource) source).sendFeedback(fromLegacy(s)); + } + } + + @Override + public UUID getUUID() { + if (source instanceof ServerCommandSource) { + Entity entity = ((ServerCommandSource) source).getEntity(); + if (entity != null) return entity.getUuid(); + } else if (source instanceof FabricClientCommandSource) { + return ((FabricClientCommandSource) source).getPlayer().getUuid(); + } + return UUID.nameUUIDFromBytes(getName().getBytes(StandardCharsets.UTF_8)); + } + + @Override + public String getName() { + if (source instanceof ServerCommandSource) { + return ((ServerCommandSource) source).getName(); + } else if (source instanceof FabricClientCommandSource) { + return ((FabricClientCommandSource) source).getPlayer().getEntityName(); + } + return "?"; + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/VFCommandHandler.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/VFCommandHandler.java new file mode 100644 index 0000000..3575157 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/commands/VFCommandHandler.java @@ -0,0 +1,72 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.commands; + +import com.viaversion.fabric.common.commands.subs.LeakDetectSubCommand; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.command.CommandSource; +import com.viaversion.viaversion.commands.ViaCommandHandler; + +import java.util.concurrent.CompletableFuture; + +public class VFCommandHandler extends ViaCommandHandler { + { + try { + registerSubCommand(new LeakDetectSubCommand()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public int execute(CommandContext ctx) { + String[] args = new String[0]; + try { + args = StringArgumentType.getString(ctx, "args").split(" "); + } catch (IllegalArgumentException ignored) { + } + onCommand( + new NMSCommandSender(ctx.getSource()), + args + ); + return 1; + } + + public CompletableFuture suggestion(CommandContext ctx, SuggestionsBuilder builder) { + String[] args; + try { + args = StringArgumentType.getString(ctx, "args").split(" ", -1); + } catch (IllegalArgumentException ignored) { + args = new String[]{""}; + } + String[] pref = args.clone(); + pref[pref.length - 1] = ""; + String prefix = String.join(" ", pref); + onTabComplete(new NMSCommandSender(ctx.getSource()), args) + .stream() + .map(it -> { + SuggestionsBuilder b = new SuggestionsBuilder(builder.getInput(), prefix.length() + builder.getStart()); + b.suggest(it); + return b; + }) + .forEach(builder::add); + return builder.buildFuture(); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ModMenuConfig.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ModMenuConfig.java new file mode 100644 index 0000000..9fdd2bd --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ModMenuConfig.java @@ -0,0 +1,36 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.gui; + +import com.google.common.collect.ImmutableMap; +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; + +import java.util.Map; + +public class ModMenuConfig implements ModMenuApi { + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return ViaConfigScreen::new; + } + + @Override + public Map> getProvidedConfigScreenFactories() { + return ImmutableMap.of("viafabric", getModConfigScreenFactory()); + } +} \ No newline at end of file diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ViaConfigScreen.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ViaConfigScreen.java new file mode 100644 index 0000000..e6d92d3 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/gui/ViaConfigScreen.java @@ -0,0 +1,176 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.gui; + +import com.viaversion.fabric.common.config.AbstractViaConfigScreen; +import com.viaversion.fabric.mc1201.ViaFabric; +import com.viaversion.fabric.common.util.ProtocolUtils; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.ConfirmScreen; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.screen.ScreenTexts; +import net.minecraft.text.Text; + +import java.util.concurrent.CompletableFuture; + +@Environment(EnvType.CLIENT) +public class ViaConfigScreen extends Screen implements AbstractViaConfigScreen { + private static CompletableFuture latestProtocolSave; + private final Screen parent; + private TextFieldWidget protocolVersion; + + public ViaConfigScreen(Screen parent) { + super(Text.translatable(TITLE_TRANSLATE_ID)); + this.parent = parent; + } + + @Override + protected void init() { + int entries = 0; + + this.addDrawableChild(ButtonWidget + .builder(getClientSideText(), this::onClickClientSide) + .dimensions(calculatePosX(this.width, entries), + calculatePosY(this.height, entries), 150, 20) + .build()); + entries++; + + this.addDrawableChild(ButtonWidget + .builder(getHideViaButtonText(), this::onHideViaButton) + .dimensions(calculatePosX(this.width, entries), + calculatePosY(this.height, entries), 150, 20) + .build()); + entries++; + + protocolVersion = new TextFieldWidget(this.textRenderer, + calculatePosX(this.width, entries), + calculatePosY(this.height, entries), + 150, 20, Text.translatable("gui.protocol_version_field.name")); + entries++; + + protocolVersion.setTextPredicate(ProtocolUtils::isStartOfProtocolText); + protocolVersion.setChangedListener(this::onChangeVersionField); + int clientSideVersion = ViaFabric.config.getClientSideVersion(); + protocolVersion.setText(ProtocolUtils.getProtocolName(clientSideVersion)); + + this.addDrawableChild(protocolVersion); + + this.addDrawableChild(ButtonWidget + .builder(ScreenTexts.DONE, (it) -> close()) + .dimensions(this.width / 2 - 100, this.height - 40, 200, 20) + .build()); + } + + private void onChangeVersionField(String text) { + protocolVersion.setSuggestion(null); + int newVersion = ViaFabric.config.getClientSideVersion(); + + Integer parsed = ProtocolUtils.parseProtocolId(text); + boolean validProtocol; + + if (parsed != null) { + newVersion = parsed; + validProtocol = true; + } else { + validProtocol = false; + String[] suggestions = ProtocolUtils.getProtocolSuggestions(text); + if (suggestions.length == 1) { + protocolVersion.setSuggestion(suggestions[0].substring(text.length())); + } + } + + protocolVersion.setEditableColor(getProtocolTextColor(ProtocolVersion.getProtocol(newVersion), validProtocol)); + + int finalNewVersion = newVersion; + if (latestProtocolSave == null) latestProtocolSave = CompletableFuture.completedFuture(null); + ViaFabric.config.setClientSideVersion(finalNewVersion); + latestProtocolSave = latestProtocolSave.thenRunAsync(ViaFabric.config::save, ViaFabric.ASYNC_EXECUTOR); + } + + private void onClickClientSide(ButtonWidget widget) { + if (!ViaFabric.config.isClientSideEnabled()) { + MinecraftClient.getInstance().setScreen(new ConfirmScreen( + answer -> { + if (answer) { + ViaFabric.config.setClientSideEnabled(true); + ViaFabric.config.setClientSideVersion(-2); // AUTO + ViaFabric.config.save(); + widget.setMessage(getClientSideText()); + } + MinecraftClient.getInstance().setScreen(this); + }, + Text.translatable("gui.enable_client_side.question"), + Text.translatable("gui.enable_client_side.warning"), + Text.translatable("gui.enable_client_side.enable"), + Text.translatable("gui.cancel") + )); + } else { + ViaFabric.config.setClientSideEnabled(false); + ViaFabric.config.save(); + } + widget.setMessage(getClientSideText()); + } + + @Override + public void removed() { + ViaFabric.config.save(); + } + + @Override + public void close() { + this.client.setScreen(this.parent); + } + + private Text getClientSideText() { + return ViaFabric.config.isClientSideEnabled() ? + Text.translatable("gui.client_side.disable") + : Text.translatable("gui.client_side.enable"); + } + + private Text getHideViaButtonText() { + return ViaFabric.config.isHideButton() ? + Text.translatable("gui.hide_via_button.disable") : Text.translatable("gui.hide_via_button.enable"); + } + + private void onHideViaButton(ButtonWidget widget) { + ViaFabric.config.setHideButton(!ViaFabric.config.isHideButton()); + ViaFabric.config.save(); + widget.setMessage(getHideViaButtonText()); + } + + @Override + public void render(DrawContext drawContext, int mouseX, int mouseY, float delta) { + this.renderBackground(drawContext); + drawContext.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 20, 16777215); + super.render(drawContext, mouseX, mouseY, delta); + } + + @Override + public void tick() { + super.tick(); + protocolVersion.tick(); + } +} + diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/address/client/MixinAllowedAddressResolver.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/address/client/MixinAllowedAddressResolver.java new file mode 100644 index 0000000..c0ebe58 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/address/client/MixinAllowedAddressResolver.java @@ -0,0 +1,63 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.address.client; + +import com.viaversion.fabric.common.AddressParser; +import net.minecraft.client.network.Address; +import net.minecraft.client.network.AllowedAddressResolver; +import net.minecraft.client.network.ServerAddress; +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.CallbackInfoReturnable; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.Optional; + +@Mixin(AllowedAddressResolver.class) +public abstract class MixinAllowedAddressResolver { + @Shadow + public abstract Optional
resolve(ServerAddress address); + + @Inject(method = "resolve", at = @At(value = "HEAD"), cancellable = true) + private void resolveVF(ServerAddress address, CallbackInfoReturnable> cir) { + AddressParser viaAddr = new AddressParser().parse(address.getAddress()); + if (viaAddr.viaSuffix == null) { + return; + } + + ServerAddress realAddress = new ServerAddress(viaAddr.serverAddress, address.getPort()); + + cir.setReturnValue(resolve(realAddress).map(it -> viaFabric$addSuffix(it, viaAddr.getSuffixWithOptions()))); + } + + @Unique + private Address viaFabric$addSuffix(Address it, String viaSuffix) { + try { + return Address.create(new InetSocketAddress( + InetAddress.getByAddress(it.getHostName() + "." + viaSuffix, + it.getInetSocketAddress().getAddress().getAddress()), it.getPort())); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnection.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnection.java new file mode 100644 index 0000000..7566047 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnection.java @@ -0,0 +1,41 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.debug.client; + +import io.netty.channel.ChannelHandlerContext; +import net.minecraft.network.ClientConnection; +import org.slf4j.Logger; +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(ClientConnection.class) +public abstract class MixinClientConnection { + + @Shadow + @Final + private static Logger LOGGER; + + @Inject(method = "exceptionCaught", at = @At("TAIL")) + public void exceptionCaught(ChannelHandlerContext context, Throwable ex, CallbackInfo ci) { + LOGGER.error("Packet error", ex); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnectionAccessor.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnectionAccessor.java new file mode 100644 index 0000000..d02d1ad --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinClientConnectionAccessor.java @@ -0,0 +1,29 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.debug.client; + +import io.netty.channel.Channel; +import net.minecraft.network.ClientConnection; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(ClientConnection.class) +public interface MixinClientConnectionAccessor { + @Accessor + Channel getChannel(); +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinDebugHud.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinDebugHud.java new file mode 100644 index 0000000..53d5a46 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/debug/client/MixinDebugHud.java @@ -0,0 +1,54 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.debug.client; + +import com.viaversion.fabric.common.handler.CommonTransformer; +import com.viaversion.fabric.common.handler.FabricDecodeHandler; +import com.viaversion.viaversion.api.connection.ProtocolInfo; +import io.netty.channel.ChannelHandler; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.DebugHud; +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 com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; + +import java.util.List; + +@Mixin(DebugHud.class) +public class MixinDebugHud { + @Inject(at = @At("RETURN"), method = "getLeftText") + protected void getLeftText(CallbackInfoReturnable> info) { + String line = "[ViaFabric] I: " + Via.getManager().getConnectionManager().getConnections().size() + " (F: " + + Via.getManager().getConnectionManager().getConnectedClients().size() + ")"; + @SuppressWarnings("ConstantConditions") ChannelHandler viaDecoder = ((MixinClientConnectionAccessor) MinecraftClient.getInstance().getNetworkHandler() + .getConnection()).getChannel().pipeline().get(CommonTransformer.HANDLER_DECODER_NAME); + if (viaDecoder instanceof FabricDecodeHandler) { + ProtocolInfo protocol = ((FabricDecodeHandler) viaDecoder).getInfo().getProtocolInfo(); + if (protocol != null) { + ProtocolVersion serverVer = ProtocolVersion.getProtocol(protocol.getServerProtocolVersion()); + ProtocolVersion clientVer = ProtocolVersion.getProtocol(protocol.getProtocolVersion()); + line += " / C: " + clientVer + " S: " + serverVer + " A: " + protocol.getUser().isActive(); + } + } + + info.getReturnValue().add(line); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinMultiplayerServerListPingerListener.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinMultiplayerServerListPingerListener.java new file mode 100644 index 0000000..659c61e --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinMultiplayerServerListPingerListener.java @@ -0,0 +1,50 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.gui.client; + +import com.viaversion.fabric.common.gui.ViaServerInfo; +import com.viaversion.fabric.common.handler.FabricDecodeHandler; +import com.viaversion.fabric.mc1201.mixin.debug.client.MixinClientConnectionAccessor; +import net.minecraft.client.network.ServerInfo; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.listener.ClientQueryPacketListener; +import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(targets = "net.minecraft.client.network.MultiplayerServerListPinger$1") +public abstract class MixinMultiplayerServerListPingerListener implements ClientQueryPacketListener { + @Accessor + abstract ClientConnection getField_3774(); // Synthetic + + @Accessor + abstract ServerInfo getField_3776(); // Synthetic + + @Inject(method = "onResponse(Lnet/minecraft/network/packet/s2c/query/QueryResponseS2CPacket;)V", at = @At(value = "HEAD")) + private void onResponseCaptureServerInfo(QueryResponseS2CPacket packet, CallbackInfo ci) { + FabricDecodeHandler decoder = ((MixinClientConnectionAccessor) this.getField_3774()).getChannel() + .pipeline().get(FabricDecodeHandler.class); + if (decoder != null) { + ((ViaServerInfo) getField_3776()).viaFabric$setTranslating(decoder.getInfo().isActive()); + ((ViaServerInfo) getField_3776()).viaFabric$setServerVer(decoder.getInfo().getProtocolInfo().getServerProtocolVersion()); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerEntry.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerEntry.java new file mode 100644 index 0000000..bfa94a7 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerEntry.java @@ -0,0 +1,65 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.gui.client; + +import com.viaversion.fabric.common.gui.ViaServerInfo; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import net.minecraft.client.gui.DrawContext; +import net.minecraft.client.gui.screen.multiplayer.MultiplayerScreen; +import net.minecraft.client.gui.screen.multiplayer.MultiplayerServerListWidget; +import net.minecraft.client.network.ServerInfo; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Final; +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.Redirect; + +import java.util.ArrayList; +import java.util.List; + +@Mixin(MultiplayerServerListWidget.ServerEntry.class) +public class MixinServerEntry { + @Shadow + @Final + private ServerInfo server; + + @Unique + private static final Identifier viaFabric$GUI_ICONS_TEXTURES = new Identifier("textures/gui/icons.png"); + + @Redirect(method = "render", at = @At(value = "INVOKE", ordinal = 0, + target = "Lnet/minecraft/client/gui/DrawContext;drawTexture(Lnet/minecraft/util/Identifier;IIFFIIII)V")) + private void redirectPingIcon(DrawContext instance, Identifier texture, int x, int y, float u, float v, int width, int height, int textureWidth, int textureHeight) { + if (texture.equals(viaFabric$GUI_ICONS_TEXTURES) && ((ViaServerInfo) this.server).viaFabric$translating()) { + instance.drawTexture(new Identifier("viafabric:textures/gui/icons.png"), x, y, u, v, width, height, textureWidth, textureHeight); + return; + } + instance.drawTexture(texture, x, y, u, v, width, height, textureWidth, textureHeight); + } + + @Redirect(method = "render", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;setMultiplayerScreenTooltip(Ljava/util/List;)V")) + private void addServerVer(MultiplayerScreen multiplayerScreen, List tooltipText) { + ProtocolVersion proto = ProtocolVersion.getProtocol(((ViaServerInfo) this.server).viaFabric$getServerVer()); + List lines = new ArrayList<>(tooltipText); + lines.add(Text.translatable("gui.ping_version.translated", proto.getName(), proto.getVersion())); + lines.add(this.server.version.copy()); + multiplayerScreen.setMultiplayerScreenTooltip(lines); + } +} \ No newline at end of file diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerInfo.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerInfo.java new file mode 100644 index 0000000..e00587c --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/gui/client/MixinServerInfo.java @@ -0,0 +1,52 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.gui.client; + +import com.viaversion.fabric.common.gui.ViaServerInfo; +import net.minecraft.client.network.ServerInfo; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; + +@Mixin(ServerInfo.class) +public class MixinServerInfo implements ViaServerInfo { + @Unique + private boolean viaFabric$translating; + + @Unique + private int viaFabric$serverVer; + + @Override + public int viaFabric$getServerVer() { + return viaFabric$serverVer; + } + + @Override + public void viaFabric$setServerVer(int ver) { + this.viaFabric$serverVer = ver; + } + + @Override + public boolean viaFabric$translating() { + return viaFabric$translating; + } + + @Override + public void viaFabric$setTranslating(boolean via) { + this.viaFabric$translating = via; + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinClientConnection.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinClientConnection.java new file mode 100644 index 0000000..ccd2248 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinClientConnection.java @@ -0,0 +1,39 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.pipeline; + +import com.viaversion.fabric.common.handler.PipelineReorderEvent; +import io.netty.channel.Channel; +import net.minecraft.network.ClientConnection; +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(ClientConnection.class) +public class MixinClientConnection { + @Shadow + private Channel channel; + + @Inject(method = "setCompressionThreshold", at = @At("RETURN")) + private void reorderCompression(int compressionThreshold, boolean rejectBad, CallbackInfo ci) { + channel.pipeline().fireUserEventTriggered(new PipelineReorderEvent()); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinServerNetworkIoChInit.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinServerNetworkIoChInit.java new file mode 100644 index 0000000..fc4c0fb --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/MixinServerNetworkIoChInit.java @@ -0,0 +1,45 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.pipeline; + +import com.viaversion.fabric.common.handler.CommonTransformer; +import com.viaversion.fabric.common.handler.FabricDecodeHandler; +import com.viaversion.fabric.common.handler.FabricEncodeHandler; +import com.viaversion.viaversion.connection.UserConnectionImpl; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import io.netty.channel.Channel; +import io.netty.channel.socket.SocketChannel; +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 com.viaversion.viaversion.api.connection.UserConnection; + +@Mixin(targets = "net.minecraft.server.ServerNetworkIo$1") +public class MixinServerNetworkIoChInit { + @Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false) + private void onInitChannel(Channel channel, CallbackInfo ci) { + if (channel instanceof SocketChannel) { + UserConnection user = new UserConnectionImpl(channel); + new ProtocolPipelineImpl(user); + + channel.pipeline().addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user)); + channel.pipeline().addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user)); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnection.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnection.java new file mode 100644 index 0000000..b55cf24 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnection.java @@ -0,0 +1,43 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.pipeline.client; + +import com.viaversion.fabric.mc1201.ViaFabric; +import com.viaversion.fabric.mc1201.service.ProtocolAutoDetector; +import net.minecraft.network.ClientConnection; +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.net.InetSocketAddress; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; + +@Mixin(ClientConnection.class) +public class MixinClientConnection { + @Inject(method = "connect", at = @At("HEAD")) + private static void onConnect(InetSocketAddress address, boolean useEpoll, CallbackInfoReturnable cir) { + try { + if (!ViaFabric.config.isClientSideEnabled()) return; + ProtocolAutoDetector.detectVersion(address).get(10, TimeUnit.SECONDS); + } catch (Exception e) { + ViaFabric.JLOGGER.log(Level.WARNING, "Could not auto-detect protocol for " + address + " " + e); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnectionChInit.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnectionChInit.java new file mode 100644 index 0000000..39c7cb6 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/mixin/pipeline/client/MixinClientConnectionChInit.java @@ -0,0 +1,47 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.mixin.pipeline.client; + +import com.viaversion.fabric.common.handler.FabricDecodeHandler; +import com.viaversion.fabric.common.handler.FabricEncodeHandler; +import com.viaversion.fabric.common.handler.CommonTransformer; +import com.viaversion.fabric.common.protocol.HostnameParserProtocol; +import com.viaversion.viaversion.connection.UserConnectionImpl; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import io.netty.channel.Channel; +import io.netty.channel.socket.SocketChannel; +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 com.viaversion.viaversion.api.connection.UserConnection; + +@Mixin(targets = "net.minecraft.network.ClientConnection$1") +public class MixinClientConnectionChInit { + @Inject(method = "initChannel", at = @At(value = "TAIL"), remap = false) + private void onInitChannel(Channel channel, CallbackInfo ci) { + if (channel instanceof SocketChannel) { + UserConnection user = new UserConnectionImpl(channel, true); + new ProtocolPipelineImpl(user).add(HostnameParserProtocol.INSTANCE); + + channel.pipeline() + .addBefore("encoder", CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user)) + .addBefore("decoder", CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user)); + } + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricNativeVersionProvider.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricNativeVersionProvider.java new file mode 100644 index 0000000..b87f3f1 --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricNativeVersionProvider.java @@ -0,0 +1,28 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.platform; + +import com.viaversion.fabric.common.platform.NativeVersionProvider; +import net.minecraft.SharedConstants; + +public class FabricNativeVersionProvider implements NativeVersionProvider { + @Override + public int getNativeServerVersion() { + return SharedConstants.getGameVersion().getProtocolVersion(); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricPlatform.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricPlatform.java new file mode 100644 index 0000000..87031ea --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/FabricPlatform.java @@ -0,0 +1,140 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.platform; + +import com.viaversion.fabric.common.commands.UserCommandSender; +import com.viaversion.fabric.common.platform.NativeVersionProvider; +import com.viaversion.fabric.common.provider.AbstractFabricPlatform; +import com.viaversion.fabric.common.util.FutureTaskId; +import com.viaversion.fabric.mc1201.ViaFabric; +import com.viaversion.fabric.mc1201.commands.NMSCommandSender; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.command.ViaCommandSender; +import io.netty.channel.EventLoop; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.Entity; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.function.Supplier; +import java.util.logging.Level; + +public class FabricPlatform extends AbstractFabricPlatform { + public static MinecraftServer getServer() { + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + return getIntegratedServer(); + } + return (MinecraftServer) FabricLoader.getInstance().getGameInstance(); + } + + @Environment(EnvType.CLIENT) + private static MinecraftServer getIntegratedServer() { + return MinecraftClient.getInstance().getServer(); + } + + @Override + public FutureTaskId runSync(Runnable runnable) { + if (getServer() != null) { + return runServerSync(runnable); + } else { + return runEventLoop(runnable); + } + } + + private FutureTaskId runServerSync(Runnable runnable) { + // Kick task needs to be on main thread, it does already have error logger + return new FutureTaskId(CompletableFuture.runAsync(runnable, getServer())); + } + + @Override + public ViaCommandSender[] getOnlinePlayers() { + MinecraftServer server = getServer(); + if (server != null && server.isOnThread()) { + return getServerPlayers(); + } + return Via.getManager().getConnectionManager().getConnectedClients().values().stream() + .map(UserCommandSender::new) + .toArray(ViaCommandSender[]::new); + } + + private ViaCommandSender[] getServerPlayers() { + return getServer().getPlayerManager().getPlayerList().stream() + .map(Entity::getCommandSource) + .map(NMSCommandSender::new) + .toArray(ViaCommandSender[]::new); + } + + @Override + public void sendMessage(UUID uuid, String s) { + sendMessageServer(uuid, s); + } + + private void sendMessageServer(UUID uuid, String s) { + MinecraftServer server = getServer(); + if (server == null) return; + runServerSync(() -> { + ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid); + if (player == null) return; + player.sendMessage(NMSCommandSender.fromLegacy(s), false); + }); + } + + @Override + public boolean kickPlayer(UUID uuid, String s) { + return kickServer(uuid, s); + } + + private boolean kickServer(UUID uuid, String s) { + MinecraftServer server = getServer(); + if (server == null) return false; + Supplier kickTask = () -> { + ServerPlayerEntity player = server.getPlayerManager().getPlayer(uuid); + if (player == null) return false; + player.networkHandler.disconnect(NMSCommandSender.fromLegacy(s)); + return true; + }; + if (server.isOnThread()) { + return kickTask.get(); + } else { + ViaFabric.JLOGGER.log(Level.WARNING, "Weird!? Player kicking was called off-thread", new Throwable()); + runServerSync(kickTask::get); + } + return false; // Can't know if it worked + } + + @Override + protected void installNativeVersionProvider() { + Via.getManager().getProviders().use(NativeVersionProvider.class, new FabricNativeVersionProvider()); + } + + @Override + protected ExecutorService asyncService() { + return ViaFabric.ASYNC_EXECUTOR; + } + + @Override + protected EventLoop eventLoop() { + return ViaFabric.EVENT_LOOP; + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/VFLoader.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/VFLoader.java new file mode 100644 index 0000000..052eddf --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/platform/VFLoader.java @@ -0,0 +1,54 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.platform; + +import com.viaversion.fabric.mc1201.providers.VFHandItemProvider; +import com.viaversion.fabric.mc1201.providers.FabricVersionProvider; +import com.viaversion.fabric.mc1201.providers.VFPlayerAbilitiesProvider; +import com.viaversion.fabric.mc1201.providers.VFPlayerLookTargetProvider; +import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.PlayerLookTargetProvider; +import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.provider.PlayerAbilitiesProvider; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.platform.ViaPlatformLoader; +import com.viaversion.viaversion.api.protocol.version.VersionProvider; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider; + +public class VFLoader implements ViaPlatformLoader { + @Override + public void load() { + Via.getManager().getProviders().use(VersionProvider.class, new FabricVersionProvider()); + + if (Via.getPlatform().getConf().isItemCache()) { + VFHandItemProvider handProvider = new VFHandItemProvider(); + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + handProvider.registerClientTick(); + } + Via.getManager().getProviders().use(HandItemProvider.class, handProvider); + } + + Via.getManager().getProviders().use(PlayerAbilitiesProvider.class, new VFPlayerAbilitiesProvider()); + Via.getManager().getProviders().use(PlayerLookTargetProvider.class, new VFPlayerLookTargetProvider()); + } + + @Override + public void unload() { + // Nothing to do + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/FabricVersionProvider.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/FabricVersionProvider.java new file mode 100644 index 0000000..ca7b79f --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/FabricVersionProvider.java @@ -0,0 +1,52 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.providers; + +import com.viaversion.fabric.common.config.VFConfig; +import com.viaversion.fabric.common.provider.AbstractFabricVersionProvider; +import com.viaversion.fabric.mc1201.ViaFabric; +import com.viaversion.fabric.mc1201.service.ProtocolAutoDetector; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import io.netty.channel.ChannelPipeline; +import net.minecraft.network.ClientConnection; + +import java.net.InetSocketAddress; +import java.util.concurrent.CompletableFuture; +import java.util.logging.Logger; + +public class FabricVersionProvider extends AbstractFabricVersionProvider { + @Override + protected Logger getLogger() { + return ViaFabric.JLOGGER; + } + + @Override + protected VFConfig getConfig() { + return ViaFabric.config; + } + + @Override + protected CompletableFuture detectVersion(InetSocketAddress address) { + return ProtocolAutoDetector.detectVersion(address); + } + + @Override + protected boolean isMulticonnectHandler(ChannelPipeline pipe) { + return pipe.get(ClientConnection.class).getPacketListener().getClass().getName().startsWith("net.earthcomputer.multiconnect"); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFHandItemProvider.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFHandItemProvider.java new file mode 100644 index 0000000..d5d36bc --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFHandItemProvider.java @@ -0,0 +1,74 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.providers; + +import com.viaversion.fabric.common.util.RemappingUtil; +import com.viaversion.fabric.mc1201.ViaFabric; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.item.DataItem; +import com.viaversion.viaversion.api.minecraft.item.Item; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.HandItemProvider; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.registry.Registries; +import net.minecraft.util.Identifier; + +public class VFHandItemProvider extends HandItemProvider { + public Item clientItem = null; + + @Override + public Item getHandItem(UserConnection info) { + if (info.isClientSide()) { + return getClientItem(); + } + return super.getHandItem(info); + } + + private Item getClientItem() { + if (clientItem == null) { + return new DataItem(0, (byte) 0, (short) 0, null); + } + return new DataItem(clientItem); + } + + @Environment(EnvType.CLIENT) + public void registerClientTick() { + try { + ClientTickEvents.END_WORLD_TICK.register(clientWorld -> tickClient()); + } catch (NoClassDefFoundError ignored) { + ViaFabric.JLOGGER.info("Fabric Lifecycle V1 isn't installed"); + } + } + + private void tickClient() { + ClientPlayerEntity p = MinecraftClient.getInstance().player; + if (p != null) { + clientItem = fromNative(p.getInventory().getMainHandStack()); + } + } + + private Item fromNative(ItemStack original) { + Identifier iid = Registries.ITEM.getId(original.getItem()); + int id = RemappingUtil.swordId(iid.toString()); + return new DataItem(id, (byte) original.getCount(), (short) original.getDamage(), null); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerAbilitiesProvider.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerAbilitiesProvider.java new file mode 100644 index 0000000..9ee08ee --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerAbilitiesProvider.java @@ -0,0 +1,39 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.providers; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.protocol1_16to1_15_2.provider.PlayerAbilitiesProvider; +import net.minecraft.client.MinecraftClient; + +public class VFPlayerAbilitiesProvider extends PlayerAbilitiesProvider { + + @Override + public float getFlyingSpeed(UserConnection connection) { + if (!connection.isClientSide()) return super.getFlyingSpeed(connection); + + return MinecraftClient.getInstance().player.getAbilities().getFlySpeed(); + } + + @Override + public float getWalkingSpeed(UserConnection connection) { + if (!connection.isClientSide()) return super.getWalkingSpeed(connection); + + return MinecraftClient.getInstance().player.getAbilities().getWalkSpeed(); + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerLookTargetProvider.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerLookTargetProvider.java new file mode 100644 index 0000000..9efd56b --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/providers/VFPlayerLookTargetProvider.java @@ -0,0 +1,39 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.providers; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.Position; +import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.providers.PlayerLookTargetProvider; +import net.minecraft.client.MinecraftClient; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; + +public class VFPlayerLookTargetProvider extends PlayerLookTargetProvider { + + @Override + public Position getPlayerLookTarget(UserConnection info) { + if (!info.isClientSide()) return null; + + if (MinecraftClient.getInstance().crosshairTarget instanceof BlockHitResult blockHitResult) { + final BlockPos pos = blockHitResult.getBlockPos(); + return new Position(pos.getX(), pos.getY(), pos.getZ()); + } + return null; + } +} diff --git a/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/service/ProtocolAutoDetector.java b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/service/ProtocolAutoDetector.java new file mode 100644 index 0000000..57edbee --- /dev/null +++ b/viafabric-mc1201/src/main/java/com/viaversion/fabric/mc1201/service/ProtocolAutoDetector.java @@ -0,0 +1,141 @@ +/* + * This file is part of ViaFabric - https://github.com/ViaVersion/ViaFabric + * Copyright (C) 2018-2024 ViaVersion 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 com.viaversion.fabric.mc1201.service; + +import com.viaversion.fabric.common.AddressParser; +import com.viaversion.fabric.mc1201.ViaFabric; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import io.netty.bootstrap.Bootstrap; +import io.netty.channel.*; +import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.timeout.ReadTimeoutHandler; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.network.*; +import net.minecraft.network.listener.ClientQueryPacketListener; +import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket; +import net.minecraft.network.packet.c2s.query.QueryRequestC2SPacket; +import net.minecraft.network.packet.s2c.query.QueryPongS2CPacket; +import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket; +import net.minecraft.server.ServerMetadata; +import net.minecraft.text.Text; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; + +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; + +@Environment(EnvType.CLIENT) +public class ProtocolAutoDetector { + private static final LoadingCache> SERVER_VER = CacheBuilder.newBuilder() + .expireAfterWrite(30, TimeUnit.SECONDS) + .build(CacheLoader.from((address) -> { + CompletableFuture future = new CompletableFuture<>(); + + try { + final ClientConnection clientConnection = new ClientConnection(NetworkSide.CLIENTBOUND); + + ChannelFuture ch = new Bootstrap() + .group(ClientConnection.CLIENT_IO_GROUP.get()) + .channel(NioSocketChannel.class) + .handler(new ChannelInitializer() { + protected void initChannel(Channel channel) { + try { + channel.config().setOption(ChannelOption.TCP_NODELAY, true); + channel.config().setOption(ChannelOption.IP_TOS, 0x18); // Stolen from Velocity, low delay, high reliability + } catch (ChannelException ignored) { + } + + channel.pipeline() + .addLast("timeout", new ReadTimeoutHandler(30)) + .addLast("splitter", new SplitterHandler()) + .addLast("decoder", new DecoderHandler(NetworkSide.CLIENTBOUND)) + .addLast("prepender", new SizePrepender()) + .addLast("encoder", new PacketEncoder(NetworkSide.SERVERBOUND)) + .addLast("packet_handler", clientConnection); + } + }) + .connect(address); + + ch.addListener(future1 -> { + if (!future1.isSuccess()) { + future.completeExceptionally(future1.cause()); + } else { + ch.channel().eventLoop().execute(() -> { // needs to execute after channel init + clientConnection.setPacketListener(new ClientQueryPacketListener() { + @Override + public void onResponse(QueryResponseS2CPacket packet) { + ServerMetadata meta = packet.metadata(); + if (meta != null && meta.version().isPresent()) { + ProtocolVersion ver = ProtocolVersion.getProtocol(meta.version().get() + .protocolVersion()); + future.complete(ver); + ViaFabric.JLOGGER.info("Auto-detected " + ver + " for " + address); + } else { + future.completeExceptionally(new IllegalArgumentException("Null version in query response")); + } + clientConnection.disconnect(Text.empty()); + } + + @Override + public void onPong(QueryPongS2CPacket packet) { + clientConnection.disconnect(Text.literal("Pong not requested!")); + } + + @Override + public void onDisconnected(Text reason) { + future.completeExceptionally(new IllegalStateException(reason.getString())); + } + + @Override + public boolean isConnectionOpen() { + return ch.channel().isOpen(); + } + }); + + clientConnection.send(new HandshakeC2SPacket(address.getHostString(), + address.getPort(), NetworkState.STATUS)); + clientConnection.send(new QueryRequestC2SPacket()); + }); + } + }); + } catch (Throwable throwable) { + future.completeExceptionally(throwable); + } + + return future; + })); + + public static CompletableFuture detectVersion(InetSocketAddress address) { + try { + InetSocketAddress real = new InetSocketAddress(InetAddress.getByAddress + (new AddressParser().parse(address.getHostString()).serverAddress, + address.getAddress().getAddress()), address.getPort()); + return SERVER_VER.get(real); + } catch (UnknownHostException | ExecutionException e) { + ViaFabric.JLOGGER.log(Level.WARNING, "Protocol auto detector error: ", e); + return CompletableFuture.completedFuture(null); + } + } +} diff --git a/viafabric-mc1201/src/main/resources/fabric.mod.json b/viafabric-mc1201/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..3402ec3 --- /dev/null +++ b/viafabric-mc1201/src/main/resources/fabric.mod.json @@ -0,0 +1,78 @@ +{ + "schemaVersion": 1, + "id": "viafabric-mc1201", + "name": "ViaFabric for 1.20.1", + "version": "${version}", + "description": "${description}", + "license": "GPL-3.0", + "contact": { + "homepage": "https://viaversion.com/fabric", + "issues": "https://github.com/ViaVersion/ViaFabric/issues", + "sources": "https://github.com/ViaVersion/ViaFabric" + }, + "environment": "*", + "authors": [ + { + "name": "creeper123123321", + "contact": { + "homepage": "https://creeper123123321.github.io/" + } + }, + { + "name": "FlorianMichael/EnZaXD", + "contact": { + "homepage": "https://github.com/FlorianMichael" + } + }, + { + "name": "kennytv", + "contact": { + "homepage": "https://kennytv.eu" + } + }, + { + "name": "Kichura", + "contact": { + "homepage": "https://github.com/Kichura" + } + } + ], + "contributors": [ + { + "name": "GitHub contributors", + "contact": { + "homepage": "https://github.com/ViaVersion/ViaFabric/graphs/contributors" + } + } + ], + "entrypoints": { + "main": [ + "com.viaversion.fabric.mc1201.ViaFabric" + ], + "client": [ + "com.viaversion.fabric.mc1201.ViaFabricClient" + ], + "modmenu": [ + "com.viaversion.fabric.mc1201.gui.ModMenuConfig" + ] + }, + "depends": { + "fabric-resource-loader-v0": "*", + "minecraft": "1.20.1", + "viafabric": "*" + }, + "recommends": { + "fabric-command-api-v2": "*" + }, + "mixins": [ + "mixins.viafabric1201.address.json", + "mixins.viafabric1201.gui.json", + "mixins.viafabric1201.debug.json", + "mixins.viafabric1201.pipeline.json" + ], + "custom": { + "modmenu": { + "parent": "viafabric" + } + } +} diff --git a/viafabric-mc1201/src/main/resources/mixins.viafabric1201.address.json b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.address.json new file mode 100644 index 0000000..044e77b --- /dev/null +++ b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.address.json @@ -0,0 +1,13 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_17", + "package": "com.viaversion.fabric.mc1201.mixin.address", + "mixins": [ + ], + "client": [ + "client.MixinAllowedAddressResolver" + ], + "injectors": { + "defaultRequire": 0 + } +} diff --git a/viafabric-mc1201/src/main/resources/mixins.viafabric1201.debug.json b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.debug.json new file mode 100644 index 0000000..aa9e88b --- /dev/null +++ b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.debug.json @@ -0,0 +1,15 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_17", + "package": "com.viaversion.fabric.mc1201.mixin.debug", + "mixins": [ + ], + "client": [ + "client.MixinClientConnectionAccessor", + "client.MixinDebugHud", + "client.MixinClientConnection" + ], + "injectors": { + "defaultRequire": 0 + } +} diff --git a/viafabric-mc1201/src/main/resources/mixins.viafabric1201.gui.json b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.gui.json new file mode 100644 index 0000000..6c5cb07 --- /dev/null +++ b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.gui.json @@ -0,0 +1,15 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_17", + "package": "com.viaversion.fabric.mc1201.mixin.gui", + "mixins": [ + ], + "client": [ + "client.MixinMultiplayerServerListPingerListener", + "client.MixinServerEntry", + "client.MixinServerInfo" + ], + "injectors": { + "defaultRequire": 0 + } +} diff --git a/viafabric-mc1201/src/main/resources/mixins.viafabric1201.pipeline.json b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.pipeline.json new file mode 100644 index 0000000..6bb592f --- /dev/null +++ b/viafabric-mc1201/src/main/resources/mixins.viafabric1201.pipeline.json @@ -0,0 +1,16 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_17", + "package": "com.viaversion.fabric.mc1201.mixin.pipeline", + "mixins": [ + "MixinClientConnection", + "MixinServerNetworkIoChInit" + ], + "client": [ + "client.MixinClientConnection", + "client.MixinClientConnectionChInit" + ], + "injectors": { + "defaultRequire": 1 + } +}