Skip to content

Commit

Permalink
Merge pull request #47 from ocelotpotpie/multi-platform
Browse files Browse the repository at this point in the history
Fabric Implementation.
  • Loading branch information
ocelotpotpie authored Feb 14, 2024
2 parents 8927a7e + 054aade commit 2f5440e
Show file tree
Hide file tree
Showing 21 changed files with 410 additions and 51 deletions.
13 changes: 9 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
with:
fetch-depth: 0
- name: Gradle wrapper validation
uses: gradle/wrapper-validation-action@v1
uses: gradle/wrapper-validation-action@v2
- name: Set up JDK
uses: actions/setup-java@v4
with:
Expand All @@ -20,8 +20,13 @@ jobs:
cache: 'gradle'
- name: Build
run: ./gradlew build
- name: Upload
- name: Upload Paper
uses: actions/upload-artifact@v4
with:
name: FreedomChat
path: "build/libs/FreedomChat-*.jar"
name: FreedomChat Paper
path: "paper/build/libs/FreedomChat-*.jar"
- name: Upload Fabric
uses: actions/upload-artifact@v4
with:
name: FreedomChat Fabric
path: "fabric/build/libs/FreedomChat-*.jar"
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/.gradle
/.idea
/build
/run
**/.gradle
**/build
paper/run
45 changes: 12 additions & 33 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,44 +1,23 @@
plugins {
id("java-library")
id("io.papermc.paperweight.userdev") version "1.5.11"
id("xyz.jpenilla.run-paper") version "2.2.2"
}

group = "ru.bk.oharass.freedomchat"
version = "1.5.2"
description = "Liberate your server from the chat-reporting bourgeoisie! Disable chat reporting with maximum compatibility."
subprojects {
plugins.apply("java-library")

dependencies {
paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT")
}

tasks {
assemble {
dependsOn(reobfJar)
}
group = "ru.bk.oharass.freedomchat"
version = "1.5.2"
description = "Liberate your server from the chat-reporting bourgeoisie! Disable chat signing server-side."

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
tasks {
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
}
}
}

compileJava {
options.encoding = Charsets.UTF_8.name()
}

runServer {
minecraftVersion("1.20.4")
}

processResources {
val props = mapOf(
"version" to project.version,
"description" to project.description
)
inputs.properties(props)
filesMatching("plugin.yml") {
expand(props)
compileJava {
options.encoding = Charsets.UTF_8.name()
}
}
}
40 changes: 40 additions & 0 deletions fabric/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
plugins {
id("dev.architectury.loom") version "1.5-SNAPSHOT"
id("com.github.johnrengelman.shadow") version "8.1.1"
}

val shade: Configuration by configurations.creating

repositories {
maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots/") {
name = "sonatype-oss-snapshots1"
mavenContent { snapshotsOnly() }
}
}

dependencies {
minecraft(group = "com.mojang", name = "minecraft", version = "1.20.4")
mappings(group = "net.fabricmc", name = "yarn", version = "1.20.4+build.3", classifier = "v2")
modImplementation(group = "net.fabricmc", name = "fabric-loader", version = "0.15.3")
modImplementation(group = "net.fabricmc.fabric-api", name = "fabric-api", version = "0.92.0+1.20.4")
modImplementation(include(group = "net.kyori", name = "adventure-platform-fabric", version = "5.11.0"))
shade(implementation(group = "org.spongepowered", name = "configurate-yaml", version = "4.1.2"))
}

tasks {
processResources {
filesMatching("fabric.mod.json") {
expand(
"version" to project.version,
"description" to project.description,
)
}
}
shadowJar {
configurations = listOf(shade)
archiveClassifier.set("dev")
}
remapJar {
inputFile.set(shadowJar.get().archiveFile)
}
}
70 changes: 70 additions & 0 deletions fabric/src/main/java/ru/bk/oharass/freedomchat/FreedomChat.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package ru.bk.oharass.freedomchat;

import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.minecraft.SharedConstants;
import net.minecraft.server.MinecraftServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongepowered.configurate.CommentedConfigurationNode;
import org.spongepowered.configurate.ConfigurateException;
import org.spongepowered.configurate.yaml.NodeStyle;
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;

import java.nio.file.Path;

public class FreedomChat implements ModInitializer {
public static final String MOD_ID = "freedomchat";
private final Logger logger = LoggerFactory.getLogger(MOD_ID);
private MinecraftServer server;
private static FreedomHandler handler;

@Override
public void onInitialize() {
ServerLifecycleEvents.SERVER_STARTED.register(server -> {
this.server = server;
if (!Boolean.getBoolean("im.evan.freedomchat.bypassprotocolcheck") && SharedConstants.getProtocolVersion() != 765) {
logger.warn("This version of FreedomChat only supports protocol version 765 (1.20.4). Please use the appropriate version of FreedomChat for your server");
logger.warn("If you know what you are doing, set the im.evan.freedomchat.bypassprotocolcheck system property to true to bypass this check");
return;
}
final Path configPath = Path.of("config/FreedomChat/config.yml");
final YamlConfigurationLoader loader = YamlConfigurationLoader.builder()
.path(configPath)
.nodeStyle(NodeStyle.BLOCK)
.build();
CommentedConfigurationNode config;
try {
config = loader.load();
final boolean rewriteChat = config.node("rewrite-chat").getBoolean(true);
final boolean claimSecureChatEnforced = config.node("claim-secure-chat-enforced").getBoolean(true);
final boolean sendPreventsChatReportsToClient = config.node("send-prevents-chat-reports-to-client").getBoolean(false);
loader.save(config);

handler = new FreedomHandler(
rewriteChat,
claimSecureChatEnforced,
sendPreventsChatReportsToClient,
this
);
} catch (ConfigurateException e) {
logger.error("An error occurred while loading this configuration: " + e.getMessage());
if (e.getCause() != null) {
e.getCause().printStackTrace();
}
}
});
}

public Logger getLogger() {
return logger;
}

public MinecraftServer getServer() {
return server;
}

public static FreedomHandler getHandler() {
return handler;
}
}
99 changes: 99 additions & 0 deletions fabric/src/main/java/ru/bk/oharass/freedomchat/FreedomHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package ru.bk.oharass.freedomchat;

import com.google.gson.JsonObject;
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.ClientConnection;
import net.minecraft.network.PacketByteBuf;
import net.minecraft.network.message.MessageType;
import net.minecraft.network.packet.Packet;
import net.minecraft.network.packet.s2c.play.ChatMessageS2CPacket;
import net.minecraft.network.packet.s2c.play.GameMessageS2CPacket;
import net.minecraft.network.packet.s2c.play.ServerMetadataS2CPacket;
import net.minecraft.network.packet.s2c.query.QueryResponseS2CPacket;
import net.minecraft.server.ServerMetadata;
import net.minecraft.text.Text;

import java.util.Objects;
import java.util.Optional;

@ChannelHandler.Sharable
public class FreedomHandler extends MessageToByteEncoder<Packet<?>> {

private final boolean rewriteChat;
private final boolean claimSecureChatEnforced;
private final boolean noChatReports;
private final FreedomChat freedom;

public FreedomHandler(boolean rewriteChat, boolean claimSecureChatEnforced, boolean noChatReports, final FreedomChat freedom) {
this.rewriteChat = rewriteChat;
this.claimSecureChatEnforced = claimSecureChatEnforced;
this.noChatReports = noChatReports;
this.freedom = freedom;
}

@Override
public boolean acceptOutboundMessage(Object msg) {
return rewriteChat && msg instanceof ChatMessageS2CPacket
|| noChatReports && msg instanceof QueryResponseS2CPacket
|| claimSecureChatEnforced && msg instanceof ServerMetadataS2CPacket;
}

@Override
protected void encode(ChannelHandlerContext ctx, Packet msg, ByteBuf out) {
final PacketByteBuf fbb = new PacketByteBuf(out);

if (msg instanceof ChatMessageS2CPacket packet) {
encode(ctx, packet, fbb);
} else if (msg instanceof ServerMetadataS2CPacket packet) {
encode(ctx, packet, fbb);
} else if (msg instanceof QueryResponseS2CPacket packet) {
encode(ctx, packet, fbb);
}
}

private void encode(final ChannelHandlerContext ctx, final ChatMessageS2CPacket msg, final PacketByteBuf buf) {
final Text content = Objects.requireNonNullElseGet(msg.unsignedContent(), () -> Text.literal(msg.body().content()));

final Optional<MessageType.Parameters> ctbo = msg.serializedParameters().toParameters(freedom.getServer().getRegistryManager());
if (ctbo.isEmpty()) {
freedom.getLogger().warn("Processing packet with unknown ChatType " + msg.serializedParameters().typeId(), new Throwable());
return;
}
final Text decoratedContent = ctbo.orElseThrow().applyChatDecoration(content);

final GameMessageS2CPacket system = new GameMessageS2CPacket(decoratedContent, false);
writeId(ctx, system, buf);
system.write(buf);
}

private void encode(final ChannelHandlerContext ctx, final ServerMetadataS2CPacket msg, final PacketByteBuf buf) {
writeId(ctx, msg, buf);
buf.writeText(msg.getDescription());
buf.writeOptional(msg.getFavicon(), PacketByteBuf::writeByteArray);
buf.writeBoolean(true);
}

private void encode(final ChannelHandlerContext ctx, final QueryResponseS2CPacket msg, final PacketByteBuf buf) {
final JsonObject status = ServerMetadata.CODEC
.encodeStart(JsonOps.INSTANCE, msg.metadata())
.get()
.left()
.orElseThrow(() -> new EncoderException("Failed to encode ServerStatus"))
.getAsJsonObject();

status.addProperty("preventsChatReports", true);

writeId(ctx, msg, buf);
buf.writeString(GsonComponentSerializer.gson().serializer().toJson(status));
}

private void writeId(final ChannelHandlerContext ctx, final Packet<?> packet, final PacketByteBuf buf) {
buf.writeVarInt(ctx.channel().attr(ClientConnection.CLIENTBOUND_PROTOCOL_KEY).get().getId(packet));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ru.bk.oharass.freedomchat.access;

import io.netty.channel.Channel;

public interface ClientConnectionAccess {
Channel getChannel();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package ru.bk.oharass.freedomchat.access;

public interface ServerCommonNetworkHandlerAccess {
ClientConnectionAccess getConnectionAccess();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ru.bk.oharass.freedomchat.mixins;

import io.netty.channel.Channel;
import net.minecraft.network.ClientConnection;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import ru.bk.oharass.freedomchat.access.ClientConnectionAccess;

@Mixin(ClientConnection.class)
public class ClientConnectionMixin implements ClientConnectionAccess {
@Shadow
private Channel channel;

@Override
public Channel getChannel() {
return channel;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ru.bk.oharass.freedomchat.mixins;

import io.netty.channel.ChannelPipeline;
import net.minecraft.network.ClientConnection;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ConnectedClientData;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import ru.bk.oharass.freedomchat.FreedomChat;
import ru.bk.oharass.freedomchat.access.ServerCommonNetworkHandlerAccess;

@Mixin(PlayerManager.class)
public class PlayerManagerMixin {
@Inject(method = "onPlayerConnect", at = @At(value = "TAIL"))
public void onPlayerConnect(ClientConnection connection, ServerPlayerEntity player, ConnectedClientData clientData, CallbackInfo ci) {
final ChannelPipeline pipeline = ((ServerCommonNetworkHandlerAccess) player.networkHandler).getConnectionAccess().getChannel().pipeline();
pipeline.addAfter("packet_handler", "freedom_handler", FreedomChat.getHandler());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ru.bk.oharass.freedomchat.mixins;

import net.minecraft.network.ClientConnection;
import net.minecraft.server.network.ServerCommonNetworkHandler;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import ru.bk.oharass.freedomchat.access.ClientConnectionAccess;
import ru.bk.oharass.freedomchat.access.ServerCommonNetworkHandlerAccess;

@Mixin(ServerCommonNetworkHandler.class)
public class ServerCommonNetworkHandlerMixin implements ServerCommonNetworkHandlerAccess {
@Final
@Shadow
protected ClientConnection connection;

@Override
public ClientConnectionAccess getConnectionAccess() {
return (ClientConnectionAccess) connection;
}
}
Binary file added fabric/src/main/resources/assets/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 2f5440e

Please sign in to comment.