forked from retrooper/packetevents
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathPacketEncoder.java
More file actions
126 lines (110 loc) · 5.26 KB
/
Copy pathPacketEncoder.java
File metadata and controls
126 lines (110 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
* FIXED VERSION: Restored buffer management logic
*/
package io.github.retrooper.packetevents.handler;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.event.ProtocolPacketEvent;
import com.github.retrooper.packetevents.exception.CancelPacketException;
import com.github.retrooper.packetevents.exception.InvalidDisconnectPacketSend;
import com.github.retrooper.packetevents.exception.PacketProcessException;
import com.github.retrooper.packetevents.netty.buffer.ByteBufHelper;
import com.github.retrooper.packetevents.protocol.ConnectionState;
import com.github.retrooper.packetevents.protocol.PacketSide;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.util.ExceptionUtil;
import com.github.retrooper.packetevents.util.PacketEventsImplHelper;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerDisconnect;
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsAPI;
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.ChannelPromise;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nullable;
@ApiStatus.Internal @ChannelHandler.Sharable
public class PacketEncoder extends ChannelOutboundHandlerAdapter {
private static final boolean NETTY_4_1_0;
static {
boolean netty410 = false;
try {
ChannelPromise.class.getDeclaredMethod("unvoid");
netty410 = true;
} catch (NoSuchMethodException ignored) {
}
NETTY_4_1_0 = netty410;
}
private final PacketSide side;
public User user;
// Platform-typed player: yarn ServerPlayerEntity on intermediary, Mojang ServerPlayer
// on official. Concrete-only handling is delegated to AbstractFabricPlayerManager.
public Object player;
private ChannelPromise promise;
private final boolean preViaVersion;
public PacketEncoder(PacketSide side, User user, boolean preViaVersion) {
this.side = side;
this.user = user;
this.preViaVersion = preViaVersion;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (!(msg instanceof ByteBuf in)) {
ctx.write(msg, promise);
return;
}
// Handle promise management
ChannelPromise oldPromise = this.promise != null && !this.promise.isSuccess() ? this.promise : null;
if (NETTY_4_1_0) {
promise = promise.unvoid();
}
promise.addListener(p -> this.promise = oldPromise);
this.promise = promise;
handlePacket(ctx, in, promise);
if (!ByteBufHelper.isReadable(in)) {
throw CancelPacketException.INSTANCE;
} else {
ctx.write(in, promise);
}
}
private @Nullable ProtocolPacketEvent handlePacket(ChannelHandlerContext ctx, ByteBuf buffer, ChannelPromise promise) throws Exception {
if (!preViaVersion && PacketEvents.getAPI().getSettings().isPreViaInjection() && !ViaVersionUtil.isAvailable(user))
PacketEventsImplHelper.handlePacket(ctx.channel(), user, player, buffer, preViaVersion, this.side);
ProtocolPacketEvent protocolPacketEvent = PacketEventsImplHelper.handlePacket(
ctx.channel(), this.user, this.player, buffer, !preViaVersion, this.side
);
if (protocolPacketEvent instanceof PacketSendEvent packetSendEvent && packetSendEvent.hasTasksAfterSend()) {
promise.addListener((p) -> {
for (Runnable task : packetSendEvent.getTasksAfterSend()) {
task.run();
}
});
}
return protocolPacketEvent;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (ExceptionUtil.isException(cause, CancelPacketException.class)) return;
if (ExceptionUtil.isException(cause, InvalidDisconnectPacketSend.class)) return;
boolean didWeCauseThis = ExceptionUtil.isException(cause, PacketProcessException.class);
if (didWeCauseThis && (user == null || user.getEncoderState() != ConnectionState.HANDSHAKING)) {
if (PacketEvents.getAPI().getSettings().isKickOnPacketExceptionEnabled()) {
try {
if (user != null && player != null) {
WrapperPlayServerDisconnect disconnectPacket = new WrapperPlayServerDisconnect(
net.kyori.adventure.text.Component.text("Invalid packet")
);
user.sendPacket(disconnectPacket);
}
} catch (Exception ignored) {}
ctx.channel().close();
if (player != null) {
FabricPacketEventsAPI.getServerAPI().getPlayerManager()
.kickOnException(player, "Invalid packet");
}
}
}
super.exceptionCaught(ctx, cause);
}
}