Merge pull request #570 from D3lta-2-1/fabric
Fabric server side support added
This commit is contained in:
18 files changed
+425
-77
No files matched your search
+1
-5
@@ -3,10 +3,6 @@ plugins {
|
||||
id 'maven-publish'
|
||||
}
|
||||
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
archivesBaseName = project.archives_base_name
|
||||
version = project.mod_version
|
||||
group = project.maven_group
|
||||
|
||||
@@ -40,7 +36,7 @@ dependencies {
|
||||
|
||||
mappings loom.layered() {
|
||||
officialMojangMappings()
|
||||
parchment("org.parchmentmc.data:parchment-${project.minecraft_version}:${project.parchment_mappings}")
|
||||
parchment("org.parchmentmc.data:parchment-${project.parchment_minecraft_version}:${project.parchment_mappings}")
|
||||
}
|
||||
|
||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||
|
||||
+5
-4
@@ -3,9 +3,10 @@ org.gradle.jvmargs=-Xmx1G
|
||||
|
||||
# Fabric Properties
|
||||
# check these on https://fabricmc.net/develop
|
||||
minecraft_version=1.18.1
|
||||
parchment_mappings=2022.01.23
|
||||
loader_version=0.13.1
|
||||
minecraft_version=1.19.4
|
||||
parchment_mappings=2023.03.12
|
||||
parchment_minecraft_version=1.19.3
|
||||
loader_version=0.14.18
|
||||
|
||||
# Mod Properties
|
||||
mod_version = 2.0.0
|
||||
@@ -13,5 +14,5 @@ org.gradle.jvmargs=-Xmx1G
|
||||
archives_base_name = packetevents
|
||||
|
||||
# Dependencies
|
||||
fabric_version=0.46.4+1.18
|
||||
fabric_version=0.77.0+1.19.4
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package io.github.retrooper.packetevents;
|
||||
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
|
||||
public class ChannelUtilities {
|
||||
public static boolean pipelineContainsSplitterAndPrepender(ChannelPipeline pipeline)
|
||||
{
|
||||
boolean containsSplitter = false;
|
||||
boolean containsPrepender = false;
|
||||
for(var handler : pipeline) {
|
||||
PacketEventsMod.LOGGER.info(handler.getClass().getName());
|
||||
if(handler.getKey().equals("splitter")) {
|
||||
containsSplitter = true;
|
||||
}
|
||||
if(handler.getKey().equals("prepender")) {
|
||||
containsPrepender = true;
|
||||
}
|
||||
}
|
||||
return containsSplitter && containsPrepender;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
package io.github.retrooper.packetevents;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsBuilder;
|
||||
import io.github.retrooper.packetevents.factory.fabric.ServerInstanceManager;
|
||||
import io.github.retrooper.packetevents.mixin.ClientPacketListenerAccessor;
|
||||
import io.github.retrooper.packetevents.mixin.ConnectionAccessor;
|
||||
import io.github.retrooper.packetevents.mixin.ServerGamePacketListenerImplAccessor;
|
||||
import net.fabricmc.api.ClientModInitializer;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayConnectionEvents;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
import net.fabricmc.loader.api.entrypoint.PreLaunchEntrypoint;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PacketEventsMod implements PreLaunchEntrypoint, ModInitializer {
|
||||
// This logger is used to write text to the console and the log file.
|
||||
// It is considered best practice to use your mod id as the logger's name.
|
||||
// That way, it's clear which mod wrote info, warnings, and errors.
|
||||
public class PacketEventsMod implements PreLaunchEntrypoint, ModInitializer, ClientModInitializer {
|
||||
//single player world are locked on loading, don't know why
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("packetevents");
|
||||
|
||||
@Override
|
||||
@@ -24,6 +32,31 @@ public class PacketEventsMod implements PreLaunchEntrypoint, ModInitializer {
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
ServerInstanceManager.init();
|
||||
PacketEvents.getAPI().init();
|
||||
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {
|
||||
var connection = ((ServerGamePacketListenerImplAccessor)handler).getConnection();
|
||||
var channel = ((ConnectionAccessor)connection).getChannel();
|
||||
if(ChannelUtilities.pipelineContainsSplitterAndPrepender(channel.pipeline()))
|
||||
PacketEvents.getAPI().getInjector().setPlayer(channel, handler.player);
|
||||
});
|
||||
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketListenerAbstract() {
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
//System.out.println("Packet send: " + event.getPacketType());
|
||||
//System.out.println("player: " + event.getPlayer());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeClient() {
|
||||
ClientPlayConnectionEvents.JOIN.register((handler, sender, client) -> {
|
||||
var connection = ((ClientPacketListenerAccessor)handler).getConnection();
|
||||
var channel = ((ConnectionAccessor)connection).getChannel();
|
||||
if(ChannelUtilities.pipelineContainsSplitterAndPrepender(channel.pipeline()))
|
||||
PacketEvents.getAPI().getInjector().setPlayer(channel, Minecraft.getInstance().player);
|
||||
});
|
||||
}
|
||||
}
|
||||
+31
-34
@@ -2,8 +2,6 @@ package io.github.retrooper.packetevents.factory.fabric;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.event.SimplePacketListenerAbstract;
|
||||
import com.github.retrooper.packetevents.event.simple.PacketPlaySendEvent;
|
||||
import com.github.retrooper.packetevents.injector.ChannelInjector;
|
||||
import com.github.retrooper.packetevents.manager.InternalPacketListener;
|
||||
import com.github.retrooper.packetevents.manager.player.PlayerManager;
|
||||
@@ -11,15 +9,15 @@ import com.github.retrooper.packetevents.manager.protocol.ProtocolManager;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerManager;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.netty.NettyManager;
|
||||
import com.github.retrooper.packetevents.protocol.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.ProtocolVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.settings.PacketEventsSettings;
|
||||
import com.github.retrooper.packetevents.util.LogManager;
|
||||
import com.github.retrooper.packetevents.util.reflection.ReflectionObject;
|
||||
import io.github.retrooper.packetevents.handler.PacketDecoder;
|
||||
import io.github.retrooper.packetevents.handler.PacketEncoder;
|
||||
import io.github.retrooper.packetevents.PacketEventsMod;
|
||||
import io.github.retrooper.packetevents.handler.ServerPacketDecoder;
|
||||
import io.github.retrooper.packetevents.handler.ServerPacketEncoder;
|
||||
import io.github.retrooper.packetevents.impl.netty.NettyManagerImpl;
|
||||
import io.github.retrooper.packetevents.impl.netty.manager.player.PlayerManagerAbstract;
|
||||
import io.github.retrooper.packetevents.impl.netty.manager.protocol.ProtocolManagerAbstract;
|
||||
@@ -27,31 +25,33 @@ import io.github.retrooper.packetevents.impl.netty.manager.server.ServerManagerA
|
||||
import io.netty.channel.Channel;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FabricPacketEventsBuilder {
|
||||
private static final Pattern STRIP_COLOR_PATTERN = Pattern.compile("(?i)" + '\u00A7' + "[0-9A-FK-ORX]");
|
||||
private static PacketEventsAPI<Minecraft> INSTANCE;
|
||||
private static PacketEventsAPI<MinecraftServer> INSTANCE;
|
||||
|
||||
public static void clearBuildCache() {
|
||||
INSTANCE = null;
|
||||
}
|
||||
|
||||
public static PacketEventsAPI<Minecraft> build(String modId) {
|
||||
public static PacketEventsAPI<MinecraftServer> build(String modId) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = buildNoCache(modId);
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static PacketEventsAPI<Minecraft> build(String modId, PacketEventsSettings settings) {
|
||||
public static PacketEventsAPI<MinecraftServer> build(String modId, PacketEventsSettings settings) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = buildNoCache(modId, settings);
|
||||
}
|
||||
@@ -59,11 +59,11 @@ public class FabricPacketEventsBuilder {
|
||||
}
|
||||
|
||||
|
||||
public static PacketEventsAPI<Minecraft> buildNoCache(String modId) {
|
||||
public static PacketEventsAPI<MinecraftServer> buildNoCache(String modId) {
|
||||
return buildNoCache(modId, new PacketEventsSettings());
|
||||
}
|
||||
|
||||
public static PacketEventsAPI<Minecraft> buildNoCache(String modId, PacketEventsSettings inSettings) {
|
||||
public static PacketEventsAPI<MinecraftServer> buildNoCache(String modId, PacketEventsSettings inSettings) {
|
||||
return new PacketEventsAPI<>() {
|
||||
private final PacketEventsSettings settings = inSettings;
|
||||
//TODO Implement platform version
|
||||
@@ -94,11 +94,18 @@ public class FabricPacketEventsBuilder {
|
||||
private final PlayerManagerAbstract playerManager = new PlayerManagerAbstract() {
|
||||
@Override
|
||||
public int getPing(@NotNull Object player) {
|
||||
String name = ((LocalPlayer) player).getGameProfile().getName();
|
||||
UUID id = ((Player) player).getGameProfile().getId();
|
||||
try {
|
||||
return ((LocalPlayer) player).connection.getPlayerInfo(name).getLatency();
|
||||
var minecraft = getPlugin();
|
||||
if(minecraft == null)
|
||||
return ((LocalPlayer) player).connection.getPlayerInfo(id).getLatency();
|
||||
else {
|
||||
var playerManager = minecraft.getPlayerList();
|
||||
var playerEntity = playerManager.getPlayer(id);
|
||||
return playerEntity.latency;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
PacketEvents.getAPI().getLogManager().debug("Failed to get ping for player " + name);
|
||||
PacketEvents.getAPI().getLogManager().debug("Failed to get ping for player " + id);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +120,7 @@ public class FabricPacketEventsBuilder {
|
||||
|
||||
private final ChannelInjector injector = new ChannelInjector() {
|
||||
@Override
|
||||
public boolean isServerBound() {
|
||||
public boolean isServerBound() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -130,20 +137,20 @@ public class FabricPacketEventsBuilder {
|
||||
@Override
|
||||
public void updateUser(Object ch, User user) {
|
||||
Channel channel = (Channel) ch;
|
||||
PacketDecoder decoder = (PacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME);
|
||||
ServerPacketDecoder decoder = (ServerPacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME);
|
||||
decoder.user = user;
|
||||
PacketEncoder encoder = (PacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME);
|
||||
ServerPacketEncoder encoder = (ServerPacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME);
|
||||
encoder.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayer(Object ch, Object player) {
|
||||
Channel channel = (Channel) ch;
|
||||
PacketDecoder decoder = (PacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME);
|
||||
decoder.player = (LocalPlayer) player;
|
||||
ServerPacketDecoder decoder = (ServerPacketDecoder) channel.pipeline().get(PacketEvents.DECODER_NAME);
|
||||
decoder.player = (Player) player;
|
||||
|
||||
PacketEncoder encoder = (PacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME);
|
||||
encoder.player = (LocalPlayer) player;
|
||||
ServerPacketEncoder encoder = (ServerPacketEncoder) channel.pipeline().get(PacketEvents.ENCODER_NAME);
|
||||
encoder.player = (Player) player;
|
||||
}
|
||||
};
|
||||
private final NettyManager nettyManager = new NettyManagerImpl();
|
||||
@@ -152,7 +159,7 @@ public class FabricPacketEventsBuilder {
|
||||
protected void log(Level level, @Nullable NamedTextColor color, String message) {
|
||||
//First we must strip away the color codes that might be in this message
|
||||
message = STRIP_COLOR_PATTERN.matcher(message).replaceAll("");
|
||||
System.out.println(message);
|
||||
PacketEventsMod.LOGGER.info(message);
|
||||
}
|
||||
};
|
||||
private boolean loaded;
|
||||
@@ -176,16 +183,6 @@ public class FabricPacketEventsBuilder {
|
||||
//Register internal packet listener (should be the first listener)
|
||||
//This listener doesn't do any modifications to the packets, just reads data
|
||||
getEventManager().registerListener(new InternalPacketListener());
|
||||
getEventManager().registerListener(new SimplePacketListenerAbstract() {
|
||||
@Override
|
||||
public void onPacketPlaySend(PacketPlaySendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.JOIN_GAME) {
|
||||
System.out.println("Is player null? " + (Minecraft.getInstance().player != null));
|
||||
PacketEvents.getAPI().getInjector().setPlayer(event.getChannel(),
|
||||
Minecraft.getInstance().player);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,8 +227,8 @@ public class FabricPacketEventsBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Minecraft getPlugin() {
|
||||
return Minecraft.getInstance();
|
||||
public MinecraftServer getPlugin() {
|
||||
return ServerInstanceManager.getServerInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package io.github.retrooper.packetevents.factory.fabric;
|
||||
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public class ServerInstanceManager {
|
||||
private static MinecraftServer serverInstance;
|
||||
|
||||
public static void init() {
|
||||
ServerLifecycleEvents.SERVER_STARTED.register(server -> serverInstance = server);
|
||||
ServerLifecycleEvents.SERVER_STOPPED.register(server -> serverInstance = null);
|
||||
}
|
||||
public static MinecraftServer getServerInstance() {
|
||||
return serverInstance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package io.github.retrooper.packetevents.handler;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import java.util.List;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ClientPacketDecoder extends ServerPacketDecoder {
|
||||
public ClientPacketDecoder(User user) {
|
||||
super(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
|
||||
if (msg.isReadable()) {
|
||||
ByteBuf outputBuffer = ctx.alloc().buffer().writeBytes(msg);
|
||||
boolean recompress = handleCompression(ctx, outputBuffer);
|
||||
PacketEventsImplHelper.handleClientBoundPacket(ctx.channel(), user, player, outputBuffer, false);
|
||||
//TODO hasTasksAfter
|
||||
if (outputBuffer.isReadable()) {
|
||||
if (recompress) {
|
||||
recompress(ctx, outputBuffer);
|
||||
}
|
||||
out.add(outputBuffer.retain());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package io.github.retrooper.packetevents.handler;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ClientPacketEncoder extends ServerPacketEncoder {
|
||||
public ClientPacketEncoder(User user) {
|
||||
super(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
|
||||
if (msg.isReadable()) {
|
||||
PacketEventsImplHelper.handleServerBoundPacket(ctx.channel(), user, player, msg, false);
|
||||
out.writeBytes(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
@@ -18,7 +19,7 @@ import java.util.List;
|
||||
public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
private static Method DECOMPRESSOR_METHOD, COMPRESSOR_METHOD;
|
||||
public User user;
|
||||
public LocalPlayer player;
|
||||
public Player player;
|
||||
public boolean checkedCompression;
|
||||
|
||||
public PacketDecoder(User user) {
|
||||
@@ -30,6 +31,7 @@ public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
if (msg.isReadable()) {
|
||||
ByteBuf outputBuffer = ctx.alloc().buffer().writeBytes(msg);
|
||||
boolean recompress = handleCompression(ctx, outputBuffer);
|
||||
|
||||
PacketEventsImplHelper.handleClientBoundPacket(ctx.channel(), user, player, outputBuffer, false);
|
||||
//TODO hasTasksAfter
|
||||
if (outputBuffer.isReadable()) {
|
||||
@@ -42,12 +44,12 @@ public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
|
||||
private boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) {
|
||||
protected boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) {
|
||||
if (checkedCompression) return false;
|
||||
if (ctx.pipeline().names().indexOf("decompress") > ctx.pipeline().names().indexOf(PacketEvents.DECODER_NAME)) {
|
||||
// Need to decompress this packet due to bad order
|
||||
@@ -81,7 +83,7 @@ public class PacketDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void recompress(ChannelHandlerContext ctx, ByteBuf buffer) {
|
||||
protected void recompress(ChannelHandlerContext ctx, ByteBuf buffer) {
|
||||
ByteBuf compressed = ctx.alloc().buffer();
|
||||
try {
|
||||
ChannelHandler compressor = ctx.pipeline().get("compress");
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package io.github.retrooper.packetevents.handler;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.EventCreationUtil;
|
||||
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
@@ -13,19 +9,19 @@ import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class PacketEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
public User user;
|
||||
public LocalPlayer player;
|
||||
public Player player;
|
||||
|
||||
public PacketEncoder(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
|
||||
ByteBuf buf = null;
|
||||
try {
|
||||
if (acceptOutboundMessage(msg)) {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package io.github.retrooper.packetevents.handler;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ServerPacketDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||
private static Method DECOMPRESSOR_METHOD, COMPRESSOR_METHOD;
|
||||
public User user;
|
||||
public Player player;
|
||||
public boolean checkedCompression;
|
||||
|
||||
public ServerPacketDecoder(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {
|
||||
if (msg.isReadable()) {
|
||||
ByteBuf outputBuffer = ctx.alloc().buffer().writeBytes(msg);
|
||||
boolean recompress = handleCompression(ctx, outputBuffer);
|
||||
|
||||
PacketEventsImplHelper.handleServerBoundPacket(ctx.channel(), user, player, outputBuffer, false);
|
||||
//TODO hasTasksAfter
|
||||
if (outputBuffer.isReadable()) {
|
||||
if (recompress) {
|
||||
recompress(ctx, outputBuffer);
|
||||
}
|
||||
out.add(outputBuffer.retain());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
|
||||
super.channelInactive(ctx);
|
||||
}
|
||||
|
||||
|
||||
protected boolean handleCompression(ChannelHandlerContext ctx, ByteBuf buffer) {
|
||||
if (checkedCompression) return false;
|
||||
if (ctx.pipeline().names().indexOf("decompress") > ctx.pipeline().names().indexOf(PacketEvents.DECODER_NAME)) {
|
||||
// Need to decompress this packet due to bad order
|
||||
ChannelHandler decompressor = ctx.pipeline().get("decompress");
|
||||
//CompressionDecoder
|
||||
try {
|
||||
if (DECOMPRESSOR_METHOD == null) {
|
||||
DECOMPRESSOR_METHOD = decompressor.getClass().getDeclaredMethod("decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
|
||||
}
|
||||
List<?> list = new ArrayList<>(1);
|
||||
DECOMPRESSOR_METHOD.invoke(decompressor, ctx, buffer, list);
|
||||
ByteBuf decompressed = (ByteBuf) list.get(0);
|
||||
if (buffer != decompressed) {
|
||||
try {
|
||||
buffer.clear().writeBytes(decompressed);
|
||||
} finally {
|
||||
decompressed.release();
|
||||
}
|
||||
}
|
||||
//Relocate handlers
|
||||
ServerPacketDecoder decoder = (ServerPacketDecoder) ctx.pipeline().remove(PacketEvents.DECODER_NAME);
|
||||
ctx.pipeline().addAfter("decompress", PacketEvents.DECODER_NAME, decoder);
|
||||
ServerPacketEncoder encoder = (ServerPacketEncoder) ctx.pipeline().remove(PacketEvents.ENCODER_NAME);
|
||||
ctx.pipeline().addAfter("compress", PacketEvents.ENCODER_NAME, encoder);
|
||||
checkedCompression = true;
|
||||
return true;
|
||||
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected void recompress(ChannelHandlerContext ctx, ByteBuf buffer) {
|
||||
ByteBuf compressed = ctx.alloc().buffer();
|
||||
try {
|
||||
ChannelHandler compressor = ctx.pipeline().get("compress");
|
||||
if (COMPRESSOR_METHOD == null) {
|
||||
COMPRESSOR_METHOD = compressor.getClass().getDeclaredMethod("encode", ChannelHandlerContext.class, ByteBuf.class, ByteBuf.class);
|
||||
}
|
||||
COMPRESSOR_METHOD.invoke(compressor, ctx, buffer, compressed);
|
||||
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
try {
|
||||
buffer.clear().writeBytes(compressed);
|
||||
PacketEvents.getAPI().getLogManager().debug("Recompressed packet!");
|
||||
} finally {
|
||||
compressed.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package io.github.retrooper.packetevents.handler;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.handler.codec.EncoderException;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public class ServerPacketEncoder extends MessageToByteEncoder<ByteBuf> {
|
||||
public User user;
|
||||
public Player player;
|
||||
|
||||
public ServerPacketEncoder(User user) {
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
|
||||
ByteBuf buf = null;
|
||||
try {
|
||||
if (acceptOutboundMessage(msg)) {
|
||||
ByteBuf in = (ByteBuf) msg;
|
||||
buf = allocateBuffer(ctx, in, true);
|
||||
try {
|
||||
encode(ctx, in, buf);
|
||||
} finally {
|
||||
ReferenceCountUtil.release(in);
|
||||
}
|
||||
if (buf.isReadable()) {
|
||||
ctx.write(buf, promise);
|
||||
} else {
|
||||
buf.release();
|
||||
//We cancelled this packet, do not pass it on to the next handler.
|
||||
//ctx.write(Unpooled.EMPTY_BUFFER, promise);
|
||||
}
|
||||
buf = null;
|
||||
} else {
|
||||
ctx.write(msg, promise);
|
||||
}
|
||||
} catch (EncoderException e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
throw new EncoderException(e);
|
||||
} finally {
|
||||
if (buf != null) {
|
||||
buf.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
|
||||
if (msg.isReadable()) {
|
||||
PacketEventsImplHelper.handleClientBoundPacket(ctx.channel(), user, player, msg, false);
|
||||
out.writeBytes(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.github.retrooper.packetevents.mixin;
|
||||
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.network.Connection;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(ClientPacketListener.class)
|
||||
public interface ClientPacketListenerAccessor {
|
||||
@Accessor
|
||||
Connection getConnection();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package io.github.retrooper.packetevents.mixin;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(net.minecraft.network.Connection.class)
|
||||
public interface ConnectionAccessor {
|
||||
@Accessor
|
||||
Channel getChannel();
|
||||
}
|
||||
+35
-11
@@ -7,14 +7,18 @@ import com.github.retrooper.packetevents.protocol.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.protocol.player.UserProfile;
|
||||
import io.github.retrooper.packetevents.ChannelUtilities;
|
||||
import io.github.retrooper.packetevents.PacketEventsMod;
|
||||
import io.github.retrooper.packetevents.handler.PacketDecoder;
|
||||
import io.github.retrooper.packetevents.handler.PacketEncoder;
|
||||
import io.github.retrooper.packetevents.handler.ServerPacketDecoder;
|
||||
import io.github.retrooper.packetevents.handler.ServerPacketEncoder;
|
||||
import io.github.retrooper.packetevents.handler.ClientPacketDecoder;
|
||||
import io.github.retrooper.packetevents.handler.ClientPacketEncoder;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.protocol.PacketFlow;
|
||||
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;
|
||||
@@ -22,22 +26,42 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(net.minecraft.network.Connection.class)
|
||||
public class PacketEventsInjectorMixin {
|
||||
|
||||
@Shadow @Final
|
||||
private PacketFlow receiving;
|
||||
|
||||
@Inject(method = "channelActive", at = @At("HEAD"))
|
||||
private void channelActive(ChannelHandlerContext ctx, CallbackInfo info) throws Exception {
|
||||
PacketEventsMod.LOGGER.info("Connected!");
|
||||
private void channelActive(ChannelHandlerContext ctx, CallbackInfo info) {
|
||||
|
||||
Channel channel = ctx.channel();
|
||||
User user = new User(channel, ConnectionState.HANDSHAKING, ClientVersion.getLatest(),
|
||||
new UserProfile(null, null));
|
||||
ProtocolManager.USERS.put(channel, user);
|
||||
PacketDecoder decoder = new PacketDecoder(user);
|
||||
PacketEncoder encoder = new PacketEncoder(user);
|
||||
channel.pipeline().addAfter("splitter", PacketEvents.DECODER_NAME, decoder);
|
||||
channel.pipeline().addAfter("prepender", PacketEvents.ENCODER_NAME, encoder);
|
||||
ServerPacketDecoder decoder;
|
||||
ServerPacketEncoder encoder;
|
||||
if(receiving == PacketFlow.CLIENTBOUND) {
|
||||
PacketEventsMod.LOGGER.info("Connected as Client!");
|
||||
decoder = new ClientPacketDecoder(user);
|
||||
encoder = new ClientPacketEncoder(user);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
PacketEventsMod.LOGGER.info("Connected as Server!");
|
||||
decoder = new ServerPacketDecoder(user);
|
||||
encoder = new ServerPacketEncoder(user);
|
||||
}
|
||||
|
||||
if(ChannelUtilities.pipelineContainsSplitterAndPrepender(channel.pipeline()))
|
||||
{
|
||||
channel.pipeline().addAfter("splitter", PacketEvents.DECODER_NAME, decoder);
|
||||
channel.pipeline().addAfter("prepender", PacketEvents.ENCODER_NAME, encoder);
|
||||
}
|
||||
PacketEventsMod.LOGGER.info("Pipeline: " + ChannelHelper.pipelineHandlerNamesAsString(channel));
|
||||
}
|
||||
|
||||
@Inject(method = "channelInactive", at = @At("HEAD"))
|
||||
private void channelInactive(ChannelHandlerContext ctx, CallbackInfo info) {
|
||||
PacketEventsMod.LOGGER.info("Disconnected!");
|
||||
PacketEventsMod.LOGGER.debug("Disconnected!");
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
package io.github.retrooper.packetevents.mixin;
|
||||
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import net.minecraft.network.Connection;
|
||||
|
||||
@Mixin(ServerGamePacketListenerImpl.class)
|
||||
public interface ServerGamePacketListenerImplAccessor {
|
||||
@Accessor
|
||||
Connection getConnection();
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"version": "${version}",
|
||||
|
||||
"name": "PacketEvents Fabric",
|
||||
"description": "This is an example description! Tell everyone what your mod is about!",
|
||||
"description": "fabric implementation of packetevents",
|
||||
"authors": [
|
||||
"Me!"
|
||||
],
|
||||
@@ -23,6 +23,9 @@
|
||||
],
|
||||
"main": [
|
||||
"io.github.retrooper.packetevents.PacketEventsMod"
|
||||
],
|
||||
"client": [
|
||||
"io.github.retrooper.packetevents.PacketEventsMod"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
@@ -30,9 +33,9 @@
|
||||
],
|
||||
|
||||
"depends": {
|
||||
"fabricloader": ">=0.12.12",
|
||||
"fabricloader": ">=0.14.18",
|
||||
"fabric": "*",
|
||||
"minecraft": "1.18.x",
|
||||
"minecraft": "1.19.x",
|
||||
"java": ">=17"
|
||||
},
|
||||
"suggests": {
|
||||
|
||||
@@ -4,11 +4,14 @@
|
||||
"package": "io.github.retrooper.packetevents.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"mixins": [
|
||||
],
|
||||
"client": [
|
||||
"PacketEventsInjectorMixin"
|
||||
"ConnectionAccessor",
|
||||
"PacketEventsInjectorMixin",
|
||||
"ServerGamePacketListenerImplAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
},
|
||||
"client": [
|
||||
"ClientPacketListenerAccessor"
|
||||
]
|
||||
}
|
||||
Reference in new issue
Block a user