feat: initial implementation of patchless packet handling
currently only supports "play packets", thus not including login and handshake
This commit is contained in:
parent
5a86e4e2be
commit
94391df724
13 changed files with 94 additions and 126 deletions
|
@ -66,7 +66,7 @@ dependencies {
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava { //mappings for lillero-processor
|
compileJava { //mappings for lillero-processor
|
||||||
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/output.tsrg'
|
options.compilerArgs << '-AmappingsFile=https://data.fantabos.co/1.16.5.tsrg'
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import ftbsc.bscv.api.IModule;
|
||||||
import ftbsc.bscv.patches.CommandsPatch.CommandsBuiltEvent;
|
import ftbsc.bscv.patches.CommandsPatch.CommandsBuiltEvent;
|
||||||
import ftbsc.bscv.system.Friends;
|
import ftbsc.bscv.system.Friends;
|
||||||
import ftbsc.bscv.system.ModManager;
|
import ftbsc.bscv.system.ModManager;
|
||||||
|
import ftbsc.bscv.system.PacketHandler;
|
||||||
import net.minecraft.client.gui.screen.IngameMenuScreen;
|
import net.minecraft.client.gui.screen.IngameMenuScreen;
|
||||||
import net.minecraft.client.gui.widget.button.Button;
|
import net.minecraft.client.gui.widget.button.Button;
|
||||||
import net.minecraft.command.CommandSource;
|
import net.minecraft.command.CommandSource;
|
||||||
|
@ -27,9 +28,9 @@ import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
|
||||||
@Mod("bscv")
|
@Mod(Boscovicino.MOD_ID)
|
||||||
public class Boscovicino implements ICommons {
|
public class Boscovicino implements ICommons {
|
||||||
public static String MOD_ID = "bscv";
|
public static final String MOD_ID = "bscv";
|
||||||
|
|
||||||
public static final Logger LOGGER = LogManager.getLogger();
|
public static final Logger LOGGER = LogManager.getLogger();
|
||||||
|
|
||||||
|
@ -40,7 +41,12 @@ public class Boscovicino implements ICommons {
|
||||||
public static ForgeConfigSpec spec;
|
public static ForgeConfigSpec spec;
|
||||||
|
|
||||||
private static Friends friends;
|
private static Friends friends;
|
||||||
public static Friends friends() { return Boscovicino.friends; }
|
|
||||||
|
private static PacketHandler packetHandler;
|
||||||
|
|
||||||
|
public static Friends friends() {
|
||||||
|
return Boscovicino.friends;
|
||||||
|
}
|
||||||
|
|
||||||
public Boscovicino() {
|
public Boscovicino() {
|
||||||
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetupComplete);
|
FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetupComplete);
|
||||||
|
@ -48,13 +54,16 @@ public class Boscovicino implements ICommons {
|
||||||
ForgeConfigSpec.Builder cfg = new ForgeConfigSpec.Builder();
|
ForgeConfigSpec.Builder cfg = new ForgeConfigSpec.Builder();
|
||||||
CommandDispatcher<CommandSource> dp = this.dispatcher;
|
CommandDispatcher<CommandSource> dp = this.dispatcher;
|
||||||
|
|
||||||
|
// load mods
|
||||||
Boscovicino.modManager = new ModManager(cfg, dp);
|
Boscovicino.modManager = new ModManager(cfg, dp);
|
||||||
Boscovicino.modManager.load();
|
Boscovicino.modManager.load();
|
||||||
|
|
||||||
Boscovicino.modManager.finish();
|
Boscovicino.modManager.finish();
|
||||||
|
|
||||||
Boscovicino.spec = cfg.build();
|
Boscovicino.spec = cfg.build();
|
||||||
|
|
||||||
|
// initialise packet handler
|
||||||
|
Boscovicino.packetHandler = new PacketHandler();
|
||||||
|
|
||||||
|
// initialise friend manager
|
||||||
ForgeConfigSpec.Builder friendSpec = new ForgeConfigSpec.Builder();
|
ForgeConfigSpec.Builder friendSpec = new ForgeConfigSpec.Builder();
|
||||||
Boscovicino.friends = new Friends(friendSpec, dp);
|
Boscovicino.friends = new Friends(friendSpec, dp);
|
||||||
|
|
||||||
|
@ -62,7 +71,7 @@ public class Boscovicino implements ICommons {
|
||||||
ModLoadingContext.get().registerConfig(Type.CLIENT, spec, "bscv.toml");
|
ModLoadingContext.get().registerConfig(Type.CLIENT, spec, "bscv.toml");
|
||||||
ModLoadingContext.get().registerConfig(Type.CLIENT, friendSpec.build(), "friends.toml");
|
ModLoadingContext.get().registerConfig(Type.CLIENT, friendSpec.build(), "friends.toml");
|
||||||
|
|
||||||
// Register ourselves for server and other game events we are interested in
|
// register ourselves on the event bus
|
||||||
MinecraftForge.EVENT_BUS.register(this);
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +88,6 @@ public class Boscovicino implements ICommons {
|
||||||
|
|
||||||
private void onSetupComplete(final FMLLoadCompleteEvent event) {
|
private void onSetupComplete(final FMLLoadCompleteEvent event) {
|
||||||
LOGGER.info("Initializing modules");
|
LOGGER.info("Initializing modules");
|
||||||
|
|
||||||
for (IModule m : modManager.mods) {
|
for (IModule m : modManager.mods) {
|
||||||
if (m.isEnabled()) {
|
if (m.isEnabled()) {
|
||||||
m.enable(); // re-run enable() to register on the event bus and run enabled callbacks
|
m.enable(); // re-run enable() to register on the event bus and run enabled callbacks
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ftbsc.bscv.modules.hud;
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.HudModule;
|
import ftbsc.bscv.modules.HudModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.client.network.play.NetworkPlayerInfo;
|
import net.minecraft.client.network.play.NetworkPlayerInfo;
|
||||||
import net.minecraft.network.play.server.SUpdateTimePacket;
|
import net.minecraft.network.play.server.SUpdateTimePacket;
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
package ftbsc.bscv.modules.motion;
|
package ftbsc.bscv.modules.motion;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
import ftbsc.bscv.ICommons;
|
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.QuickModule;
|
import ftbsc.bscv.modules.QuickModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.client.entity.player.ClientPlayerEntity;
|
|
||||||
import net.minecraft.network.play.client.CPlayerPacket;
|
import net.minecraft.network.play.client.CPlayerPacket;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
import net.minecraftforge.common.ForgeConfigSpec;
|
import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
|
|
|
@ -24,7 +24,7 @@ import com.google.gson.JsonPrimitive;
|
||||||
import ftbsc.bscv.Boscovicino;
|
import ftbsc.bscv.Boscovicino;
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.QuickModule;
|
import ftbsc.bscv.modules.QuickModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import net.minecraft.network.IPacket;
|
import net.minecraft.network.IPacket;
|
||||||
import net.minecraft.util.math.vector.Vector2f;
|
import net.minecraft.util.math.vector.Vector2f;
|
||||||
import net.minecraft.util.math.vector.Vector3d;
|
import net.minecraft.util.math.vector.Vector3d;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.google.auto.service.AutoService;
|
||||||
import ftbsc.bscv.ICommons;
|
import ftbsc.bscv.ICommons;
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.AbstractModule;
|
import ftbsc.bscv.modules.AbstractModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.network.play.client.CEntityActionPacket;
|
import net.minecraft.network.play.client.CEntityActionPacket;
|
||||||
import net.minecraft.network.play.client.CEntityActionPacket.Action;
|
import net.minecraft.network.play.client.CEntityActionPacket.Action;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.google.auto.service.AutoService;
|
||||||
import ftbsc.bscv.ICommons;
|
import ftbsc.bscv.ICommons;
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.AbstractModule;
|
import ftbsc.bscv.modules.AbstractModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.network.play.server.SDisconnectPacket;
|
import net.minecraft.network.play.server.SDisconnectPacket;
|
||||||
import net.minecraft.network.play.server.SUpdateHealthPacket;
|
import net.minecraft.network.play.server.SUpdateHealthPacket;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import com.google.auto.service.AutoService;
|
||||||
import ftbsc.bscv.ICommons;
|
import ftbsc.bscv.ICommons;
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.AbstractModule;
|
import ftbsc.bscv.modules.AbstractModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.network.play.server.SPlaySoundEffectPacket;
|
import net.minecraft.network.play.server.SPlaySoundEffectPacket;
|
||||||
|
|
|
@ -5,7 +5,7 @@ import ftbsc.bscv.Boscovicino;
|
||||||
import ftbsc.bscv.ICommons;
|
import ftbsc.bscv.ICommons;
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.QuickModule;
|
import ftbsc.bscv.modules.QuickModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Keyboard;
|
import ftbsc.bscv.tools.Keyboard;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.client.entity.player.RemoteClientPlayerEntity;
|
import net.minecraft.client.entity.player.RemoteClientPlayerEntity;
|
||||||
|
|
|
@ -7,7 +7,7 @@ import ftbsc.bscv.modules.AbstractModule;
|
||||||
import ftbsc.bscv.patches.BlockPushPatch.PlayerBlockPushEvent;
|
import ftbsc.bscv.patches.BlockPushPatch.PlayerBlockPushEvent;
|
||||||
import ftbsc.bscv.patches.EntityPushPatch.PlayerEntityPushEvent;
|
import ftbsc.bscv.patches.EntityPushPatch.PlayerEntityPushEvent;
|
||||||
import ftbsc.bscv.patches.LiquidPushPatch.PlayerLiquidPushEvent;
|
import ftbsc.bscv.patches.LiquidPushPatch.PlayerLiquidPushEvent;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.network.play.server.SEntityVelocityPacket;
|
import net.minecraft.network.play.server.SEntityVelocityPacket;
|
||||||
import net.minecraft.network.play.server.SExplosionPacket;
|
import net.minecraft.network.play.server.SExplosionPacket;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
|
|
||||||
import ftbsc.bscv.api.ILoadable;
|
import ftbsc.bscv.api.ILoadable;
|
||||||
import ftbsc.bscv.modules.QuickModule;
|
import ftbsc.bscv.modules.QuickModule;
|
||||||
import ftbsc.bscv.patches.PacketPatch.PacketEvent;
|
import ftbsc.bscv.system.PacketHandler.PacketEvent;
|
||||||
import ftbsc.bscv.tools.Setting;
|
import ftbsc.bscv.tools.Setting;
|
||||||
import net.minecraft.client.renderer.BufferBuilder;
|
import net.minecraft.client.renderer.BufferBuilder;
|
||||||
import net.minecraft.client.renderer.Tessellator;
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
package ftbsc.bscv.patches;
|
|
||||||
|
|
||||||
import ftbsc.lll.processor.annotations.Find;
|
|
||||||
import ftbsc.lll.processor.annotations.Injector;
|
|
||||||
import ftbsc.lll.processor.annotations.Patch;
|
|
||||||
import ftbsc.lll.processor.annotations.Target;
|
|
||||||
import ftbsc.lll.proxies.MethodProxy;
|
|
||||||
import ftbsc.lll.tools.InsnSequence;
|
|
||||||
import ftbsc.lll.tools.PatternMatcher;
|
|
||||||
import ftbsc.lll.tools.debug.BytecodePrinter;
|
|
||||||
import ftbsc.lll.tools.nodes.MethodProxyInsnNode;
|
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
|
||||||
import io.netty.util.concurrent.Future;
|
|
||||||
import io.netty.util.concurrent.GenericFutureListener;
|
|
||||||
import net.minecraft.network.IPacket;
|
|
||||||
import net.minecraft.network.NetworkManager;
|
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
|
||||||
import net.minecraftforge.eventbus.api.Cancelable;
|
|
||||||
import net.minecraftforge.eventbus.api.Event;
|
|
||||||
|
|
||||||
import org.objectweb.asm.Opcodes;
|
|
||||||
import org.objectweb.asm.tree.*;
|
|
||||||
|
|
||||||
public class PacketPatch {
|
|
||||||
|
|
||||||
public static class PacketEvent {
|
|
||||||
@Cancelable
|
|
||||||
public static class Outgoing extends Event {
|
|
||||||
public final IPacket<?> packet;
|
|
||||||
|
|
||||||
public Outgoing(IPacket<?> packet) {
|
|
||||||
this.packet = packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Cancelable
|
|
||||||
public static class Incoming extends Event {
|
|
||||||
public final IPacket<?> packet;
|
|
||||||
|
|
||||||
public Incoming(IPacket<?> packet) {
|
|
||||||
this.packet = packet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean pktIn(IPacket<?> pkt) {
|
|
||||||
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Incoming(pkt));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean pktOut(IPacket<?> pkt) {
|
|
||||||
return MinecraftForge.EVENT_BUS.post(new PacketEvent.Outgoing(pkt));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Patch(value = NetworkManager.class, reason = "add hook to intercept and alter/cancel incoming packets")
|
|
||||||
public abstract static class IncomingPacketInterceptor implements Opcodes {
|
|
||||||
@Find(parent = PacketPatch.class)
|
|
||||||
abstract MethodProxy pktIn();
|
|
||||||
|
|
||||||
@Target
|
|
||||||
public abstract void channelRead0(ChannelHandlerContext ctx, IPacket<?> pak);
|
|
||||||
|
|
||||||
@Injector
|
|
||||||
public void inject(ClassNode clazz, MethodNode main) {
|
|
||||||
AbstractInsnNode found = PatternMatcher.builder()
|
|
||||||
.opcodes(ALOAD, GETFIELD, INVOKEINTERFACE, IFEQ)
|
|
||||||
.ignoreFrames()
|
|
||||||
.ignoreLabels()
|
|
||||||
.ignoreLineNumbers()
|
|
||||||
.build()
|
|
||||||
.find(main)
|
|
||||||
.getLast();
|
|
||||||
|
|
||||||
LabelNode skip = new LabelNode();
|
|
||||||
InsnSequence is = new InsnSequence();
|
|
||||||
is.add(new VarInsnNode(ALOAD, 2));
|
|
||||||
is.add(new MethodProxyInsnNode(INVOKESTATIC, pktIn()));
|
|
||||||
is.add(new JumpInsnNode(IFEQ, skip));
|
|
||||||
is.add(new InsnNode(RETURN));
|
|
||||||
is.add(skip);
|
|
||||||
|
|
||||||
main.instructions.insert(found, is);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Patch(value = NetworkManager.class, reason = "add hook to intercept and alter/cancel outgoing packets")
|
|
||||||
public abstract static class OutgoingPacketInterceptor implements Opcodes {
|
|
||||||
@Find(parent = PacketPatch.class)
|
|
||||||
abstract MethodProxy pktOut();
|
|
||||||
|
|
||||||
@Target
|
|
||||||
public abstract void sendPacket(IPacket<?> pak, GenericFutureListener<? extends Future<? super Void>> gfl);
|
|
||||||
|
|
||||||
@Injector
|
|
||||||
public void inject(ClassNode clazz, MethodNode main) {
|
|
||||||
// hook at the top
|
|
||||||
LabelNode skip = new LabelNode();
|
|
||||||
InsnSequence is = new InsnSequence();
|
|
||||||
is.add(new VarInsnNode(ALOAD, 1));
|
|
||||||
is.add(new MethodProxyInsnNode(INVOKESTATIC, pktOut()));
|
|
||||||
is.add(new JumpInsnNode(IFEQ, skip));
|
|
||||||
is.add(new InsnNode(RETURN));
|
|
||||||
is.add(skip);
|
|
||||||
|
|
||||||
main.instructions.insert(is);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
69
src/main/java/ftbsc/bscv/system/PacketHandler.java
Normal file
69
src/main/java/ftbsc/bscv/system/PacketHandler.java
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
package ftbsc.bscv.system;
|
||||||
|
|
||||||
|
import ftbsc.bscv.Boscovicino;
|
||||||
|
import io.netty.channel.*;
|
||||||
|
import net.minecraft.network.IPacket;
|
||||||
|
import net.minecraft.network.NetworkManager;
|
||||||
|
import net.minecraftforge.client.event.ClientPlayerNetworkEvent;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.eventbus.api.Cancelable;
|
||||||
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
|
@ChannelHandler.Sharable
|
||||||
|
public class PacketHandler extends ChannelDuplexHandler {
|
||||||
|
|
||||||
|
public PacketHandler() {
|
||||||
|
MinecraftForge.EVENT_BUS.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
if(processPacket(msg, false))
|
||||||
|
super.channelRead(ctx, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
|
if(processPacket(msg, true))
|
||||||
|
super.write(ctx, msg, promise);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean processPacket(Object msg, boolean outgoing) {
|
||||||
|
if(msg instanceof IPacket) {
|
||||||
|
IPacket<?> pkt = (IPacket<?>) msg;
|
||||||
|
PacketEvent event = outgoing ? new PacketEvent.Outgoing(pkt) : new PacketEvent.Incoming(pkt);
|
||||||
|
MinecraftForge.EVENT_BUS.post(event);
|
||||||
|
return !event.isCanceled();
|
||||||
|
} else return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
|
public void registerOnLogin(ClientPlayerNetworkEvent.LoggedInEvent event) {
|
||||||
|
NetworkManager nm = event.getNetworkManager();
|
||||||
|
if(nm != null) {
|
||||||
|
nm.channel().pipeline().addBefore("packet_handler", "bscv_handler", this);
|
||||||
|
Boscovicino.LOGGER.info("Successfully registered PacketHandler!");
|
||||||
|
} else Boscovicino.LOGGER.error("Failed to register PacketHandler: NetworkManager was null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cancelable
|
||||||
|
public static class PacketEvent extends Event {
|
||||||
|
|
||||||
|
public static class Outgoing extends PacketEvent {
|
||||||
|
public final IPacket<?> packet;
|
||||||
|
|
||||||
|
public Outgoing(IPacket<?> packet) {
|
||||||
|
this.packet = packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Incoming extends PacketEvent {
|
||||||
|
public final IPacket<?> packet;
|
||||||
|
|
||||||
|
public Incoming(IPacket<?> packet) {
|
||||||
|
this.packet = packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue