Remove unused packet classes

This commit is contained in:
kernitus committed 2024-05-25 12:43:25 +01:00
1 parent ea563c1f7e
commit 649f50ba92
8 files changed
-698

No files matched your search

@@ -1,38 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet;
import org.bukkit.entity.Player;
public interface ImmutablePacket {
/**
* Sends this packet to the given players.
*
* @param players the players to send it to
*/
default void send(Player... players) {
for(Player player : players){
PacketSender.getInstance().sendPacket(this, player);
}
}
/**
* Returns the underlying packet object. The packet object is immutable in newer versions. This method is provided
* as an escape hatch.
*
* @return the underlying nms packet
*/
Object getNmsPacket();
/**
* @implNote this method return {@code getNmsPacket().getClass()}
* @return the class of the nms packet
*/
default Class<?> getPacketClass() {
return getNmsPacket().getClass();
}
}
@@ -1,53 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet;
import kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector;
import kernitus.plugin.OldCombatMechanics.utilities.reflection.type.ClassType;
public class PacketHelper {
private static final Class<?> NMS_PACKET_CLASS = Reflector.getClass(ClassType.NMS, "network.protocol.Packet");
public static Class<?> getPacketClass(PacketType type, String name){
return Reflector.getClass(ClassType.NMS, "network.protocol.game.Packet" + type.prefix + name);
}
/**
* Checks if a given object is an NMS packet.
*
* @param object the object to check
* @return true if it is an HMS packet
*/
public static boolean isNmsPacket(Object object){
if(object == null){
return false;
}
return Reflector.inheritsFrom(object.getClass(), NMS_PACKET_CLASS);
}
/**
* Wraps a nms packet in a trivial {@link ImmutablePacket}.
*
* @param nmsPacket the nms packet to wrap
* @return the wrapping {@link ImmutablePacket}
*/
public static ImmutablePacket wrap(Object nmsPacket){
return () -> nmsPacket;
}
/**
* The type of a packet (in / out).
*/
public enum PacketType {
PlayOut("PlayOut"), PlayIn("PlayIn");
public String prefix;
PacketType(String prefix){
this.prefix = prefix;
}
}
}
@@ -1,68 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet;
import kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector;
import kernitus.plugin.OldCombatMechanics.utilities.reflection.type.ClassType;
import org.bukkit.entity.Player;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* A Packet sender
*/
public class PacketSender {
private static final PacketSender instance = new PacketSender();
private static final Method GET_HANDLE;
private static final Method SEND_PACKET;
private static final Field PLAYER_CONNECTION_FIELD;
static{
Class<?> craftPlayer = Reflector.getClass(ClassType.CRAFTBUKKIT, "entity.CraftPlayer");
Class<?> playerConnection = Reflector.getClass(ClassType.NMS, "server.network.PlayerConnection");
Class<?> entityPlayer = Reflector.getClass(ClassType.NMS, "server.level.EntityPlayer");
GET_HANDLE = Reflector.getMethod(craftPlayer, "getHandle");
SEND_PACKET = Reflector.versionIsNewerOrEqualTo(1, 18, 0)
? Reflector.getMethod(playerConnection, "a", "Packet")
: Reflector.getMethod(playerConnection, "sendPacket");
PLAYER_CONNECTION_FIELD = Reflector.getFieldByType(entityPlayer, "PlayerConnection");
}
private PacketSender(){
}
/**
* @return The Instance of the PacketSender
*/
public static PacketSender getInstance(){
return instance;
}
/**
* Sends a packet to a Player
*
* @param packet The {@link ImmutablePacket} to send
* @param player The Player to send it to
*/
public void sendPacket(ImmutablePacket packet, Player player){
Reflector.invokeMethod(SEND_PACKET, getConnection(player), packet.getNmsPacket());
}
/**
* Returns the Player's PlayerConnection
*
* @param player The Player to get the Connection for
* @return The Player's connection
*/
public Object getConnection(Player player){
Object handle = Reflector.invokeMethod(GET_HANDLE, player);
return Reflector.getFieldValue(PLAYER_CONNECTION_FIELD, handle);
}
}
@@ -1,22 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet.mitm;
/**
* Skeleton implementation of {@link PacketListener}.
*/
public class PacketAdapter implements PacketListener {
@Override
public void onPacketReceived(PacketEvent packetEvent){
}
@Override
public void onPacketSend(PacketEvent packetEvent){
}
}
@@ -1,98 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet.mitm;
import kernitus.plugin.OldCombatMechanics.utilities.packet.ImmutablePacket;
import org.bukkit.entity.Player;
/**
* A packet event
*/
public class PacketEvent {
private ImmutablePacket packet;
private final Player player;
private boolean cancelled;
private final ConnectionDirection direction;
/**
* @param packet The packet
* @param direction The direction the packet is travelling
* @param player The involved Player
*/
protected PacketEvent(ImmutablePacket packet, ConnectionDirection direction, Player player){
this.packet = packet;
this.direction = direction;
this.player = player;
this.cancelled = false;
}
/**
* Returns the packet
*
* @return The Packet
*/
public ImmutablePacket getPacket(){
return packet;
}
/**
* Sets the new packet
*
* @param packet The new packet
*/
public void setPacket(ImmutablePacket packet){
this.packet = packet;
}
/**
* Checks if the event is cancelled
*
* @return True if the event is cancelled
*/
@SuppressWarnings("WeakerAccess")
public boolean isCancelled(){
return cancelled;
}
/**
* Sets the events cancelled status.
*
* @param cancelled if true, the event will be cancelled.
*/
public void setCancelled(boolean cancelled){
this.cancelled = cancelled;
}
/**
* Returns the connection direction
*
* @return The Direction the packet was travelling
*/
@SuppressWarnings("unused")
public ConnectionDirection getDirection(){
return direction;
}
/**
* Returns the involved Player
*
* @return The player that is involved.
*/
@SuppressWarnings("unused")
public Player getPlayer(){
return player;
}
/**
* The direction the packet was travelling
*/
public enum ConnectionDirection {
TO_CLIENT,
TO_SERVER
}
}
@@ -1,244 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet.mitm;
import io.netty.channel.*;
import kernitus.plugin.OldCombatMechanics.utilities.Messenger;
import kernitus.plugin.OldCombatMechanics.utilities.packet.PacketHelper;
import kernitus.plugin.OldCombatMechanics.utilities.packet.PacketSender;
import kernitus.plugin.OldCombatMechanics.utilities.reflection.Reflector;
import org.bukkit.entity.Player;
import java.lang.ref.WeakReference;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A simple packet injector, to modify the packets sent and received
*/
class PacketInjector extends ChannelDuplexHandler {
private volatile boolean isClosed;
private Channel channel;
// There are a lot more reads than writes, so performance should be okay
private final List<PacketListener> packetListeners = new CopyOnWriteArrayList<>();
private final WeakReference<Player> playerWeakReference;
private boolean detectedNonNMSPacket = false;
/**
* Must be detached manually!
*
* @param player The player to attach into
*/
PacketInjector(Player player) {
Objects.requireNonNull(player, "player can not be null!");
playerWeakReference = new WeakReference<>(player);
try {
attach(player);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Attaches to a player
*
* @param player The player to attach to
*/
private void attach(Player player) throws Exception {
Object playerConnection = PacketSender.getInstance().getConnection(player);
if (playerConnection == null) {
debug("Could not get playerConnection for player(%s)! Did PacketSender fail to load? (%d)", player.getName(), hashCode());
return;
}
Object manager = Reflector.getFieldValueByType(playerConnection, "NetworkManager");
channel = (Channel) Reflector.getFieldValueByType(manager, "Channel");
// remove old listener, if it wasn't properly cleared up
if (channel.pipeline().get("ocm_handler") != null) {
debug("Old listener lingered around");
ChannelHandler old = channel.pipeline().get("ocm_handler");
if (old instanceof PacketInjector) {
debug("Detaching old listener");
((PacketInjector) old).detach();
}
// remove old
channel.pipeline().remove("ocm_handler");
}
try {
channel.pipeline().addBefore("packet_handler", "ocm_handler", this);
} catch (NoSuchElementException e) {
throw new NoSuchElementException("No base handler found. Was the player instantly disconnected?");
}
}
/**
* Removes this handler
*/
void detach() {
debug("Detaching injector... (%d)", hashCode());
if (channel == null) {
debug("Could not detach injector because it was never fully attached! (%d)", hashCode());
return;
}
if (isClosed || !channel.isOpen()) {
debug("Closed(%b) or channel closed(%b) already! (%d)", isClosed, !channel.isOpen(), hashCode());
return;
}
channel.eventLoop().submit(() -> {
channel.pipeline().remove(this);
// only clear the channel after the last access
channel = null;
isClosed = true;
// clear references. Probably not needed, but I am not sure about the
// channel.
playerWeakReference.clear();
packetListeners.clear();
debug("Injector successfully detached (%d)", hashCode());
});
}
/**
* Adds a {@link PacketListener}
*
* @param packetListener The {@link PacketListener} to add
* @throws IllegalStateException if the channel is already closed
*/
void addPacketListener(PacketListener packetListener) {
Objects.requireNonNull(packetListener, "packetListener can not be null");
if (isClosed) {
throw new IllegalStateException("Channel already closed. Adding of listener invalid");
}
// prevent duplicate registrations
packetListeners.remove(packetListener);
packetListeners.add(packetListener);
}
/**
* Removes a {@link PacketListener}
*
* @param packetListener The {@link PacketListener} to remove
*/
void removePacketListener(PacketListener packetListener) {
packetListeners.remove(packetListener);
}
/**
* Returns the amount of listeners
*
* @return The amount of listeners
*/
int getListenerAmount() {
return packetListeners.size();
}
@Override
public void write(ChannelHandlerContext channelHandlerContext, Object packet, ChannelPromise channelPromise)
throws Exception {
if (playerWeakReference == null || playerWeakReference.get() == null) {
debug(
"playerWeakReference or its value is null. This should NOT happen at this stage. " +
"(write@%d)", hashCode()
);
detach();
// bubble up
super.write(channelHandlerContext, packet, channelPromise);
return;
}
if (!PacketHelper.isNmsPacket(packet)) {
// forward non-nms packets, but complain at least once
if (!detectedNonNMSPacket) {
Messenger.warn("Received a packet that is not NMS: %s %s", packet.getClass(), packet);
detectedNonNMSPacket = true;
}
super.write(channelHandlerContext, packet, channelPromise);
return;
}
PacketEvent event = new PacketEvent(
PacketHelper.wrap(packet),
PacketEvent.ConnectionDirection.TO_CLIENT,
playerWeakReference.get()
);
for (PacketListener packetListener : packetListeners) {
try {
if (!isClosed) {
packetListener.onPacketSend(event);
}
} catch (Exception e) {
Messenger.warn(e, "Error in a packet listener (send).");
}
}
// let it through
if (!event.isCancelled()) {
super.write(channelHandlerContext, packet, channelPromise);
}
}
@Override
public void channelRead(ChannelHandlerContext channelHandlerContext, Object packet) throws Exception {
if (playerWeakReference == null || playerWeakReference.get() == null) {
debug(
"playerWeakReference or its value is null. This should NOT happen at this stage. " +
"(read@%d)", hashCode()
);
detach();
// bubble up
super.channelRead(channelHandlerContext, packet);
return;
}
if (!PacketHelper.isNmsPacket(packet)) {
debug("Received a packet THAT IS NO PACKET: " + packet.getClass() + " " + packet);
return;
}
PacketEvent event = new PacketEvent(
PacketHelper.wrap(packet),
PacketEvent.ConnectionDirection.TO_SERVER,
playerWeakReference.get()
);
for (PacketListener packetListener : packetListeners) {
try {
if (!isClosed) {
packetListener.onPacketReceived(event);
}
} catch (Exception e) {
Messenger.warn(e, "Error in a packet listener (receive).");
}
}
// let it through
if (!event.isCancelled()) {
super.channelRead(channelHandlerContext, packet);
}
}
private static void debug(String message, Object... formatArgs) {
Messenger.debug("PacketInjector: " + message, formatArgs);
}
}
@@ -1,26 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet.mitm;
/**
* Listens for a Packet
*/
public interface PacketListener {
/**
* Called when a packet is received
*
* @param packetEvent The {@link PacketEvent}
*/
void onPacketReceived(PacketEvent packetEvent);
/**
* Called when a packet is send
*
* @param packetEvent The {@link PacketEvent}
*/
void onPacketSend(PacketEvent packetEvent);
}
@@ -1,149 +0,0 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package kernitus.plugin.OldCombatMechanics.utilities.packet.mitm;
import kernitus.plugin.OldCombatMechanics.OCMMain;
import kernitus.plugin.OldCombatMechanics.utilities.Messenger;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import java.util.*;
/**
* Manages PacketListeners and stuff
* <p>
* This Manager removes the listeners when the Player leaves. You do not need to
* keep track of that!
*/
public class PacketManager implements Listener {
private static PacketManager instance;
private final Map<UUID, PacketInjector> injectorMap = new HashMap<>();
/**
* Instantiates a new PacketManager
*
* @param plugin The plugin to instantiate it as
*/
private PacketManager(Plugin plugin){
Bukkit.getPluginManager().registerEvents(this, plugin);
OCMMain.getInstance().addDisableListener(() -> {
removeAll();
instance = null;
});
}
/**
* Returns the Manager instance
*
* @return An instance of the PacketManager
*/
public static synchronized PacketManager getInstance(){
if(instance == null){
instance = new PacketManager(OCMMain.getInstance());
}
return instance;
}
/**
* Adds a packet listener
*
* @param listener The {@link PacketListener} to add
* @param player The Player to listen for
* @throws NullPointerException if any parameter is null
*/
public void addListener(PacketListener listener, Player player){
Objects.requireNonNull(listener, "listener can not be null");
Objects.requireNonNull(player, "player can not be null");
// no modifications during checks or the result may be wrong! (it
// changes depending on the current state)
synchronized(injectorMap){
if(injectorMap.containsKey(player.getUniqueId())){
injectorMap.get(player.getUniqueId()).addPacketListener(listener);
} else {
try{
PacketInjector injector = new PacketInjector(player);
injector.addPacketListener(listener);
injectorMap.put(player.getUniqueId(), injector);
} catch(Exception e){
Messenger.debug("Error attaching packet listener!", e);
}
}
}
}
/**
* Removes the Listener for a player
*
* @param listener The listener to remove
* @param player The player to remove it for
* @throws NullPointerException if any parameter is null
*/
public void removeListener(PacketListener listener, Player player){
Objects.requireNonNull(listener, "listener can not be null");
Objects.requireNonNull(player, "player can not be null");
// no modifications during checks or the result may be wrong! (it
// changes depending on the current state)
synchronized(injectorMap){
if(!injectorMap.containsKey(player.getUniqueId())){
return;
}
PacketInjector injector = injectorMap.get(player.getUniqueId());
injector.removePacketListener(listener);
if(injector.getListenerAmount() < 1){
injector.detach();
injectorMap.remove(player.getUniqueId());
}
}
}
/**
* Removes <b>all</b> listeners from a player
*
* @param uuid The {@link UUID} of the Player to remove all listeners for
* @throws NullPointerException if uuid is null
*/
public void removeAllListeners(UUID uuid){
Objects.requireNonNull(uuid, "uuid can not be null");
// no modifications during checks or the result may be wrong! (it
// changes depending on the current state)
synchronized(injectorMap){
if(injectorMap.containsKey(uuid)){
injectorMap.get(uuid).detach();
injectorMap.remove(uuid);
}
}
}
/**
* <i>Removes <b>ALL</b> listeners</i>
* <p>
* Use with caution or not at all.
*/
private void removeAll(){
synchronized(injectorMap){
// clone to avoid concurrent modification
Set<UUID> keys = new HashSet<>(injectorMap.keySet());
keys.forEach(this::removeAllListeners);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onLeave(PlayerQuitEvent event){
// clean up
removeAllListeners(event.getPlayer().getUniqueId());
}
}