forked from SteamWar/SteamWar
Add SteamWar adaption for TinyProtocol
This commit is contained in:
@@ -24,6 +24,7 @@ import de.steamwar.Reflection;
|
|||||||
import de.steamwar.core.Core;
|
import de.steamwar.core.Core;
|
||||||
import io.netty.channel.*;
|
import io.netty.channel.*;
|
||||||
import net.minecraft.network.Connection;
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.network.protocol.login.ServerboundHelloPacket;
|
import net.minecraft.network.protocol.login.ServerboundHelloPacket;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.network.ServerConnectionListener;
|
import net.minecraft.server.network.ServerConnectionListener;
|
||||||
@@ -39,6 +40,8 @@ import org.bukkit.plugin.Plugin;
|
|||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -57,7 +60,7 @@ public class TinyProtocol {
|
|||||||
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
|
private Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
|
||||||
|
|
||||||
// List of network markers
|
// List of network markers
|
||||||
private List<Connection> networkManagers;
|
public List<Connection> networkManagers;
|
||||||
|
|
||||||
// Injected channel handlers
|
// Injected channel handlers
|
||||||
private List<Channel> serverChannels = new ArrayList<>();
|
private List<Channel> serverChannels = new ArrayList<>();
|
||||||
@@ -72,6 +75,11 @@ public class TinyProtocol {
|
|||||||
protected Plugin plugin;
|
protected Plugin plugin;
|
||||||
|
|
||||||
public static final TinyProtocol instance = new TinyProtocol(Core.getInstance());
|
public static final TinyProtocol instance = new TinyProtocol(Core.getInstance());
|
||||||
|
private final Map<Class<?>, List<BiFunction<Player, Object, Object>>> packetFilters = new HashMap<>();
|
||||||
|
|
||||||
|
public static void init() {
|
||||||
|
// enforce init
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
|
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
|
||||||
@@ -235,79 +243,63 @@ public class TinyProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public <T> void addTypedFilter(Class<T> packetType, BiFunction<Player, T, Object> filter) {
|
||||||
* Invoked when the server is starting to send a packet to a player.
|
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add((BiFunction) filter);
|
||||||
* <p>
|
|
||||||
* Note that this is not executed on the main thread.
|
|
||||||
*
|
|
||||||
* @param receiver - the receiving player, NULL for early login/status packets.
|
|
||||||
* @param channel - the channel that received the packet. Never NULL.
|
|
||||||
* @param packet - the packet being sent.
|
|
||||||
* @return The packet to send instead, or NULL to cancel the transmission.
|
|
||||||
*/
|
|
||||||
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Deprecated
|
||||||
* Invoked when the server has received a packet from a given player.
|
public void addFilter(Class<?> packetType, BiFunction<Player, Object, Object> filter) {
|
||||||
* <p>
|
packetFilters.computeIfAbsent(packetType, c -> new CopyOnWriteArrayList<>()).add(filter);
|
||||||
* Use {@link Channel#remoteAddress()} to get the remote address of the client.
|
}
|
||||||
*
|
|
||||||
* @param sender - the player that sent the packet, NULL for early login/status packets.
|
public void removeFilter(Class<?> packetType, BiFunction<Player, Object, Object> filter) {
|
||||||
* @param channel - channel that received the packet. Never NULL.
|
packetFilters.getOrDefault(packetType, Collections.emptyList()).remove(filter);
|
||||||
* @param packet - the packet being received.
|
|
||||||
* @return The packet to recieve instead, or NULL to cancel.
|
|
||||||
*/
|
|
||||||
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
|
|
||||||
return packet;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a packet to a particular player.
|
* Send a packet to a particular player.
|
||||||
* <p>
|
|
||||||
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
|
|
||||||
*
|
*
|
||||||
* @param player - the destination player.
|
* @param player - the destination player.
|
||||||
* @param packet - the packet to send.
|
* @param packet - the packet to send.
|
||||||
*/
|
*/
|
||||||
public void sendPacket(Player player, Object packet) {
|
public void sendPacket(Player player, Packet<?> packet) {
|
||||||
sendPacket(getChannel(player), packet);
|
sendPacket(getChannel(player), packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public void sendPacket(Player player, Object object) {
|
||||||
|
if (object instanceof Packet<?> packet) {
|
||||||
|
sendPacket(getChannel(player), packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a packet to a particular client.
|
* Send a packet to a particular client.
|
||||||
* <p>
|
|
||||||
* Note that {@link #onPacketOutAsync(Player, Channel, Object)} will be invoked with this packet.
|
|
||||||
*
|
*
|
||||||
* @param channel - client identified by a channel.
|
* @param channel - client identified by a channel.
|
||||||
* @param packet - the packet to send.
|
* @param packet - the packet to send.
|
||||||
*/
|
*/
|
||||||
public void sendPacket(Channel channel, Object packet) {
|
public void sendPacket(Channel channel, Packet<?> packet) {
|
||||||
channel.pipeline().writeAndFlush(packet);
|
channel.pipeline().writeAndFlush(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pretend that a given packet has been received from a player.
|
* Pretend that a given packet has been received from a player.
|
||||||
* <p>
|
|
||||||
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
|
|
||||||
*
|
*
|
||||||
* @param player - the player that sent the packet.
|
* @param player - the player that sent the packet.
|
||||||
* @param packet - the packet that will be received by the server.
|
* @param packet - the packet that will be received by the server.
|
||||||
*/
|
*/
|
||||||
public void receivePacket(Player player, Object packet) {
|
public void receivePacket(Player player, Packet<?> packet) {
|
||||||
receivePacket(getChannel(player), packet);
|
receivePacket(getChannel(player), packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pretend that a given packet has been received from a given client.
|
* Pretend that a given packet has been received from a given client.
|
||||||
* <p>
|
|
||||||
* Note that {@link #onPacketInAsync(Player, Channel, Object)} will be invoked with this packet.
|
|
||||||
*
|
*
|
||||||
* @param channel - client identified by a channel.
|
* @param channel - client identified by a channel.
|
||||||
* @param packet - the packet that will be received by the server.
|
* @param packet - the packet that will be received by the server.
|
||||||
*/
|
*/
|
||||||
public void receivePacket(Channel channel, Object packet) {
|
public void receivePacket(Channel channel, Packet<?> packet) {
|
||||||
channel.pipeline().context("encoder").fireChannelRead(packet);
|
channel.pipeline().context("encoder").fireChannelRead(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,7 +453,7 @@ public class TinyProtocol {
|
|||||||
handleLoginStart(channel, msg);
|
handleLoginStart(channel, msg);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
msg = onPacketInAsync(player, channel, msg);
|
msg = filterPacket(player, msg);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
|
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
|
||||||
}
|
}
|
||||||
@@ -474,7 +466,7 @@ public class TinyProtocol {
|
|||||||
@Override
|
@Override
|
||||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
try {
|
try {
|
||||||
msg = onPacketOutAsync(player, ctx.channel(), msg);
|
msg = filterPacket(player, msg);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
|
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
|
||||||
}
|
}
|
||||||
@@ -489,5 +481,16 @@ public class TinyProtocol {
|
|||||||
channelLookup.put(name, channel);
|
channelLookup.put(name, channel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Object filterPacket(Player player, Object packet) {
|
||||||
|
List<BiFunction<Player, Object, Object>> filters = packetFilters.getOrDefault(packet.getClass(), Collections.emptyList());
|
||||||
|
|
||||||
|
for(BiFunction<Player, Object, Object> filter : filters) {
|
||||||
|
packet = filter.apply(player, packet);
|
||||||
|
if(packet == null) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,6 +23,8 @@ import com.comphenix.tinyprotocol.TinyProtocol;
|
|||||||
import de.steamwar.Reflection;
|
import de.steamwar.Reflection;
|
||||||
import de.steamwar.sql.internal.Statement;
|
import de.steamwar.sql.internal.Statement;
|
||||||
import io.netty.channel.ChannelFuture;
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.network.ServerConnectionListener;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.eclipse.openj9.criu.CRIUSupport;
|
import org.eclipse.openj9.criu.CRIUSupport;
|
||||||
import org.eclipse.openj9.criu.JVMCRIUException;
|
import org.eclipse.openj9.criu.JVMCRIUException;
|
||||||
@@ -56,7 +58,7 @@ class CheckpointUtilsJ9 {
|
|||||||
|
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null));
|
Bukkit.getOnlinePlayers().forEach(player -> player.kickPlayer(null));
|
||||||
|
|
||||||
List<?> networkManagers = TinyProtocol.networkManagers.get(TinyProtocol.getServerConnection(Core.getInstance()));
|
List<?> networkManagers = TinyProtocol.instance.networkManagers;
|
||||||
if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) {
|
if(!Bukkit.getOnlinePlayers().isEmpty() || !networkManagers.isEmpty()) {
|
||||||
Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing");
|
Core.getInstance().getLogger().log(Level.INFO, "Waiting for players to disconnect for checkpointing");
|
||||||
Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1);
|
Bukkit.getScheduler().runTaskLater(Core.getInstance(), CheckpointUtils::freeze, 1);
|
||||||
@@ -90,8 +92,8 @@ class CheckpointUtilsJ9 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static final Reflection.Field<List> channelFutures = Reflection.getField(TinyProtocol.serverConnection, List.class, 0, ChannelFuture.class);
|
private static final Reflection.Field<List> channelFutures = Reflection.getField(ServerConnectionListener.class, List.class, 0, ChannelFuture.class);
|
||||||
private static final Reflection.Method bind = Reflection.getMethod(TinyProtocol.serverConnection, null, InetAddress.class, int.class);
|
private static final Reflection.Method bind = Reflection.getMethod(ServerConnectionListener.class, null, InetAddress.class, int.class);
|
||||||
private static void freezeInternal(Path path) throws Exception {
|
private static void freezeInternal(Path path) throws Exception {
|
||||||
Bukkit.getPluginManager().callEvent(new CRIUSleepEvent());
|
Bukkit.getPluginManager().callEvent(new CRIUSleepEvent());
|
||||||
|
|
||||||
@@ -99,7 +101,7 @@ class CheckpointUtilsJ9 {
|
|||||||
Statement.closeAll();
|
Statement.closeAll();
|
||||||
|
|
||||||
// Close socket
|
// Close socket
|
||||||
Object serverConnection = TinyProtocol.getServerConnection(Core.getInstance());
|
ServerConnectionListener serverConnection = MinecraftServer.getServer().getConnection();
|
||||||
List<?> channels = channelFutures.get(serverConnection);
|
List<?> channels = channelFutures.get(serverConnection);
|
||||||
for(Object future : channels) {
|
for(Object future : channels) {
|
||||||
((ChannelFuture) future).channel().close().syncUninterruptibly();
|
((ChannelFuture) future).channel().close().syncUninterruptibly();
|
||||||
|
|||||||
Reference in New Issue
Block a user