diff --git a/src/main/java/com/github/creeper123123321/viafabric/mixin/MixinClientConnection.java b/src/main/java/com/github/creeper123123321/viafabric/mixin/MixinClientConnection.java new file mode 100644 index 0000000..fa9502a --- /dev/null +++ b/src/main/java/com/github/creeper123123321/viafabric/mixin/MixinClientConnection.java @@ -0,0 +1,50 @@ +/* + * MIT License + * + * Copyright (c) 2018 creeper123123321 and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.creeper123123321.viafabric.mixin; + +import net.minecraft.network.ClientConnection; +import org.apache.logging.log4j.Logger; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + + +@Mixin(ClientConnection.class) +public class MixinClientConnection { + @Redirect( + method = "exceptionCaught", + remap = false, + at = @At( + value = "INVOKE", + target = "Lorg/apache/logging/log4j/Logger;debug(Ljava/lang/String;Ljava/lang/Throwable;)V" + )) + public void redirectDebug(Logger logger, String message, Throwable t) { + if ("Failed to sent packet".equals(message)) { + logger.info(message, t); + } else { + logger.debug(message, t); + } + } +} diff --git a/src/main/java/com/github/creeper123123321/viafabric/mixin/client/MixinMultiplayerScreen.java b/src/main/java/com/github/creeper123123321/viafabric/mixin/client/MixinMultiplayerScreen.java index 0b84ca6..402d552 100644 --- a/src/main/java/com/github/creeper123123321/viafabric/mixin/client/MixinMultiplayerScreen.java +++ b/src/main/java/com/github/creeper123123321/viafabric/mixin/client/MixinMultiplayerScreen.java @@ -26,10 +26,16 @@ package com.github.creeper123123321.viafabric.mixin.client; import com.github.creeper123123321.viafabric.providers.VRVersionProvider; import com.github.creeper123123321.viafabric.util.VersionFormatFilter; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.Screen; import net.minecraft.client.gui.menu.MultiplayerScreen; +import net.minecraft.client.gui.menu.YesNoScreen; +import net.minecraft.client.gui.widget.ButtonWidget; import net.minecraft.client.gui.widget.TextFieldWidget; +import net.minecraft.client.resource.language.I18n; import net.minecraft.text.TextComponent; +import net.minecraft.text.TranslatableTextComponent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -39,6 +45,7 @@ import us.myles.ViaVersion.api.protocol.ProtocolRegistry; import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.protocols.base.VersionProvider; +import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @@ -47,7 +54,8 @@ import java.util.stream.Stream; @Mixin(MultiplayerScreen.class) public abstract class MixinMultiplayerScreen extends Screen { private TextFieldWidget protocolVersion; - private boolean validProtocol = true; + private ButtonWidget enableClientSideViaVersion; + private boolean validProtocol; private boolean supportedProtocol; protected MixinMultiplayerScreen(TextComponent textComponent_1, UnsupportedOperationException e) { @@ -94,12 +102,37 @@ public abstract class MixinMultiplayerScreen extends Screen { ? ProtocolVersion.getProtocol(clientSideVersion).getName() : Integer.toString(clientSideVersion)); this.listeners.add(protocolVersion); + + enableClientSideViaVersion = new ButtonWidget(this.screenWidth / 2 + 48, 13, 105, 15, + I18n.translate("gui.enable_client_side_button"), button -> + MinecraftClient.getInstance().openScreen(new YesNoScreen( + (answer, id) -> { + MinecraftClient.getInstance().openScreen(this); + if (answer) { + try { + FabricLoader.getInstance().getConfigDirectory().toPath().resolve("ViaFabric").resolve("enable_client_side").toFile().createNewFile(); + protocolVersion.setVisible(true); + enableClientSideViaVersion.visible = false; + } catch (IOException e) { + e.printStackTrace(); + } + } + }, + new TranslatableTextComponent("gui.enable_client_side.question"), + new TranslatableTextComponent("gui.enable_client_side.warning"), + I18n.translate("gui.enable_client_side.enable"), + I18n.translate("gui.cancel"), + 0 + ))); + protocolVersion.setVisible(FabricLoader.getInstance().getConfigDirectory().toPath().resolve("ViaFabric").resolve("enable_client_side").toFile().exists()); + enableClientSideViaVersion.visible = !protocolVersion.isVisible(); + addButton(enableClientSideViaVersion); } @Inject(method = "render", at = { - @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Screen;render(IIF)V"), - @At(value = "INVOKE", target = "Lnet/minecraft/class_437;render(IIF)V") // Generated refmap doesn't have it + @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/Screen;render(IIF)V"), + @At(value = "INVOKE", target = "Lnet/minecraft/class_437;render(IIF)V") // Generated refmap doesn't have it }, remap = false) private void onRender(int int_1, int int_2, float float_1, CallbackInfo ci) { diff --git a/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/Protocol1_8TO1_7_6_10.java b/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/Protocol1_8TO1_7_6_10.java index c8002ae..a512daa 100644 --- a/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/Protocol1_8TO1_7_6_10.java +++ b/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/Protocol1_8TO1_7_6_10.java @@ -31,8 +31,12 @@ import com.google.common.base.Charsets; import de.gerrygames.viarewind.protocol.protocol1_7_6_10to1_8.types.CustomIntType; import de.gerrygames.viarewind.protocol.protocol1_7_6_10to1_8.types.CustomStringType; import de.gerrygames.viarewind.protocol.protocol1_7_6_10to1_8.types.Types1_7_6_10; +import de.gerrygames.viarewind.utils.ChatUtil; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.TranslatableComponent; import net.md_5.bungee.chat.ComponentSerializer; import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.Via; @@ -48,6 +52,10 @@ import us.myles.ViaVersion.api.type.types.CustomByteType; import us.myles.ViaVersion.api.type.types.VoidType; import us.myles.ViaVersion.api.type.types.version.Types1_8; import us.myles.ViaVersion.packets.State; +import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8; +import us.myles.viaversion.libs.opennbt.tag.builtin.CompoundTag; +import us.myles.viaversion.libs.opennbt.tag.builtin.ListTag; +import us.myles.viaversion.libs.opennbt.tag.builtin.StringTag; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -201,7 +209,15 @@ public class Protocol1_8TO1_7_6_10 extends Protocol { @Override public void registerMap() { map(Type.INT, Type.VAR_INT); //Entity Id - map(xyzToPosition, new TypeRemapper<>(Type.POSITION)); //Position + handler(new PacketHandler() { + @Override + public void handle(PacketWrapper packetWrapper) throws Exception { + long x = packetWrapper.read(Type.INT); + long y = packetWrapper.read(Type.UNSIGNED_BYTE); + long z = packetWrapper.read(Type.INT); + packetWrapper.write(Type.POSITION, new Position(x, y, z)); + } + }); } }); @@ -900,9 +916,9 @@ public class Protocol1_8TO1_7_6_10 extends Protocol { short slots = packetWrapper.read(Type.UNSIGNED_BYTE); boolean useProvidedWindowTitle = packetWrapper.read(Type.BOOLEAN); //Use provided window title if (useProvidedWindowTitle) { - title = "{\"text\": \"" + title + "\"}"; + title = Protocol1_9TO1_8.fixJson(title); } else { - title = "{\"translate\": \"" + title + "\"}"; + title = ComponentSerializer.toString(new TranslatableComponent(title)); } packetWrapper.write(Type.STRING, title); //Window title packetWrapper.write(Type.UNSIGNED_BYTE, slots); @@ -969,7 +985,7 @@ public class Protocol1_8TO1_7_6_10 extends Protocol { @Override public void handle(PacketWrapper packetWrapper) throws Exception { for (int i = 0; i < 4; i++) - packetWrapper.write(Type.STRING, "{\"text\": \"" + packetWrapper.read(Type.STRING) + "\"}"); + packetWrapper.write(Type.STRING, Protocol1_9TO1_8.fixJson(packetWrapper.read(Type.STRING))); } }); } @@ -1224,6 +1240,29 @@ public class Protocol1_8TO1_7_6_10 extends Protocol { packetWrapper.passthrough(Type.BOOLEAN); } packetWrapper.write(Type.BYTE, (byte) 1); + } if (channel.equalsIgnoreCase("MC|TrList")) { + packetWrapper.passthrough(Type.INT); //Window Id + + int size = packetWrapper.passthrough(Type.UNSIGNED_BYTE); //Size + + for (int i = 0; i < size; i++) { + Item item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM); + packetWrapper.write(Type.ITEM, item); //Buy Item 1 + + item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM); + packetWrapper.write(Type.ITEM, item); //Buy Item 3 + + boolean has3Items = packetWrapper.passthrough(Type.BOOLEAN); + if (has3Items) { + item = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM); + packetWrapper.write(Type.ITEM, item); //Buy Item 2 + } + + packetWrapper.passthrough(Type.BOOLEAN); //Unavailable + packetWrapper.write(Type.INT, 0); //Uses + packetWrapper.write(Type.INT, 0); //Max Uses + } + } } }); @@ -1300,7 +1339,7 @@ public class Protocol1_8TO1_7_6_10 extends Protocol { this.registerIncoming(State.PLAY, 0x07, 0x07, new PacketRemapper() { @Override public void registerMap() { - map(Type.BYTE); //Status + map(Type.UNSIGNED_BYTE, Type.BYTE); //Status handler(new PacketHandler() { @Override public void handle(PacketWrapper packetWrapper) throws Exception { @@ -1510,11 +1549,46 @@ public class Protocol1_8TO1_7_6_10 extends Protocol { handler(new PacketHandler() { @Override public void handle(PacketWrapper packetWrapper) throws Exception { - byte[] data = packetWrapper.read(Type.REMAINING_BYTES); - packetWrapper.write(Type.SHORT, (short) data.length); - for (byte b : data) { - packetWrapper.write(Type.BYTE, b); + String channel = packetWrapper.get(Type.STRING, 0); + if (channel.equalsIgnoreCase("MC|ItemName")) { + byte[] name = packetWrapper.read(Type.STRING).getBytes(Charsets.UTF_8); + packetWrapper.write(Type.REMAINING_BYTES, name); + } else if (channel.equalsIgnoreCase("MC|BEdit") || channel.equalsIgnoreCase("MC|BSign")) { + packetWrapper.read(Type.SHORT); //length + Item book = packetWrapper.read(Types1_7_6_10.COMPRESSED_NBT_ITEM); + CompoundTag tag = book.getTag(); + if (tag != null && tag.contains("pages")) { + ListTag pages = tag.get("pages"); + for (int i = 0; i < pages.size(); i++) { + StringTag page = pages.get(i); + String value = page.getValue(); + value = ChatUtil.jsonToLegacy(value); + page.setValue(value); + } + } + packetWrapper.write(Type.ITEM, book); } + + packetWrapper.cancel(); + packetWrapper.setId(-1); + ByteBuf newPacketBuf = Unpooled.buffer(); + packetWrapper.writeToBuffer(newPacketBuf); + PacketWrapper newWrapper = new PacketWrapper(0x17, newPacketBuf, packetWrapper.user()); + newWrapper.passthrough(Type.STRING); + final int[] length = new int[1]; + newWrapper.read(new Type(Void.class) { + @Override + public Void read(ByteBuf byteBuf) { + length[0] = byteBuf.readableBytes(); + return null; + } + + @Override + public void write(ByteBuf byteBuf, Void aVoid) { + } + }); + newWrapper.write(Type.SHORT, (short) length[0]); + newWrapper.sendToServer(Protocol1_8TO1_7_6_10.class, true, true); } }); } diff --git a/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/chunks/ChunkPacketTransformer.java b/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/chunks/ChunkPacketTransformer.java index 3b2fe76..b5c9d59 100644 --- a/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/chunks/ChunkPacketTransformer.java +++ b/src/main/java/com/github/creeper123123321/viafabric/protocol/protocol1_8to1_7_6_10/chunks/ChunkPacketTransformer.java @@ -26,6 +26,7 @@ package com.github.creeper123123321.viafabric.protocol.protocol1_8to1_7_6_10.chu import io.netty.buffer.ByteBuf; import us.myles.ViaVersion.api.PacketWrapper; +import us.myles.ViaVersion.api.minecraft.BlockChangeRecord; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.types.CustomByteType; @@ -33,6 +34,7 @@ import java.io.IOException; import java.lang.reflect.Field; import java.util.LinkedList; import java.util.List; +import java.util.stream.IntStream; import java.util.zip.DataFormatException; import java.util.zip.Inflater; @@ -182,11 +184,11 @@ public class ChunkPacketTransformer { packetWrapper.write(Type.INT, chunkX); packetWrapper.write(Type.INT, chunkZ); - packetWrapper.write(Type.VAR_INT, size); - - for (int i = 0; i < size; i++) { - packetWrapper.write(Type.SHORT, positions[i]); - packetWrapper.write(Type.VAR_INT, (int) blocks[i]); - } + packetWrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, IntStream.range(0, size) + .mapToObj(it -> new BlockChangeRecord( + (short) (positions[it] >>> 8), + (short) (positions[it] & 0xFFFF), + blocks[it])) + .toArray(BlockChangeRecord[]::new)); } } \ No newline at end of file diff --git a/src/main/resources/assets/viafabric/lang/en_us.json b/src/main/resources/assets/viafabric/lang/en_us.json index 7a73a41..02b1245 100644 --- a/src/main/resources/assets/viafabric/lang/en_us.json +++ b/src/main/resources/assets/viafabric/lang/en_us.json @@ -1,2 +1,6 @@ { + "gui.enable_client_side_button": "Enable ViaVersion", + "gui.enable_client_side.question": "Are you sure you want to enable client-side mode?", + "gui.enable_client_side.warning": "I can not guarantee that this mod is allowed on every (or even any) server. This mod may cause problems with anti-cheat plugins. USE AT OWN RISK.", + "gui.enable_client_side.enable": "Enable" } \ No newline at end of file diff --git a/src/main/resources/assets/viafabric/lang/pt_br.json b/src/main/resources/assets/viafabric/lang/pt_br.json index 7a73a41..9af997a 100644 --- a/src/main/resources/assets/viafabric/lang/pt_br.json +++ b/src/main/resources/assets/viafabric/lang/pt_br.json @@ -1,2 +1,6 @@ { + "gui.enable_client_side_button": "Habilitar ViaVersion", + "gui.enable_client_side.question": "Você tem certeza de que deseja habilitar o modo client-side?", + "gui.enable_client_side.warning": "Não posso garantir que este mod seja permitido em todos os (ou mesmo em quaisquer) servidores. Esse poderá causar problemas com plugins anti-trapaça. USE POR SUA PRÓPRIA CONTA E RISCO.", + "gui.enable_client_side.enable": "Habilitar" } \ No newline at end of file diff --git a/src/main/resources/mixins.viafabric.common.json b/src/main/resources/mixins.viafabric.common.json index e20ca5f..8890986 100644 --- a/src/main/resources/mixins.viafabric.common.json +++ b/src/main/resources/mixins.viafabric.common.json @@ -3,7 +3,8 @@ "compatibilityLevel": "JAVA_8", "package": "com.github.creeper123123321.viafabric.mixin", "mixins": [ - "MixinServerNetworkIOChInit" + "MixinServerNetworkIOChInit", + "MixinClientConnection" ], "injectors": { "defaultRequire": 1