From a29320acf2f509e0e8a9098e932dc3323846ee2b Mon Sep 17 00:00:00 2001 From: EnZaXD Date: Sun, 16 Jun 2024 18:21:04 +0200 Subject: [PATCH] Add 1.21 support (#342) --- README.md | 2 +- gradle.properties | 4 +- settings.gradle.kts | 1 + src/main/resources/fabric.mod.json | 4 +- viafabric-mc121/build.gradle.kts | 11 ++ .../viaversion/fabric/mc121/ViaFabric.java | 119 ++++++++++++ .../fabric/mc121/ViaFabricClient.java | 54 ++++++ .../mc121/commands/NMSCommandSender.java | 78 ++++++++ .../mc121/commands/VFCommandHandler.java | 72 ++++++++ .../fabric/mc121/gui/ModMenuConfig.java | 36 ++++ .../fabric/mc121/gui/ViaConfigScreen.java | 172 ++++++++++++++++++ .../client/MixinAllowedAddressResolver.java | 63 +++++++ .../mixin/debug/MixinRegistrySyncManager.java | 39 ++++ .../debug/client/MixinClientConnection.java | 41 +++++ .../client/MixinClientConnectionAccessor.java | 29 +++ .../mixin/debug/client/MixinDebugHud.java | 56 ++++++ .../client/MixinRegistrySyncManager.java | 49 +++++ ...inMultiplayerServerListPingerListener.java | 50 +++++ .../mixin/gui/client/MixinServerEntry.java | 61 +++++++ .../mixin/gui/client/MixinServerInfo.java | 52 ++++++ .../mixin/pipeline/MixinClientConnection.java | 68 +++++++ .../client/MixinClientConnection.java | 44 +++++ .../shutdown/server/MixinMinecraftServer.java | 34 ++++ .../platform/FabricNativeVersionProvider.java | 28 +++ .../fabric/mc121/platform/FabricPlatform.java | 140 ++++++++++++++ .../fabric/mc121/platform/VFLoader.java | 54 ++++++ .../providers/FabricVersionProvider.java | 52 ++++++ .../mc121/providers/VFHandItemProvider.java | 74 ++++++++ .../providers/VFPlayerAbilitiesProvider.java | 39 ++++ .../providers/VFPlayerLookTargetProvider.java | 39 ++++ .../mc121/service/ProtocolAutoDetector.java | 160 ++++++++++++++++ .../src/main/resources/fabric.mod.json | 79 ++++++++ .../mixins.viafabric121.address.json | 13 ++ .../resources/mixins.viafabric121.debug.json | 17 ++ .../resources/mixins.viafabric121.gui.json | 15 ++ .../mixins.viafabric121.pipeline.json | 14 ++ .../mixins.viafabric121.shutdown.json | 13 ++ 37 files changed, 1871 insertions(+), 5 deletions(-) create mode 100644 viafabric-mc121/build.gradle.kts create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabric.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabricClient.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/commands/NMSCommandSender.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/commands/VFCommandHandler.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ModMenuConfig.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ViaConfigScreen.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/address/client/MixinAllowedAddressResolver.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/MixinRegistrySyncManager.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinClientConnection.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinClientConnectionAccessor.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinDebugHud.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinRegistrySyncManager.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinMultiplayerServerListPingerListener.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerEntry.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerInfo.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/MixinClientConnection.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/client/MixinClientConnection.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/shutdown/server/MixinMinecraftServer.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/FabricNativeVersionProvider.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/FabricPlatform.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/VFLoader.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/FabricVersionProvider.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFHandItemProvider.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFPlayerAbilitiesProvider.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFPlayerLookTargetProvider.java create mode 100644 viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/service/ProtocolAutoDetector.java create mode 100644 viafabric-mc121/src/main/resources/fabric.mod.json create mode 100644 viafabric-mc121/src/main/resources/mixins.viafabric121.address.json create mode 100644 viafabric-mc121/src/main/resources/mixins.viafabric121.debug.json create mode 100644 viafabric-mc121/src/main/resources/mixins.viafabric121.gui.json create mode 100644 viafabric-mc121/src/main/resources/mixins.viafabric121.pipeline.json create mode 100644 viafabric-mc121/src/main/resources/mixins.viafabric121.shutdown.json diff --git a/README.md b/README.md index aa04f9d..e1a660d 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Allows the connection to/from different Minecraft versions on your Minecraft client/server (LAN worlds too) -This mod can be installed on 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.4, 1.20.6 with Fabric Loader. +This mod can be installed on 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.4, 1.20.6, 1.21 with Fabric Loader. ## Dependencies diff --git a/gradle.properties b/gradle.properties index 978d79b..a96cadc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,10 +2,10 @@ org.gradle.jvmargs=-Xms32M -Xmx4G -XX:+UseG1GC -XX:+UseStringDeduplication loader_version=0.15.11 -viaver_version=5.0.0-SNAPSHOT +viaver_version=5.0.0 yaml_version=2.2 -publish_mc_versions=1.20.6, 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 +publish_mc_versions=1.21, 1.20.6, 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 063eb77..f847891 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -19,6 +19,7 @@ include("viafabric-mc1194") include("viafabric-mc1201") include("viafabric-mc1204") include("viafabric-mc1206") +include("viafabric-mc121") plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 7fe6860..49aca38 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -13,8 +13,8 @@ }, "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.1", "1.20.3", "1.20.4", "1.20.5", "1.20.6"], - "viaversion": ">=4.10.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.1", "1.20.3", "1.20.4", "1.20.5", "1.20.6", "1.21"], + "viaversion": ">=5.0.0" }, "breaks": { "viafabricplus": "*" diff --git a/viafabric-mc121/build.gradle.kts b/viafabric-mc121/build.gradle.kts new file mode 100644 index 0000000..8fa4e23 --- /dev/null +++ b/viafabric-mc121/build.gradle.kts @@ -0,0 +1,11 @@ +dependencies { + minecraft("com.mojang:minecraft:1.21") + mappings("net.fabricmc:yarn:1.21+build.1:v2") + + modImplementation("net.fabricmc.fabric-api:fabric-api:0.100.1+1.21") + modImplementation("com.terraformersmc:modmenu:11.0.0-beta.1") +} + +tasks.compileJava { + options.release.set(21) +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabric.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabric.java new file mode 100644 index 0000000..716f192 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121; + +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.mc121.commands.VFCommandHandler; +import com.viaversion.fabric.mc121.platform.FabricPlatform; +import com.viaversion.fabric.mc121.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(), JLOGGER); + + 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-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabricClient.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabricClient.java new file mode 100644 index 0000000..83bd42f --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/ViaFabricClient.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.mc121; + +import com.viaversion.fabric.mc121.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.ButtonTextures; +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 + new ButtonTextures(Identifier.of("viafabric", "widget_unfocused"), Identifier.of("viafabric", "widget_focused")), + 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-mc121/src/main/java/com/viaversion/fabric/mc121/commands/NMSCommandSender.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/commands/NMSCommandSender.java new file mode 100644 index 0000000..e6c6b0c --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.commands; + +import com.viaversion.viaversion.api.command.ViaCommandSender; +import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource; +import net.minecraft.command.CommandSource; +import net.minecraft.entity.Entity; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; + +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.Serialization.fromJson(legacy, DynamicRegistryManager.EMPTY); + } + + @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().getName().getString(); + } + return "?"; + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/commands/VFCommandHandler.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/commands/VFCommandHandler.java new file mode 100644 index 0000000..0d40b53 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.commands; + +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 com.viaversion.fabric.common.commands.subs.LeakDetectSubCommand; +import com.viaversion.viaversion.commands.ViaCommandHandler; +import net.minecraft.command.CommandSource; + +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-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ModMenuConfig.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ModMenuConfig.java new file mode 100644 index 0000000..6925797 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ViaConfigScreen.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ViaConfigScreen.java new file mode 100644 index 0000000..0f22561 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/gui/ViaConfigScreen.java @@ -0,0 +1,172 @@ +/* + * 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.mc121.gui; + +import com.viaversion.fabric.common.config.AbstractViaConfigScreen; +import com.viaversion.fabric.common.util.ProtocolUtils; +import com.viaversion.fabric.mc121.ViaFabric; +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.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) { + super.render(drawContext, mouseX, mouseY, delta); + drawContext.drawCenteredTextWithShadow(this.textRenderer, this.title, this.width / 2, 20, 16777215); + } + + @Override + public void tick() { + super.tick(); + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/address/client/MixinAllowedAddressResolver.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/address/client/MixinAllowedAddressResolver.java new file mode 100644 index 0000000..bd9ac71 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/MixinRegistrySyncManager.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/MixinRegistrySyncManager.java new file mode 100644 index 0000000..c5cd5d9 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/MixinRegistrySyncManager.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.mc121.mixin.debug; + +import com.viaversion.fabric.mc121.ViaFabric; +import net.fabricmc.fabric.impl.registry.sync.RegistrySyncManager; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerConfigurationNetworkHandler; +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(value = RegistrySyncManager.class, remap = false) +public class MixinRegistrySyncManager { + + @Inject(method = "configureClient", at = @At("HEAD"), cancellable = true) + private static void ignoreMissingRegistries(ServerConfigurationNetworkHandler handler, MinecraftServer server, CallbackInfo ci) { + if (ViaFabric.config.isIgnoreRegistrySyncErrors()) { + ci.cancel(); + } + } + +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinClientConnection.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinClientConnection.java new file mode 100644 index 0000000..bcae086 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinClientConnectionAccessor.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinClientConnectionAccessor.java new file mode 100644 index 0000000..cfd4b5d --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinDebugHud.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinDebugHud.java new file mode 100644 index 0000000..b68dbe8 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinDebugHud.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.mc121.mixin.debug.client; + +import com.viaversion.fabric.common.handler.CommonTransformer; +import com.viaversion.fabric.common.handler.FabricDecodeHandler; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ProtocolInfo; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +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 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) { + UserConnection connection = ((FabricDecodeHandler) viaDecoder).getInfo(); + ProtocolInfo protocol = connection.getProtocolInfo(); + if (protocol != null) { + ProtocolVersion serverVer = protocol.serverProtocolVersion(); + ProtocolVersion clientVer = protocol.protocolVersion(); + line += " / C: " + clientVer + " S: " + serverVer + " A: " + connection.isActive(); + } + } + + info.getReturnValue().add(line); + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinRegistrySyncManager.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinRegistrySyncManager.java new file mode 100644 index 0000000..a1af42d --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/debug/client/MixinRegistrySyncManager.java @@ -0,0 +1,49 @@ +/* + * 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.mc121.mixin.debug.client; + +import com.viaversion.fabric.mc121.ViaFabric; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import net.fabricmc.fabric.impl.registry.sync.RegistrySyncManager; +import net.minecraft.util.Identifier; +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; + +import java.util.Map; + +@Mixin(value = RegistrySyncManager.class, remap = false) +public class MixinRegistrySyncManager { + + @Shadow + @Final + private static Logger LOGGER; + + @Inject(method = "checkRemoteRemap", at = @At(value = "INVOKE", target = "Lorg/slf4j/Logger;error(Ljava/lang/String;)V", ordinal = 0), cancellable = true) + private static void ignoreMissingRegistries(Map> map, CallbackInfo ci) { + if (ViaFabric.config.isIgnoreRegistrySyncErrors()) { + LOGGER.warn("Ignoring missing registries"); + ci.cancel(); + } + } + +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinMultiplayerServerListPingerListener.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinMultiplayerServerListPingerListener.java new file mode 100644 index 0000000..d50620b --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.mixin.gui.client; + +import com.viaversion.fabric.common.gui.ViaServerInfo; +import com.viaversion.fabric.common.handler.FabricDecodeHandler; +import com.viaversion.fabric.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerEntry.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerEntry.java new file mode 100644 index 0000000..cbdb122 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerEntry.java @@ -0,0 +1,61 @@ +/* + * 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.mc121.mixin.gui.client; + +import com.google.common.collect.Lists; +import com.viaversion.fabric.common.gui.ViaServerInfo; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +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.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; +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; + + @ModifyArg(method = "render", at = @At(value = "INVOKE", ordinal = 0, + target = "Lnet/minecraft/client/gui/DrawContext;drawGuiTexture(Lnet/minecraft/util/Identifier;IIII)V")) + private Identifier redirectPingIcon(Identifier texture) { + if (((ViaServerInfo) this.server).viaFabric$translating() && texture.getPath().startsWith("server_list/ping")) { + return Identifier.of("viafabric", texture.getPath()); + } + return texture; + } + + @Redirect(method = "render", at = @At(value = "INVOKE", ordinal = 0, target = "Lnet/minecraft/client/gui/screen/multiplayer/MultiplayerScreen;setTooltip(Lnet/minecraft/text/Text;)V")) + private void addServerVer(MultiplayerScreen instance, Text text) { + ProtocolVersion proto = ProtocolVersion.getProtocol(((ViaServerInfo) this.server).viaFabric$getServerVer()); + List lines = new ArrayList<>(); + lines.add(text); + lines.add(Text.translatable("gui.ping_version.translated", proto.getName(), proto.getVersion())); + instance.setTooltip(Lists.transform(lines, Text::asOrderedText)); + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerInfo.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/gui/client/MixinServerInfo.java new file mode 100644 index 0000000..774456c --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/MixinClientConnection.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/MixinClientConnection.java new file mode 100644 index 0000000..ce928d5 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/MixinClientConnection.java @@ -0,0 +1,68 @@ +/* + * 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.mc121.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.fabric.common.handler.PipelineReorderEvent; +import com.viaversion.fabric.common.protocol.HostnameParserProtocol; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.ProtocolPipeline; +import com.viaversion.viaversion.connection.UserConnectionImpl; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import io.netty.channel.Channel; +import io.netty.channel.ChannelPipeline; +import io.netty.channel.socket.SocketChannel; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.NetworkSide; +import net.minecraft.network.handler.HandlerNames; +import net.minecraft.network.handler.PacketSizeLogger; +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()); + } + + @Inject(method = "addHandlers", at = @At("RETURN")) + private static void onAddHandlers(ChannelPipeline pipeline, NetworkSide side, boolean local, PacketSizeLogger packetSizeLogger, CallbackInfo ci) { + final Channel channel = pipeline.channel(); + if (channel instanceof SocketChannel) { + final UserConnection user = new UserConnectionImpl(channel, side == NetworkSide.CLIENTBOUND); + final ProtocolPipeline protocolPipeline = new ProtocolPipelineImpl(user); + + final boolean clientSide = user.isClientSide(); + if (clientSide) { + protocolPipeline.add(HostnameParserProtocol.INSTANCE); + } + + pipeline.addBefore(clientSide ? HandlerNames.ENCODER : HandlerNames.OUTBOUND_CONFIG, CommonTransformer.HANDLER_ENCODER_NAME, new FabricEncodeHandler(user)); + pipeline.addBefore(clientSide ? HandlerNames.INBOUND_CONFIG : HandlerNames.DECODER, CommonTransformer.HANDLER_DECODER_NAME, new FabricDecodeHandler(user)); + } + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/client/MixinClientConnection.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/client/MixinClientConnection.java new file mode 100644 index 0000000..01fc6b1 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/pipeline/client/MixinClientConnection.java @@ -0,0 +1,44 @@ +/* + * 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.mc121.mixin.pipeline.client; + +import com.viaversion.fabric.mc121.ViaFabric; +import com.viaversion.fabric.mc121.service.ProtocolAutoDetector; +import io.netty.channel.ChannelFuture; +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(Ljava/net/InetSocketAddress;ZLnet/minecraft/network/ClientConnection;)Lio/netty/channel/ChannelFuture;", at = @At("HEAD")) + private static void onConnect(InetSocketAddress address, boolean useEpoll, ClientConnection connection, 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-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/shutdown/server/MixinMinecraftServer.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/shutdown/server/MixinMinecraftServer.java new file mode 100644 index 0000000..123d3dc --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/mixin/shutdown/server/MixinMinecraftServer.java @@ -0,0 +1,34 @@ +/* + * 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.mc121.mixin.shutdown.server; + +import com.viaversion.viaversion.ViaManagerImpl; +import com.viaversion.viaversion.api.Via; +import net.minecraft.server.MinecraftServer; +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(MinecraftServer.class) +public class MixinMinecraftServer { + @Inject(method = "stop", at = @At("TAIL")) + private void onStop(CallbackInfo ci) { + ((ViaManagerImpl) Via.getManager()).destroy(); + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/FabricNativeVersionProvider.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/FabricNativeVersionProvider.java new file mode 100644 index 0000000..631a56b --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/platform/FabricPlatform.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/FabricPlatform.java new file mode 100644 index 0000000..b069451 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.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.mc121.ViaFabric; +import com.viaversion.fabric.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/platform/VFLoader.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/platform/VFLoader.java new file mode 100644 index 0000000..deadc05 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.platform; + +import com.viaversion.fabric.mc121.providers.FabricVersionProvider; +import com.viaversion.fabric.mc121.providers.VFHandItemProvider; +import com.viaversion.fabric.mc121.providers.VFPlayerAbilitiesProvider; +import com.viaversion.fabric.mc121.providers.VFPlayerLookTargetProvider; +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.v1_12_2to1_13.provider.PlayerLookTargetProvider; +import com.viaversion.viaversion.protocols.v1_15_2to1_16.provider.PlayerAbilitiesProvider; +import com.viaversion.viaversion.protocols.v1_8to1_9.provider.HandItemProvider; +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; + +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-mc121/src/main/java/com/viaversion/fabric/mc121/providers/FabricVersionProvider.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/FabricVersionProvider.java new file mode 100644 index 0000000..dbb0753 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.providers; + +import com.viaversion.fabric.common.config.VFConfig; +import com.viaversion.fabric.common.provider.AbstractFabricVersionProvider; +import com.viaversion.fabric.mc121.ViaFabric; +import com.viaversion.fabric.mc121.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-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFHandItemProvider.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFHandItemProvider.java new file mode 100644 index 0000000..31a707e --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.providers; + +import com.viaversion.fabric.common.util.RemappingUtil; +import com.viaversion.fabric.mc121.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.v1_8to1_9.provider.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, null); + } + return clientItem.copy(); + } + + @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-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFPlayerAbilitiesProvider.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFPlayerAbilitiesProvider.java new file mode 100644 index 0000000..e05a863 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.providers; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.protocols.v1_15_2to1_16.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-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFPlayerLookTargetProvider.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/providers/VFPlayerLookTargetProvider.java new file mode 100644 index 0000000..f8e5464 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/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.mc121.providers; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.minecraft.BlockPosition; +import com.viaversion.viaversion.protocols.v1_12_2to1_13.provider.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 BlockPosition getPlayerLookTarget(UserConnection info) { + if (!info.isClientSide()) return null; + + if (MinecraftClient.getInstance().crosshairTarget instanceof BlockHitResult blockHitResult) { + final BlockPos pos = blockHitResult.getBlockPos(); + return new BlockPosition(pos.getX(), pos.getY(), pos.getZ()); + } + return null; + } +} diff --git a/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/service/ProtocolAutoDetector.java b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/service/ProtocolAutoDetector.java new file mode 100644 index 0000000..51ed734 --- /dev/null +++ b/viafabric-mc121/src/main/java/com/viaversion/fabric/mc121/service/ProtocolAutoDetector.java @@ -0,0 +1,160 @@ +/* + * 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.mc121.service; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.viaversion.fabric.common.AddressParser; +import com.viaversion.fabric.mc121.ViaFabric; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +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.SharedConstants; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.DisconnectionInfo; +import net.minecraft.network.NetworkSide; +import net.minecraft.network.handler.EncoderHandler; +import net.minecraft.network.handler.NetworkStateTransitions; +import net.minecraft.network.handler.SizePrepender; +import net.minecraft.network.handler.SplitterHandler; +import net.minecraft.network.listener.ClientQueryPacketListener; +import net.minecraft.network.packet.c2s.handshake.ConnectionIntent; +import net.minecraft.network.packet.c2s.handshake.HandshakeC2SPacket; +import net.minecraft.network.packet.c2s.query.QueryRequestC2SPacket; +import net.minecraft.network.packet.s2c.query.PingResultS2CPacket; +import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket; +import net.minecraft.network.state.HandshakeStates; +import net.minecraft.network.state.QueryStates; +import net.minecraft.server.ServerMetadata; +import net.minecraft.text.Text; +import org.jetbrains.annotations.NotNull; + +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<>() { + @Override + protected void initChannel(@NotNull 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(null)) + .addLast("inbound_config", new NetworkStateTransitions.InboundConfigurer()) + .addLast("prepender", new SizePrepender()) + .addLast("encoder", new EncoderHandler<>(HandshakeStates.C2S)) + .addLast("packet_handler", clientConnection); + } + }) + .connect(address); + + ch.addListener(future1 -> { + if (!future1.isSuccess()) { + future.completeExceptionally(future1.cause()); + } else { + ch.channel().eventLoop().submit(() -> { // needs to execute after channel init + clientConnection.transitionInbound(QueryStates.S2C, 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 onPingResult(PingResultS2CPacket packet) { + clientConnection.disconnect(Text.literal("Pong not requested!")); + } + + @Override + public void onDisconnected(DisconnectionInfo info) { + future.completeExceptionally(new IllegalStateException(info.reason().getString())); + } + + @Override + public boolean isConnectionOpen() { + return ch.channel().isOpen(); + } + }); + + //noinspection deprecation + clientConnection.send(new HandshakeC2SPacket( + SharedConstants.getGameVersion().getProtocolVersion(), + address.getHostString(), + address.getPort(), + ConnectionIntent.STATUS + )); + + clientConnection.transitionOutbound(QueryStates.C2S); + clientConnection.send(QueryRequestC2SPacket.INSTANCE); + }); + } + }); + } 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-mc121/src/main/resources/fabric.mod.json b/viafabric-mc121/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..9df2ff6 --- /dev/null +++ b/viafabric-mc121/src/main/resources/fabric.mod.json @@ -0,0 +1,79 @@ +{ + "schemaVersion": 1, + "id": "viafabric-mc121", + "name": "ViaFabric for 1.21", + "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.mc121.ViaFabric" + ], + "client": [ + "com.viaversion.fabric.mc121.ViaFabricClient" + ], + "modmenu": [ + "com.viaversion.fabric.mc121.gui.ModMenuConfig" + ] + }, + "depends": { + "fabric-resource-loader-v0": "*", + "minecraft": ["1.21"], + "viafabric": "*" + }, + "recommends": { + "fabric-command-api-v2": "*" + }, + "mixins": [ + "mixins.viafabric121.address.json", + "mixins.viafabric121.gui.json", + "mixins.viafabric121.debug.json", + "mixins.viafabric121.pipeline.json", + "mixins.viafabric121.shutdown.json" + ], + "custom": { + "modmenu": { + "parent": "viafabric" + } + } +} diff --git a/viafabric-mc121/src/main/resources/mixins.viafabric121.address.json b/viafabric-mc121/src/main/resources/mixins.viafabric121.address.json new file mode 100644 index 0000000..531b0a5 --- /dev/null +++ b/viafabric-mc121/src/main/resources/mixins.viafabric121.address.json @@ -0,0 +1,13 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_21", + "package": "com.viaversion.fabric.mc121.mixin.address", + "mixins": [ + ], + "client": [ + "client.MixinAllowedAddressResolver" + ], + "injectors": { + "defaultRequire": 0 + } +} diff --git a/viafabric-mc121/src/main/resources/mixins.viafabric121.debug.json b/viafabric-mc121/src/main/resources/mixins.viafabric121.debug.json new file mode 100644 index 0000000..a6b55b7 --- /dev/null +++ b/viafabric-mc121/src/main/resources/mixins.viafabric121.debug.json @@ -0,0 +1,17 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_21", + "package": "com.viaversion.fabric.mc121.mixin.debug", + "mixins": [ + "MixinRegistrySyncManager" + ], + "client": [ + "client.MixinRegistrySyncManager", + "client.MixinClientConnection", + "client.MixinClientConnectionAccessor", + "client.MixinDebugHud" + ], + "injectors": { + "defaultRequire": 0 + } +} diff --git a/viafabric-mc121/src/main/resources/mixins.viafabric121.gui.json b/viafabric-mc121/src/main/resources/mixins.viafabric121.gui.json new file mode 100644 index 0000000..04ad0a7 --- /dev/null +++ b/viafabric-mc121/src/main/resources/mixins.viafabric121.gui.json @@ -0,0 +1,15 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_21", + "package": "com.viaversion.fabric.mc121.mixin.gui", + "mixins": [ + ], + "client": [ + "client.MixinMultiplayerServerListPingerListener", + "client.MixinServerEntry", + "client.MixinServerInfo" + ], + "injectors": { + "defaultRequire": 0 + } +} diff --git a/viafabric-mc121/src/main/resources/mixins.viafabric121.pipeline.json b/viafabric-mc121/src/main/resources/mixins.viafabric121.pipeline.json new file mode 100644 index 0000000..6fc1c87 --- /dev/null +++ b/viafabric-mc121/src/main/resources/mixins.viafabric121.pipeline.json @@ -0,0 +1,14 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_21", + "package": "com.viaversion.fabric.mc121.mixin.pipeline", + "mixins": [ + "MixinClientConnection" + ], + "client": [ + "client.MixinClientConnection" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/viafabric-mc121/src/main/resources/mixins.viafabric121.shutdown.json b/viafabric-mc121/src/main/resources/mixins.viafabric121.shutdown.json new file mode 100644 index 0000000..d32e078 --- /dev/null +++ b/viafabric-mc121/src/main/resources/mixins.viafabric121.shutdown.json @@ -0,0 +1,13 @@ +{ + "required": true, + "compatibilityLevel": "JAVA_21", + "package": "com.viaversion.fabric.mc121.mixin.shutdown", + "mixins": [ + ], + "server": [ + "server.MixinMinecraftServer" + ], + "injectors": { + "defaultRequire": 0 + } +}