From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: AlphaKR93 Date: Mon, 29 Apr 2024 14:49:37 +0900 Subject: [PATCH] Implement FreedomChat ocelotpotpie/FreedomChat Copyright (C) 2022-2024 ocelotpotpie, Licensed under GNU GPL v3.0 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 . diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java index 2707a96f9e22469d008ec7d2fa8a8c497efaf8cf..9eedd395b3eac5e2511c8267781938a3fd994d90 100644 --- a/src/main/java/net/minecraft/server/players/PlayerList.java +++ b/src/main/java/net/minecraft/server/players/PlayerList.java @@ -135,6 +135,7 @@ public abstract class PlayerList { private static final Logger LOGGER = LogUtils.getLogger(); private static final int SEND_PLAYER_INFO_INTERVAL = 600; private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z"); + private static final ru.bk.oharass.freedomchat.FreedomChat FREEDOM_HANDLER = new ru.bk.oharass.freedomchat.FreedomChat(); // Plazma - Implement FreedomChat private final MinecraftServer server; public final List players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety private final Map playersByUUID = Maps.newHashMap(); @@ -285,6 +286,7 @@ public abstract class PlayerList { // CraftBukkit - Moved message to after join // PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", new Object[]{entityplayer.getName().getString(), s1, entityplayer.getId(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ()}); LevelData worlddata = worldserver1.getLevelData(); + connection.channel.pipeline().addAfter("packet_handler", "freedom_handler", FREEDOM_HANDLER); // Plazma - Implement FreedomChat player.loadGameTypes((CompoundTag) optional.orElse(null)); // CraftBukkit - decompile error ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, clientData); diff --git a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java index 4f3ed01e12ccb8a6f1a5c4f605451bb36370a236..98f26e3de66a881163e84295e9156c7f362bf7cb 100644 --- a/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java +++ b/src/main/java/org/plazmamc/plazma/configurations/GlobalConfiguration.java @@ -29,6 +29,16 @@ public class GlobalConfiguration extends ConfigurationPart { public boolean checkSpectatorMovedToQuickly = !OPTIMIZE; + public FreedomChat freedomChat; + public class FreedomChat extends ConfigurationPart { + + public boolean enabled = false; + public boolean rewriteChat = true; + public boolean claimSecureChatEnforced = true; + public boolean noChatReports = true; + + } + } @Setting("world-generation") diff --git a/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java b/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java new file mode 100644 index 0000000000000000000000000000000000000000..67f21c23e80881f52e7b92f22c6cbbe3a0bd55b5 --- /dev/null +++ b/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java @@ -0,0 +1,96 @@ +package ru.bk.oharass.freedomchat; + +import com.google.gson.JsonObject; +import com.mojang.logging.LogUtils; +import com.mojang.serialization.JsonOps; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.EncoderException; +import io.netty.handler.codec.MessageToByteEncoder; +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; +import net.minecraft.network.Connection; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.ChatType; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.Packet; +import net.minecraft.network.protocol.game.ClientboundPlayerChatPacket; +import net.minecraft.network.protocol.game.ClientboundServerDataPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket; +import net.minecraft.network.protocol.status.ServerStatus; +import org.slf4j.Logger; + +import java.util.Optional; + +import static org.plazmamc.plazma.configurations.GlobalConfiguration.get; +import static net.minecraft.server.MinecraftServer.getServer; + +@ChannelHandler.Sharable +public class FreedomChat extends MessageToByteEncoder> { + + private static final Logger LOGGER = LogUtils.getLogger(); + + @Override + public boolean acceptOutboundMessage(final Object msg) { + return get().player.freedomChat.rewriteChat && msg instanceof ClientboundPlayerChatPacket + || get().player.freedomChat.claimSecureChatEnforced && msg instanceof ClientboundServerDataPacket + || get().player.freedomChat.noChatReports && msg instanceof ClientboundStatusResponsePacket; + } + + @Override + protected void encode(final ChannelHandlerContext context, final Packet packet, final ByteBuf byteBuf) throws Exception { + final FriendlyByteBuf buf = new FriendlyByteBuf(byteBuf); + + // TODO: JDK 21 - Change to pattern matching + if (packet instanceof ClientboundPlayerChatPacket chat) + encodeChat(context, chat, buf); + else if (packet instanceof ClientboundServerDataPacket data) + encodeData(context, data, buf); + else if (packet instanceof ClientboundStatusResponsePacket query) + encodeQuery(context, query, buf); + } + + private static void encodeChat( + final ChannelHandlerContext context, final ClientboundPlayerChatPacket packet, final FriendlyByteBuf byteBuf + ) { + final Optional bound = packet.chatType().resolve(getServer().registryAccess()); + if (bound.isEmpty()) { + LOGGER.warn("Failed to resolve chat type: {}", packet.chatType().chatType(), new Throwable()); + return; + } + + final ClientboundSystemChatPacket after = new ClientboundSystemChatPacket( bound.orElseThrow().decorate( + Optional.ofNullable( packet.unsignedContent() ).orElse( Component.literal(packet.body().content()) ) + ), false ); + write(context, after, byteBuf); + after.write(byteBuf); + } + + private static void encodeData( + final ChannelHandlerContext context, final ClientboundServerDataPacket packet, final FriendlyByteBuf byteBuf + ) { + write(context, packet, byteBuf); + byteBuf.writeComponent(packet.getMotd()); + byteBuf.writeOptional(packet.getIconBytes(), FriendlyByteBuf::writeByteArray); + byteBuf.writeBoolean(true); + } + + private static void encodeQuery( + final ChannelHandlerContext context, final ClientboundStatusResponsePacket packet, final FriendlyByteBuf byteBuf + ) { + final JsonObject status = ServerStatus.CODEC.encodeStart(JsonOps.INSTANCE, packet.status()).get().left() + .orElseThrow(() -> new EncoderException("Failed to encode server status query response")).getAsJsonObject(); + + status.addProperty("preventsChatReports", true); + write(context, packet, byteBuf); + byteBuf.writeUtf(GsonComponentSerializer.gson().serializer().toJson(status)); + } + + private static void write( + final ChannelHandlerContext context, final Packet packet, final FriendlyByteBuf byteBuf + ) { + byteBuf.writeVarInt(context.channel().attr(Connection.ATTRIBUTE_CLIENTBOUND_PROTOCOL).get().packetId(packet)); + } + +}