Compare commits

..
2 Commits
Author SHA1 Message Date
retrooper 4a4b7b050e Merge pull request #51 from retrooper/dev
1.7 2nd PRE RELEASE
2020-10-04 09:18:00 +02:00
retrooper fdbdcb81be Merge pull request #50 from retrooper/dev
packetevents 1.7 pre release 1(1.6.9.1)
2020-09-27 18:09:44 +02:00
67 changed files with 916 additions and 4071 deletions

No files matched your search

+2 -2
View File
@@ -1,10 +1,10 @@
# packetevents
A Spigot packet API with some nice utlities.
A spigot packet API with some nice utlities.
## About
This packetlistener is **only** supported on Spigot servers and has been tested to work on these Spigot forks: PaperMC, Tuinity
This packetlistener is **only** supported on spigot servers and has been tested to work on these spigot forks: PaperSpigot, Tuinity
* No dependencies
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>io.github.retrooper</groupId>
<artifactId>packetevents</artifactId>
<version>1.7</version>
<version>1.6.9.2</version>
<!-- You can build the project with this: "mvn clean compile assembly:single" -->
<build>
@@ -24,10 +24,7 @@
package io.github.retrooper.packetevents;
import io.github.retrooper.packetevents.bungee.BungeePluginMessageListener;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.packetmanager.PacketManager;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.settings.PacketEventsSettings;
@@ -35,30 +32,29 @@ import io.github.retrooper.packetevents.updatechecker.UpdateChecker;
import io.github.retrooper.packetevents.utils.entityfinder.EntityFinderUtils;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import io.github.retrooper.packetevents.utils.server.PEVersion;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.versionlookup.VersionLookupUtils;
import io.github.retrooper.packetevents.version.PEVersion;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.Future;
public final class PacketEvents implements Listener {
private static final String nettyHandlerIdentifier = generateRandomNettyIdentifier();
private static String nettyHandlerIdentifier = generateRandomNettyIdentifier();
private static final PacketEventsAPI packetEventsAPI = new PacketEventsAPI();
private static final PacketEvents instance = new PacketEvents();
private static final ArrayList<Plugin> plugins = new ArrayList<Plugin>(1);
private static boolean loaded, initialized;
private static final PEVersion version = new PEVersion(1, 7);
private static boolean loaded, initialized, isBungee;
private static final PEVersion version = new PEVersion(1, 6, 9, 2);
private static PacketEventsSettings settings = new PacketEventsSettings();
@@ -89,20 +85,14 @@ public final class PacketEvents implements Listener {
NMSUtils.version = version;
EntityFinderUtils.version = version;
try {
NMSUtils.load();
NMSUtils.load();
PacketTypeClasses.Client.load();
PacketTypeClasses.Server.load();
PacketTypeClasses.Login.load();
PacketTypeClasses.Status.load();
PacketTypeClasses.Client.load();
PacketTypeClasses.Server.load();
EntityFinderUtils.load();
EntityFinderUtils.load();
WrappedPacket.loadAllWrappers();
} catch (Exception ex) {
throw new IllegalStateException("PacketEvents failed to successfully load...", ex);
}
WrappedPacket.loadAllWrappers();
loaded = true;
}
@@ -128,34 +118,32 @@ public final class PacketEvents implements Listener {
* @param pl JavaPlugin instance
*/
public static void init(final Plugin pl, PacketEventsSettings packetEventsSettings) {
load();
if (!loaded) {
load();
}
if (!initialized) {
settings = packetEventsSettings;
plugins.add(pl);
//Register Bukkit listener
Bukkit.getPluginManager().registerEvents(instance, plugins.get(0));
PacketEvents.getAPI().packetManager = new PacketManager(plugins.get(0), settings.shouldInjectEarly());
for (final Player p : Bukkit.getOnlinePlayers()) {
getAPI().getPlayerUtils().injectPlayer(p);
}
initialized = true;
Class<?> spigotConfigClass;
try {
spigotConfigClass = Class.forName("org.spigotmc.SpigotConfig");
Field f = spigotConfigClass.getDeclaredField("bungee");
isBungee = f.getBoolean(null);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
isBungee = false;
}
if (settings.shouldCheckForUpdates()) {
Future<?> future = NettyPacketManager.executorService.submit(new Runnable() {
@Override
public void run() {
new UpdateChecker().handleUpdate();
}
});
Bukkit.getScheduler().runTask(pl, () -> new UpdateChecker().handleUpdate());
}
if (getAPI().getServerUtils().isBungeeCordEnabled()) {
Bukkit.getMessenger().registerOutgoingPluginChannel(plugins.get(0), "BungeeCord");
Bukkit.getServer().getMessenger().registerIncomingPluginChannel(plugins.get(0), BungeePluginMessageListener.tagName, new BungeePluginMessageListener());
}
initialized = true;
}
}
@@ -167,11 +155,9 @@ public final class PacketEvents implements Listener {
for (final Player p : Bukkit.getOnlinePlayers()) {
getAPI().getPlayerUtils().ejectPlayer(p);
}
getAPI().getEventManager().unregisterAllListeners();
initialized = false;
NettyPacketManager.executorService.shutdownNow();
}
}
@@ -208,36 +194,22 @@ public final class PacketEvents implements Listener {
return version;
}
@EventHandler
public void onLogin(PlayerLoginEvent e) {
if (PacketEvents.getSettings().shouldInjectEarly()) {
assert getAPI().packetManager.tinyProtocol != null;
if (getAPI().packetManager.tinyProtocol.canInject(e.getPlayer())) {
getAPI().packetManager.injectPlayer(e.getPlayer());
}
}
}
@EventHandler
public void onJoin(final PlayerJoinEvent e) {
if (!VersionLookupUtils.hasHandledLoadedDependencies()) {
VersionLookupUtils.handleLoadedDependencies();
if (!VersionLookupUtils.hasLoaded()) {
VersionLookupUtils.load();
}
Object channel = NMSUtils.getChannel(e.getPlayer());
//Waiting for the BungeeCord server to send their plugin message with your version,
//So we leave bungee alone
if (!PacketEvents.getAPI().getServerUtils().isBungeeCordEnabled()) {
if (VersionLookupUtils.isDependencyAvailable()) {
ClientVersion version = ClientVersion.getClientVersion(VersionLookupUtils.getProtocolVersion(e.getPlayer()));
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(channel, version);
}
}
if (!PacketEvents.getSettings().shouldInjectEarly()) {
PacketEvents.getAPI().packetManager.injectPlayer(e.getPlayer());
//for now we don't support bungee, rather handle it than have it FALSE
//and return the version of the server.
if (isBungee) {
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(e.getPlayer().getUniqueId(), ClientVersion.UNKNOWN);
} else {
ClientVersion version = ClientVersion.getClientVersion(VersionLookupUtils.getProtocolVersion(e.getPlayer()));
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(e.getPlayer().getUniqueId(), version);
}
PacketEvents.getAPI().getPlayerUtils().injectPlayer(e.getPlayer());
}
@EventHandler
public void onQuit(final PlayerQuitEvent e) {
PacketEvents.getAPI().getPlayerUtils().ejectPlayer(e.getPlayer());
@@ -252,7 +224,8 @@ public final class PacketEvents implements Listener {
int index = (int) (random.nextFloat() * alphabet.length());
sb.append(alphabet.charAt(index));
}
return sb.toString();
}
}
}
@@ -25,7 +25,6 @@
package io.github.retrooper.packetevents;
import io.github.retrooper.packetevents.event.manager.EventManager;
import io.github.retrooper.packetevents.packetmanager.PacketManager;
import io.github.retrooper.packetevents.settings.PacketEventsSettings;
import io.github.retrooper.packetevents.utils.player.PlayerUtils;
import io.github.retrooper.packetevents.utils.server.ServerUtils;
@@ -34,7 +33,6 @@ public final class PacketEventsAPI {
private final EventManager eventManager = new EventManager();
private final PlayerUtils playerUtils = new PlayerUtils();
private final ServerUtils serverUtils = new ServerUtils();
public PacketManager packetManager = null;
/**
* Get all utilities to do with the player
@@ -1,55 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.bungee;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteStreams;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import org.bukkit.entity.Player;
import org.bukkit.plugin.messaging.PluginMessageListener;
import java.util.UUID;
public class BungeePluginMessageListener implements PluginMessageListener {
public static String tagName = "packetevents";
@Override
public void onPluginMessageReceived(String tag, Player player, byte[] bytes) {
if (tag.equals(tagName)) {
ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
if (in.readUTF().equals("version")) {
String uuidString = in.readUTF();
Object channel = NMSUtils.getChannel(player);
short protocolVersion = in.readShort();
ClientVersion version = ClientVersion.getClientVersion(protocolVersion);
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(channel, version);
}
}
}
}
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.server;
package io.github.retrooper.packetevents.enums;
public enum SystemOS {
WINDOWS, MACOS, LINUX, OTHER;
@@ -47,10 +47,9 @@ public enum SystemOS {
}
public static String[] getOperatingSystemNames() {
final SystemOS[] values = values();
final String[] arr = new String[values.length - 1];
for (int i = 0; i < values.length - 1; i++) {
arr[i] = values[i].name();
final String[] arr = new String[values().length - 1];
for (int i = 0; i < values().length - 1; i++) {
arr[i] = values()[i].name();
}
return arr;
}
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.eventtypes;
package io.github.retrooper.packetevents.event;
/**
* This indicates that it is possible to cancel an event,
@@ -1,37 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.eventtypes;
import org.bukkit.entity.Player;
/**
* Event having to do with a player.
*/
public interface PlayerEvent {
/**
* Associated player.
*/
Player getPlayer();
}
@@ -1,96 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
/**
* This event is called when we receive a login packet.
*/
public class PacketLoginEvent extends PacketEvent implements CancellableEvent {
private final Object channel;
private final Object packet;
private boolean cancelled;
public PacketLoginEvent(final Object channel, final Object packet) {
this.channel = channel;
this.packet = packet;
}
public Object getChannel() {
return channel;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
*
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
return PacketType.Login.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}
@@ -24,9 +24,8 @@
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
@@ -34,7 +33,7 @@ import org.bukkit.entity.Player;
/**
* This event is called each time a packet is received from a client.
*/
public final class PacketReceiveEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
public final class PacketReceiveEvent extends PacketEvent implements CancellableEvent {
private final Player player;
private final Object packet;
private boolean cancelled;
@@ -48,9 +47,8 @@ public final class PacketReceiveEvent extends PacketEvent implements Cancellable
* Get the packet sender
* @return player
*/
@Override
public Player getPlayer() {
return player;
return this.player;
}
/**
@@ -67,7 +65,7 @@ public final class PacketReceiveEvent extends PacketEvent implements Cancellable
* @return packet object
*/
public Object getNMSPacket() {
return packet;
return this.packet;
}
/**
@@ -80,12 +78,12 @@ public final class PacketReceiveEvent extends PacketEvent implements Cancellable
@Override
public void cancel() {
cancelled = true;
this.cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
this.cancelled = false;
}
@Override
@@ -94,8 +92,8 @@ public final class PacketReceiveEvent extends PacketEvent implements Cancellable
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
}
@@ -24,9 +24,8 @@
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
@@ -34,7 +33,7 @@ import org.bukkit.entity.Player;
/**
* This event is called each time the server sends a packet to the client.
*/
public final class PacketSendEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
public final class PacketSendEvent extends PacketEvent implements CancellableEvent {
private final Player player;
private final Object packet;
private boolean cancelled;
@@ -45,9 +44,9 @@ public final class PacketSendEvent extends PacketEvent implements CancellableEve
this.cancelled = false;
}
@Override
public Player getPlayer() {
return player;
return this.player;
}
/**
@@ -74,17 +73,7 @@ public final class PacketSendEvent extends PacketEvent implements CancellableEve
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
return this.packet;
}
@Override
@@ -93,8 +82,16 @@ public final class PacketSendEvent extends PacketEvent implements CancellableEve
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public void cancel() {
this.cancelled = true;
}
@Override
public void uncancel() { this.cancelled = false;}
}
@@ -1,93 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
public class PacketStatusEvent extends PacketEvent implements CancellableEvent {
private final Object channel;
private final Object packet;
private boolean cancelled;
public PacketStatusEvent(final Object channel, final Object packet) {
this.channel = channel;
this.packet = packet;
}
public Object getChannel() {
return channel;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
*
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
*
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
*
* @return packet id
*/
public byte getPacketId() {
return PacketType.Status.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
}
}
@@ -24,15 +24,14 @@
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import org.bukkit.entity.Player;
/**
* This event is called each time you eject a player.
*/
public final class PlayerEjectEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
public final class PlayerEjectEvent extends PacketEvent implements CancellableEvent {
private final Player player;
private final boolean async;
private boolean cancelled;
@@ -43,31 +42,27 @@ public final class PlayerEjectEvent extends PacketEvent implements CancellableEv
}
public PlayerEjectEvent(final Player player) {
this.player = player;
this.async = true; //default value
this(player, false);
}
@Override
public void cancel() {
cancelled = true;
this.cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
public void uncancel() {this.cancelled = false; }
@Override
public boolean isCancelled() {
return cancelled;
return this.cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
public void setCancelled(final boolean val) {
this.cancelled = val;
}
@Override
public Player getPlayer() {
return player;
}
@@ -24,15 +24,14 @@
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import org.bukkit.entity.Player;
/**
* This event is called each time you inject a player.
*/
public final class PlayerInjectEvent extends PacketEvent implements CancellableEvent, PlayerEvent {
public final class PlayerInjectEvent extends PacketEvent implements CancellableEvent {
private final Player player;
private final boolean async;
private boolean cancelled;
@@ -46,27 +45,24 @@ public final class PlayerInjectEvent extends PacketEvent implements CancellableE
this.async = isAsync;
}
@Override
public void cancel() {
cancelled = true;
}
@Override
public void uncancel() {
cancelled = false;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean value) {
cancelled = value;
public void setCancelled(boolean cancelled) {
this.cancelled = cancelled;
}
@Override
public void cancel() {
this.cancelled = true;
}
@Override
public void uncancel() {this.cancelled = false; }
public Player getPlayer() {
return player;
}
@@ -74,4 +70,5 @@ public final class PlayerInjectEvent extends PacketEvent implements CancellableE
public boolean isAsync() {
return async;
}
}
@@ -1,75 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
public class PostPacketReceiveEvent extends PacketEvent implements PlayerEvent {
private final Player player;
private final Object packet;
public PostPacketReceiveEvent(final Player player, final Object packet) {
this.player = player;
this.packet = packet;
}
/**
* Get the packet sender
* @return player
*/
@Override
public Player getPlayer() {
return player;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
* @return packet id
*/
public byte getPacketId() {
return PacketType.Client.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
}
@@ -1,75 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.event.impl;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.eventtypes.PlayerEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import org.bukkit.entity.Player;
public class PostPacketSendEvent extends PacketEvent implements PlayerEvent {
private final Player player;
private final Object packet;
public PostPacketSendEvent(final Player player, final Object packet) {
this.player = player;
this.packet = packet;
}
/**
* Get the packet sender
* @return player
*/
@Override
public Player getPlayer() {
return player;
}
/**
* Get the packet's name (NMS packet class simple name).
* The class simple name is cached.
* @return Name of the packet
*/
public String getPacketName() {
return ClassUtil.getClassSimpleName(packet.getClass());
}
/**
* Get the raw packet object
* @return packet object
*/
public Object getNMSPacket() {
return packet;
}
/**
* Get the ID of the packet
* @return packet id
*/
public byte getPacketId() {
return PacketType.Server.packetIds.getOrDefault(packet.getClass(), (byte) -1);
}
}
@@ -26,7 +26,7 @@ package io.github.retrooper.packetevents.event.manager;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.annotation.PacketHandler;
import io.github.retrooper.packetevents.event.eventtypes.CancellableEvent;
import io.github.retrooper.packetevents.event.CancellableEvent;
import io.github.retrooper.packetevents.event.PacketEvent;
import io.github.retrooper.packetevents.event.PacketListener;
import io.github.retrooper.packetevents.event.priority.PacketEventPriority;
@@ -76,9 +76,6 @@ public final class EventManager {
public void registerListener(final PacketListener listener) {
final ConcurrentLinkedQueue<Method> methods = new ConcurrentLinkedQueue<>();
for (final Method m : listener.getClass().getDeclaredMethods()) {
if(!m.isAccessible()) {
m.setAccessible(true);
}
if (m.isAnnotationPresent(PacketHandler.class)
&& m.getParameterTypes().length == 1) {
methods.add(m);
@@ -26,13 +26,6 @@ package io.github.retrooper.packetevents.example;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.PacketListener;
import io.github.retrooper.packetevents.event.annotation.PacketHandler;
import io.github.retrooper.packetevents.event.impl.PacketReceiveEvent;
import io.github.retrooper.packetevents.event.impl.PacketSendEvent;
import io.github.retrooper.packetevents.event.impl.PlayerInjectEvent;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packetwrappers.out.animation.WrappedPacketOutAnimation;
import io.github.retrooper.packetevents.packetwrappers.out.explosion.WrappedPacketOutExplosion;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.plugin.java.JavaPlugin;
@@ -46,11 +39,11 @@ public class MainExample extends JavaPlugin implements PacketListener {
@Override
public void onEnable() {
PacketEvents.getSettings().injectAsync(true).ejectAsync(true)
.autoResolveClientProtocolVersion(true)
.backupServerVersion(ServerVersion.v_1_7_10).
useProtocolLibIfAvailable(true).checkForUpdates(true).injectEarly(true);
PacketEvents.getAPI().getEventManager().registerListener(this);
useProtocolLibIfAvailable(true).checkForUpdates(true);
PacketEvents.init(this);
PacketEvents.getAPI().getEventManager().registerListener(this);
}
@Override
@@ -0,0 +1,187 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.nettyhandler;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.impl.PacketReceiveEvent;
import io.github.retrooper.packetevents.event.impl.PacketSendEvent;
import io.github.retrooper.packetevents.event.impl.PlayerInjectEvent;
import io.github.retrooper.packetevents.event.impl.PlayerEjectEvent;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.entity.Player;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class NettyPacketHandler {
public static boolean v1_7_nettyMode = false;
private static final ExecutorService singleThreadedExecutor = Executors.newSingleThreadExecutor();
static {
try {
Class.forName("io.netty.channel.Channel");
} catch (ClassNotFoundException e) {
v1_7_nettyMode = true;
}
}
/**
* Synchronously inject a player
*
* @param player Target player to inject
*/
public static void injectPlayer(final Player player) {
try {
final PlayerInjectEvent injectEvent = new PlayerInjectEvent(player);
PacketEvents.getAPI().getEventManager().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
if (v1_7_nettyMode) {
NettyPacketHandler_7.injectPlayer(player);
} else {
NettyPacketHandler_8.injectPlayer(player);
}
}
} catch (Exception ignored) {
}
}
/**
* Asynchronously inject a player
*
* @param player
* @return {@link java.util.concurrent.Future}
*/
public static Future<?> injectPlayerAsync(final Player player) {
//Make sure we cache the channel SYNCHRONOUSLY
Object channel = NMSUtils.getChannel(player);
return singleThreadedExecutor.submit(() -> {
try {
final PlayerInjectEvent injectEvent = new PlayerInjectEvent(player, true);
PacketEvents.getAPI().getEventManager().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
if (v1_7_nettyMode) {
NettyPacketHandler_7.injectPlayer(player);
} else {
NettyPacketHandler_8.injectPlayer(player);
}
}
} catch (Exception ignored) {
}
});
}
/**
* Synchronously eject a player.
*
* @param player
*/
public static void ejectPlayer(final Player player) {
NMSUtils.channelCache.remove(player.getUniqueId());
try {
final PlayerEjectEvent uninjectEvent = new PlayerEjectEvent(player);
PacketEvents.getAPI().getEventManager().callEvent(uninjectEvent);
if (!uninjectEvent.isCancelled()) {
if (v1_7_nettyMode) {
NettyPacketHandler_7.ejectPlayer(player);
} else {
NettyPacketHandler_8.ejectPlayer(player);
}
}
} catch (Exception ignored) {
}
}
/**
* Asynchronously eject a player
*
* @param player
* @return {@link java.util.concurrent.Future}
*/
public static Future<?> ejectPlayerAsync(final Player player) {
NMSUtils.channelCache.remove(player.getUniqueId());
Future<?> f = singleThreadedExecutor.submit(() -> {
try {
final PlayerEjectEvent uninjectEvent = new PlayerEjectEvent(player, true);
PacketEvents.getAPI().getEventManager().callEvent(uninjectEvent);
if (!uninjectEvent.isCancelled()) {
if (v1_7_nettyMode) {
NettyPacketHandler_7.ejectPlayer(player);
} else {
NettyPacketHandler_8.ejectPlayer(player);
}
}
} catch (Exception ignored) {
}
});
return f;
}
/**
* This function is called each time the server plans to send a packet to the client.
*
* @param sender
* @param packet
* @return
*/
public static Object write(final Player sender, final Object packet) {
final PacketSendEvent packetSendEvent = new PacketSendEvent(sender, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetSendEvent);
if (!packetSendEvent.isCancelled()) {
return packet;
}
return null;
}
/**
* This function is called each time the server receives a packet from the client.
*
* @param receiver
* @param packet
* @return
*/
public static Object read(final Player receiver, final Object packet) {
final PacketReceiveEvent packetReceiveEvent = new PacketReceiveEvent(receiver, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetReceiveEvent);
if (!packetReceiveEvent.isCancelled()) {
return packet;
}
return null;
}
public static void sendPacket(Object channel, Object packet) {
if(v1_7_nettyMode) {
NettyPacketHandler_7.sendPacket(channel, packet);
}
else {
NettyPacketHandler_8.sendPacket(channel, packet);
}
}
}
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.netty;
package io.github.retrooper.packetevents.nettyhandler;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
@@ -31,36 +31,33 @@ import net.minecraft.util.io.netty.channel.ChannelDuplexHandler;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelPipeline;
import net.minecraft.util.io.netty.channel.ChannelPromise;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
final class NettyPacketManager_7 {
NettyPacketManager_7() {
final class NettyPacketHandler_7 {
}
/**
* Inject a player using 1.7.10's netty import location
* @param player
*/
public void injectPlayer(final Player player) {
public static void injectPlayer(final Player player) {
final ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.read(player, ctx.channel(), msg);
Object packet = NettyPacketHandler.read(player, msg);
if (packet == null) {
return;
}
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, packet);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.write(player, ctx.channel(),msg);
Object packet = NettyPacketHandler.write(player, msg);
if (packet == null) {
return;
}
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, packet);
}
};
final ChannelPipeline pipeline = ((Channel) NMSUtils.getChannel(player)).pipeline();
@@ -69,15 +66,15 @@ final class NettyPacketManager_7 {
/**
* Eject a player using 1.7.10 netty import location.
* @param player Target Player
* @param player
*/
public void ejectPlayer(final Player player) {
public static void ejectPlayer(final Player player) {
Channel channel = (Channel) NMSUtils.getChannelNoCache(player);
assert channel != null;
channel.pipeline().remove(PacketEvents.getHandlerName(player.getName()));
//Make sure we are removing the cache synchronously
}
public void sendPacket(Object rawChannel, Object packet) {
public static void sendPacket(Object rawChannel, Object packet) {
Channel channel = (Channel)rawChannel;
channel.pipeline().writeAndFlush(packet);
}
@@ -22,7 +22,7 @@
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.netty;
package io.github.retrooper.packetevents.nettyhandler;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
@@ -31,36 +31,32 @@ import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
final class NettyPacketManager_8 {
NettyPacketManager_8() {
}
final class NettyPacketHandler_8 {
/**
* Inject a player with 1.8+ netty import location.
* @param player
*/
public void injectPlayer(final Player player) {
public static void injectPlayer(final Player player) {
final ChannelDuplexHandler channelDuplexHandler = new ChannelDuplexHandler() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.read(player, ctx.channel(),msg);
Object packet = NettyPacketHandler.read(player, msg);
if (packet == null) {
return;
}
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, packet);
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
Object packet = PacketEvents.getAPI().packetManager.write(player, ctx.channel(),msg);
Object packet = NettyPacketHandler.write(player, msg);
if (packet == null) {
return;
}
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, packet);
}
};
final ChannelPipeline pipeline = ((Channel) NMSUtils.getChannel(player)).pipeline();
@@ -71,13 +67,20 @@ final class NettyPacketManager_8 {
* Eject a player with 1.8+ netty import location.
* @param player
*/
public void ejectPlayer(final Player player) {
public static void ejectPlayer(final Player player) {
final Channel channel = (Channel) NMSUtils.getChannelNoCache(player);
assert channel != null;
channel.pipeline().remove(PacketEvents.getHandlerName(player.getName()));
//Make sure we are removing the cache synchronously
Bukkit.getScheduler().runTask(PacketEvents.getPlugins().get(0), new Runnable() {
@Override
public void run() {
//Make sure we are removing the cache SYNCHRONOUSLY
NMSUtils.channelCache.remove(player.getUniqueId());
}
});
}
public void sendPacket(Object rawChannel, Object packet) {
public static void sendPacket(Object rawChannel, Object packet) {
Channel channel = (Channel)rawChannel;
channel.pipeline().writeAndFlush(packet);
}
@@ -1,266 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.impl.*;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.TinyProtocol;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.packetwrappers.login.in.WrappedPacketLoginHandshake;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.player.ClientVersion;
import io.github.retrooper.packetevents.utils.reflection.ClassUtil;
import io.github.retrooper.packetevents.utils.versionlookup.VersionLookupUtils;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.HashMap;
import java.util.UUID;
public class PacketManager {
private final Plugin plugin;
private final boolean tinyProtocolMode;
public final TinyProtocol tinyProtocol;
public final NettyPacketManager nettyProtocol;
private final HashMap<UUID, Long> keepAliveMap = new HashMap<>();
public PacketManager(Plugin plugin, boolean tinyProtocolMode) {
this.plugin = plugin;
this.tinyProtocolMode = tinyProtocolMode;
if (tinyProtocolMode) {
tinyProtocol = new TinyProtocol(plugin);
nettyProtocol = null;
} else {
tinyProtocol = null;
nettyProtocol = new NettyPacketManager(plugin);
}
}
public void injectPlayer(Player player) {
if (PacketEvents.getSettings().shouldInjectAsync()) {
injectPlayerAsync(player);
} else {
injectPlayerSync(player);
}
}
public void ejectPlayer(Player player) {
if (PacketEvents.getSettings().shouldEjectAsync()) {
ejectPlayerAsync(player);
} else {
ejectPlayerSync(player);
}
}
public void injectPlayerSync(Player player) {
PlayerInjectEvent injectEvent = new PlayerInjectEvent(player, false);
PacketEvents.getAPI().getEventManager().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
if (tinyProtocolMode) {
tinyProtocol.injectPlayer(player);
} else {
nettyProtocol.injectPlayer(player);
}
}
}
public void injectPlayerAsync(Player player) {
PlayerInjectEvent injectEvent = new PlayerInjectEvent(player, true);
PacketEvents.getAPI().getEventManager().callEvent(injectEvent);
if (!injectEvent.isCancelled()) {
if (tinyProtocolMode) {
tinyProtocol.injectPlayerAsync(player);
} else {
nettyProtocol.injectPlayerAsync(player);
}
}
}
public void ejectPlayerSync(Player player) {
PlayerEjectEvent ejectEvent = new PlayerEjectEvent(player, false);
PacketEvents.getAPI().getEventManager().callEvent(ejectEvent);
if (!ejectEvent.isCancelled()) {
keepAliveMap.remove(player.getUniqueId());
NMSUtils.channelCache.remove(player.getUniqueId());
if (tinyProtocolMode) {
tinyProtocol.ejectPlayer(player);
} else {
nettyProtocol.ejectPlayer(player);
}
}
}
public void ejectPlayerAsync(Player player) {
PlayerEjectEvent ejectEvent = new PlayerEjectEvent(player, true);
PacketEvents.getAPI().getEventManager().callEvent(ejectEvent);
if (!ejectEvent.isCancelled()) {
keepAliveMap.remove(player.getUniqueId());
NMSUtils.channelCache.remove(player.getUniqueId());
if (tinyProtocolMode) {
tinyProtocol.ejectPlayerAsync(player);
} else {
nettyProtocol.ejectPlayerAsync(player);
}
}
}
public void sendPacket(Object channel, Object packet) {
if (tinyProtocolMode) {
tinyProtocol.sendPacket(channel, packet);
} else {
nettyProtocol.sendPacket(channel, packet);
}
}
public Object read(Player player, Object channel, Object packet) {
switch (ClassUtil.getClassSimpleName(packet.getClass())) {
case "PacketHandshakingInSetProtocol":
case "PacketLoginInCustomPayload":
case "PacketLoginInStart":
case "PacketLoginInEncryptionBegin":
final PacketLoginEvent packetLoginEvent = new PacketLoginEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetLoginEvent);
interceptLogin(packetLoginEvent);
if (packetLoginEvent.isCancelled()) {
packet = null;
}
break;
case "PacketStatusInPing":
final PacketStatusEvent packetStatusEvent = new PacketStatusEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetStatusEvent);
interceptStatus(packetStatusEvent);
if (packetStatusEvent.isCancelled()) {
packet = null;
}
break;
default:
final PacketReceiveEvent packetReceiveEvent = new PacketReceiveEvent(player, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetReceiveEvent);
interceptRead(packetReceiveEvent);
if (packetReceiveEvent.isCancelled()) {
packet = null;
}
break;
}
return packet;
}
public Object write(Player player, Object channel, Object packet) {
switch (ClassUtil.getClassSimpleName(packet.getClass())) {
case "PacketLoginOutDisconnect":
case "PacketLoginOutEncryptionBegin":
case "PacketLoginOutSetCompression":
case "PacketLoginOutSuccess":
final PacketLoginEvent packetLoginEvent = new PacketLoginEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetLoginEvent);
interceptLogin(packetLoginEvent);
if (packetLoginEvent.isCancelled()) {
packet = null;
}
break;
case "PacketStatusOutPong":
final PacketStatusEvent packetStatusEvent = new PacketStatusEvent(channel, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetStatusEvent);
interceptStatus(packetStatusEvent);
if (packetStatusEvent.isCancelled()) {
packet = null;
}
break;
default:
final PacketSendEvent packetSendEvent = new PacketSendEvent(player, packet);
PacketEvents.getAPI().getEventManager().callEvent(packetSendEvent);
interceptWrite(packetSendEvent);
if (packetSendEvent.isCancelled()) {
packet = null;
}
break;
}
return packet;
}
public void postRead(Player player, Object packet) {
switch (ClassUtil.getClassSimpleName(packet.getClass())) {
case "PacketHandshakingInSetProtocol":
case "PacketLoginInCustomPayload":
case "PacketLoginInStart":
case "PacketLoginInEncryptionBegin":
case "PacketStatusInPing":
break;
default:
PacketEvents.getAPI().getEventManager().callEvent(new PostPacketReceiveEvent(player, packet));
break;
}
}
public void postWrite(Player player, Object packet) {
switch (ClassUtil.getClassSimpleName(packet.getClass())) {
case "PacketLoginOutDisconnect":
case "PacketLoginOutEncryptionBegin":
case "PacketLoginOutSetCompression":
case "PacketLoginOutSuccess":
case "PacketStatusOutPong":
break;
default:
PacketEvents.getAPI().getEventManager().callEvent(new PostPacketSendEvent(player, packet));
break;
}
}
private void interceptRead(PacketReceiveEvent event) {
if (event.getPacketId() == PacketType.Client.KEEP_ALIVE) {
UUID uuid = event.getPlayer().getUniqueId();
long timestamp = keepAliveMap.getOrDefault(uuid, event.getTimestamp());
long currentTime = event.getTimestamp();
long ping = currentTime - timestamp;
long smoothedPing = ((PacketEvents.getAPI().getPlayerUtils().getSmoothedPing(event.getPlayer()) * 3) + ping) / 4;
PacketEvents.getAPI().getPlayerUtils().playerPingMap.put(uuid, (short) ping);
PacketEvents.getAPI().getPlayerUtils().playerSmoothedPingMap.put(uuid, (short) smoothedPing);
}
}
private void interceptWrite(PacketSendEvent event) {
if (event.getPacketId() == PacketType.Server.KEEP_ALIVE) {
keepAliveMap.put(event.getPlayer().getUniqueId(), event.getTimestamp());
}
}
private void interceptLogin(PacketLoginEvent event) {
if (event.getPacketId() == PacketType.Login.HANDSHAKE) {
if (!VersionLookupUtils.isDependencyAvailable()) {
WrappedPacketLoginHandshake handshake = new WrappedPacketLoginHandshake(event.getNMSPacket());
int protocolVersion = handshake.getProtocolVersion();
ClientVersion version = ClientVersion.getClientVersion(protocolVersion);
PacketEvents.getAPI().getPlayerUtils().clientVersionsMap.put(event.getChannel(), version);
}
}
}
private void interceptStatus(PacketStatusEvent event) {
}
}
@@ -1,136 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.netty;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class NettyPacketManager {
public static boolean v1_7_nettyMode = false;
public static final ExecutorService
executorService =
Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors(), 64));
static {
try {
Class.forName("io.netty.channel.Channel");
} catch (ClassNotFoundException e) {
v1_7_nettyMode = true;
}
}
private Plugin plugin;
private Object npm;
public NettyPacketManager(Plugin plugin) {
this.plugin = plugin;
if (v1_7_nettyMode) {
npm = new NettyPacketManager_7();
} else {
npm = new NettyPacketManager_8();
}
}
/**
* Synchronously inject a player
*
* @param player Target player to inject
*/
public void injectPlayer(final Player player) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7)npm;
npm_7.injectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8)npm;
npm_8.injectPlayer(player);
}
}
/**
* Asynchronously inject a player
*
* @param player
*/
public void injectPlayerAsync(final Player player) {
//Redundant channel variable created just so we can cache it synchronously.
Object channel = NMSUtils.getChannel(player);
executorService.execute(() -> {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7)npm;
npm_7.injectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8)npm;
npm_8.injectPlayer(player);
}
});
}
/**
* Synchronously eject a player.
*
* @param player
*/
public void ejectPlayer(final Player player) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7)npm;
npm_7.ejectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8)npm;
npm_8.ejectPlayer(player);
}
}
/**
* Asynchronously eject a player
*
* @param player
*/
public void ejectPlayerAsync(final Player player) {
executorService.execute(() -> {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7)npm;
npm_7.ejectPlayer(player);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8)npm;
npm_8.ejectPlayer(player);
}
});
}
public void sendPacket(Object channel, Object packet) {
if (v1_7_nettyMode) {
NettyPacketManager_7 npm_7 = (NettyPacketManager_7)npm;
npm_7.sendPacket(channel, packet);
} else {
NettyPacketManager_8 npm_8 = (NettyPacketManager_8)npm;
npm_8.sendPacket(channel, packet);
}
}
}
@@ -1,376 +0,0 @@
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
/**
* An utility class that simplifies reflection in Bukkit plugins.
*
* @author Kristian
*/
public final class Reflection {
/**
* An interface for invoking a specific constructor.
*/
public interface ConstructorInvoker {
/**
* Invoke a constructor for a specific class.
*
* @param arguments - the arguments to pass to the constructor.
* @return The constructed object.
*/
Object invoke(Object... arguments);
}
/**
* An interface for invoking a specific method.
*/
public interface MethodInvoker {
/**
* Invoke a method on a specific target object.
*
* @param target - the target object, or NULL for a static method.
* @param arguments - the arguments to pass to the method.
* @return The return value, or NULL if is void.
*/
Object invoke(Object target, Object... arguments);
}
/**
* An interface for retrieving the field content.
*
* @param <T> - field type.
*/
public interface FieldAccessor<T> {
/**
* Retrieve the content of a field.
*
* @param target - the target object, or NULL for a static field.
* @return The value of the field.
*/
T get(Object target);
/**
* Set the content of a field.
*
* @param target - the target object, or NULL for a static field.
* @param value - the new value of the field.
*/
void set(Object target, Object value);
/**
* Determine if the given object has this field.
*
* @param target - the object to test.
* @return TRUE if it does, FALSE otherwise.
*/
boolean hasField(Object target);
}
// Deduce the net.minecraft.server.v* package
private static String OBC_PREFIX = Bukkit.getServer().getClass().getPackage().getName();
private static String NMS_PREFIX = OBC_PREFIX.replace("org.bukkit.craftbukkit", "net.minecraft.server");
private static String VERSION = OBC_PREFIX.replace("org.bukkit.craftbukkit", "").replace(".", "");
// Variable replacement
private static Pattern MATCH_VARIABLE = Pattern.compile("\\{([^\\}]+)\\}");
private Reflection() {
// Seal class
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param target - the target type.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType) {
return getField(target, name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, String name, Class<T> fieldType) {
return getField(getClass(className), name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param target - the target type.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index) {
return getField(target, null, fieldType, index);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, Class<T> fieldType, int index) {
return getField(getClass(className), fieldType, index);
}
// Common method
private static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType, int index) {
for (final Field field : target.getDeclaredFields()) {
if ((name == null || field.getName().equals(name)) && fieldType.isAssignableFrom(field.getType()) && index-- <= 0) {
field.setAccessible(true);
// A function for retrieving a specific field value
return new FieldAccessor<T>() {
@Override
@SuppressWarnings("unchecked")
public T get(Object target) {
try {
return (T) field.get(target);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access reflection.", e);
}
}
@Override
public void set(Object target, Object value) {
try {
field.set(target, value);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot access reflection.", e);
}
}
@Override
public boolean hasField(Object target) {
// target instanceof DeclaringClass
return field.getDeclaringClass().isAssignableFrom(target.getClass());
}
};
}
}
// Search in parent classes
if (target.getSuperclass() != null)
return getField(target.getSuperclass(), name, fieldType, index);
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(String className, String methodName, Class<?>... params) {
return getTypedMethod(getClass(className), methodName, null, params);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(Class<?> clazz, String methodName, Class<?>... params) {
return getTypedMethod(clazz, methodName, null, params);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param returnType - the expected return type, or NULL to ignore.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
for (final Method method : clazz.getDeclaredMethods()) {
if ((methodName == null || method.getName().equals(methodName))
&& (returnType == null || method.getReturnType().equals(returnType))
&& Arrays.equals(method.getParameterTypes(), params)) {
method.setAccessible(true);
return new MethodInvoker() {
@Override
public Object invoke(Object target, Object... arguments) {
try {
return method.invoke(target, arguments);
} catch (Exception e) {
throw new RuntimeException("Cannot invoke method " + method, e);
}
}
};
}
}
// Search in every superclass
if (clazz.getSuperclass() != null)
return getMethod(clazz.getSuperclass(), methodName, params);
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(String className, Class<?>... params) {
return getConstructor(getClass(className), params);
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(Class<?> clazz, Class<?>... params) {
for (final Constructor<?> constructor : clazz.getDeclaredConstructors()) {
if (Arrays.equals(constructor.getParameterTypes(), params)) {
constructor.setAccessible(true);
return new ConstructorInvoker() {
@Override
public Object invoke(Object... arguments) {
try {
return constructor.newInstance(arguments);
} catch (Exception e) {
throw new RuntimeException("Cannot invoke constructor " + constructor, e);
}
}
};
}
}
throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
}
/**
* Retrieve a class from its full name, without knowing its type on compile time.
* <p>
* This is useful when looking up fields by a NMS or OBC type.
* <p>
*
* See {@link #getClass()} for more information.
* @param lookupName - the class name with variables.
* @return The class.
*/
public static Class<Object> getUntypedClass(String lookupName) {
@SuppressWarnings({ "rawtypes", "unchecked" })
Class<Object> clazz = (Class) getClass(lookupName);
return clazz;
}
public static Class<?> getClass(String lookupName) {
return getCanonicalClass(expandVariables(lookupName));
}
/**
* Retrieve a class in the net.minecraft.server.VERSION.* package.
*
* @param name - the name of the class, excluding the package.
* @throws IllegalArgumentException If the class doesn't exist.
*/
public static Class<?> getMinecraftClass(String name) {
return getCanonicalClass(NMS_PREFIX + "." + name);
}
/**
* Retrieve a class in the org.bukkit.craftbukkit.VERSION.* package.
*
* @param name - the name of the class, excluding the package.
* @throws IllegalArgumentException If the class doesn't exist.
*/
public static Class<?> getCraftBukkitClass(String name) {
return getCanonicalClass(OBC_PREFIX + "." + name);
}
/**
* Retrieve a class by its canonical name.
*
* @param canonicalName - the canonical name.
* @return The class.
*/
private static Class<?> getCanonicalClass(String canonicalName) {
try {
return Class.forName(canonicalName);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Cannot find " + canonicalName, e);
}
}
/**
* Expand variables such as "{nms}" and "{obc}" to their corresponding packages.
*
* @param name - the full name of the class.
* @return The expanded string.
*/
private static String expandVariables(String name) {
StringBuffer output = new StringBuffer();
Matcher matcher = MATCH_VARIABLE.matcher(name);
while (matcher.find()) {
String variable = matcher.group(1);
String replacement = "";
// Expand all detected variables
if ("nms".equalsIgnoreCase(variable))
replacement = NMS_PREFIX;
else if ("obc".equalsIgnoreCase(variable))
replacement = OBC_PREFIX;
else if ("version".equalsIgnoreCase(variable))
replacement = VERSION;
else
throw new IllegalArgumentException("Unknown variable: " + variable);
// Assume the expanded variables are all packages, and append a dot
if (replacement.length() > 0 && matcher.end() < name.length() && name.charAt(matcher.end()) != '.')
replacement += ".";
matcher.appendReplacement(output, Matcher.quoteReplacement(replacement));
}
matcher.appendTail(output);
return output.toString();
}
}
@@ -1,120 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
public class TinyProtocol {
private final Object tinyProt;
public TinyProtocol(Plugin plugin) {
if (NettyPacketManager.v1_7_nettyMode) {
tinyProt = new TinyProtocol7(plugin);
} else {
tinyProt = new TinyProtocol8(plugin);
}
}
public void injectPlayer(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.injectPlayer(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.injectPlayer(player);
}
}
public void injectPlayerAsync(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.injectPlayerAsync(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.injectPlayerAsync(player);
}
}
public void ejectPlayer(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.uninjectPlayer(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.uninjectPlayer(player);
}
}
public void ejectPlayerAsync(Player player) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.uninjectPlayerAsync(player);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.uninjectPlayerAsync(player);
}
}
public void sendPacket(Object channel, Object packet) {
if (!NettyPacketManager.v1_7_nettyMode) {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
tp8.sendPacket(channel, packet);
} else {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
tp7.sendPacket(channel, packet);
}
}
public Object read(Player player, Object channel, Object packet) {
return PacketEvents.getAPI().packetManager.read(player, channel, packet);
}
public Object write(Player player, Object channel, Object packet) {
return PacketEvents.getAPI().packetManager.write(player, channel, packet);
}
public Object getChannel(Player player) {
if (NettyPacketManager.v1_7_nettyMode) {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
return tp7.getChannel(player);
} else {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
return tp8.getChannel(player);
}
}
public boolean canInject(Player player) {
if (NettyPacketManager.v1_7_nettyMode) {
TinyProtocol7 tp7 = (TinyProtocol7) tinyProt;
return !tp7.uninjectedChannels.contains(getChannel(player));
} else {
TinyProtocol8 tp8 = (TinyProtocol8) tinyProt;
return !tp8.uninjectedChannels.contains(getChannel(player));
}
}
}
@@ -1,551 +0,0 @@
/*
* This file is part of Hawk Anticheat.
* Copyright (C) 2018 Hawk Development Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.FieldAccessor;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.MethodInvoker;
import net.minecraft.util.com.google.common.collect.Lists;
import net.minecraft.util.com.google.common.collect.MapMaker;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.io.netty.channel.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* Represents a very tiny alternative to ProtocolLib.
* <p>
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
*
* @author Kristian
*/
//BROKEN: NPEs when player joins while server is starting, and using PlayerJoinEvent instead will cause NPE for protocol version lookup.
//Protocol version number lookup method from DeprecatedLuke's version of TinyProtocol
public class TinyProtocol7 {
private static final AtomicInteger ID = new AtomicInteger();
// Used in order to lookup a channel
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
private static final FieldAccessor<Object> getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class);
private static final FieldAccessor<Object> getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class);
private static final FieldAccessor<Channel> getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0);
// Looking up ServerConnection
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer");
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection");
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
// Packets we have to intercept
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
private static final Class<?> PACKET_HANDSHAKING_IN_SET_PROTOCOL = Reflection.getMinecraftClass("PacketHandshakingInSetProtocol");
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
// Speedup channel/protocol lookup
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
private Listener listener;
// Channels that have already been removed
public Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
// List of network markers
private List<Object> networkManagers;
// Injected channel handlers
private List<Channel> serverChannels = Lists.newArrayList();
private ChannelInboundHandlerAdapter serverChannelHandler;
private ChannelInitializer<Channel> beginInitProtocol;
private ChannelInitializer<Channel> endInitProtocol;
// Current handler name
private String handlerName;
protected volatile boolean closed;
protected Plugin plugin;
/**
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
* <p>
* You can construct multiple instances per plugin.
*
* @param plugin - the plugin.
*/
public TinyProtocol7(final Plugin plugin) {
this.plugin = plugin;
// Compute handler name
this.handlerName = getHandlerName();
try {
registerChannelHandler();
registerPlayers(plugin);
} catch (IllegalArgumentException ex) {
// Damn you, late bind
plugin.getLogger().info("Delaying server channel injection due to late bind.");
new BukkitRunnable() {
@Override
public void run() {
registerChannelHandler();
registerPlayers(plugin);
plugin.getLogger().info("Late bind injection successful.");
}
}.runTask(plugin);
}
}
private void createServerChannelHandler() {
// Handle connected channels
endInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
// Stop injecting channels
if (!closed) {
channel.eventLoop().submit(() -> injectChannelInternal(channel));
}
}
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e);
}
}
};
// This is executed before Minecraft's channel handler
beginInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(endInitProtocol);
}
};
serverChannelHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg;
// Prepare to initialize ths channel
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
}
@SuppressWarnings("unchecked")
private void registerChannelHandler() {
Object mcServer = getMinecraftServer.get(Bukkit.getServer());
Object serverConnection = getServerConnection.get(mcServer);
boolean looking = true;
// We need to synchronize against this list
networkManagers = (List<Object>) getNetworkMarkers.invoke(null, serverConnection);
createServerChannelHandler();
// Find the correct list, or implicitly throw an exception
for (int i = 0; looking; i++) {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) {
if (!(item instanceof ChannelFuture))
break;
// Channel future that contains the server connection
Channel serverChannel = ((ChannelFuture) item).channel();
serverChannels.add(serverChannel);
serverChannel.pipeline().addFirst(serverChannelHandler);
looking = false;
}
}
}
private void unregisterChannelHandler() {
if (serverChannelHandler == null)
return;
for (Channel serverChannel : serverChannels) {
final ChannelPipeline pipeline = serverChannel.pipeline();
// Remove channel handler
serverChannel.eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
pipeline.remove(serverChannelHandler);
} catch (NoSuchElementException e) {
// That's fine
}
}
});
}
}
private void registerPlayers(Plugin plugin) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
injectPlayer(player);
}
}
/**
* Invoked when the server is starting to send a packet to a player.
* <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 PacketEvents.getAPI().packetManager.write(receiver, channel, packet);
}
/**
* Invoked when the server has received a packet from a given player.
* <p>
* 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.
* @param channel - channel that received the packet. Never NULL.
* @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 PacketEvents.getAPI().packetManager.read(sender, channel,packet);
}
/**
* 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 packet - the packet to send.
*/
public void sendPacket(Player player, Object packet) {
sendPacket(getChannel(player), packet);
}
/**
* 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 packet - the packet to send.
*/
public void sendPacket(Channel channel, Object packet) {
channel.pipeline().writeAndFlush(packet);
}
public void sendPacket(Object channel, Object packet) {
sendPacket((Channel) channel, packet);
}
/**
* 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 packet - the packet that will be received by the server.
*/
public void receivePacket(Player player, Object packet) {
receivePacket(getChannel(player), packet);
}
/**
* 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 packet - the packet that will be received by the server.
*/
public void receivePacket(Channel channel, Object packet) {
channel.pipeline().context("encoder").fireChannelRead(packet);
}
/**
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
* <p>
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
*
* @return A unique channel handler name.
*/
protected String getHandlerName() {
return "PacketEvents-" + ID.incrementAndGet();
}
/**
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
* <p>
* This will automatically be called when a player has logged in.
*
* @param player - the player to inject.
*/
public void injectPlayer(Player player) {
injectChannelInternal(getChannel(player)).player = player;
}
public void injectPlayerAsync(Player player) {
Channel channel = getChannel(player);
injectChannelInternalAsync(channel).player = player;
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
*/
public void injectChannel(Channel channel) {
injectChannelInternal(channel);
}
public void injectChannelAsync(Channel channel) {
injectChannelInternalAsync(channel);
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
* @return The packet interceptor.
*/
private PacketInterceptor injectChannelInternal(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
channel.pipeline().addBefore("packet_handler", handlerName, interceptor);
uninjectedChannels.remove(channel);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
private PacketInterceptor injectChannelInternalAsync(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
final PacketInterceptor pi = interceptor;
NettyPacketManager.executorService.execute(new Runnable() {
@Override
public void run() {
channel.pipeline().addBefore("packet_handler", handlerName, pi);
}
});
uninjectedChannels.remove(channel);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
/**
* Retrieve the Netty channel associated with a player. This is cached.
*
* @param player - the player.
* @return The Netty channel.
*/
public Channel getChannel(Player player) {
Channel channel = channelLookup.get(player.getName());
// Lookup channel again
if (channel == null) {
Object connection = getConnection.get(getPlayerHandle.invoke(player));
Object manager = getManager.get(connection);
channelLookup.put(player.getName(), channel = getChannel.get(manager));
}
return channel;
}
/**
* Uninject a specific player.
*
* @param player - the injected player.
*/
public void uninjectPlayer(Player player) {
uninjectChannel(getChannel(player));
}
public void uninjectPlayerAsync(Player player) {
Channel channel = getChannel(player);
uninjectChannelAsync(channel);
}
/**
* Uninject a specific channel.
* <p>
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
*
* @param channel - the injected channel.
*/
public void uninjectChannel(final Channel channel) {
// No need to guard against this if we're closing
if (!closed) {
uninjectedChannels.add(channel);
}
// See ChannelInjector in ProtocolLib, line 590
channel.pipeline().remove(handlerName);
}
public void uninjectChannelAsync(Channel channel) {
// No need to guard against this if we're closing
if (!closed) {
uninjectedChannels.add(channel);
}
// See ChannelInjector in ProtocolLib, line 590
NettyPacketManager.executorService.execute(new Runnable() {
@Override
public void run() {
channel.pipeline().remove(handlerName);
}
});
}
/**
* Determine if the given player has been injected by TinyProtocol.
*
* @param player - the player.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Player player) {
return hasInjected(getChannel(player));
}
/**
* Determine if the given channel has been injected by TinyProtocol.
*
* @param channel - the channel.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Channel channel) {
return channel.pipeline().get(handlerName) != null;
}
/**
* Cease listening for packets. This is called automatically when your plugin is disabled.
*/
public final void close() {
if (!closed) {
closed = true;
// Remove our handlers
for (Player player : plugin.getServer().getOnlinePlayers()) {
uninjectPlayer(player);
}
// Clean up Bukkit
HandlerList.unregisterAll(listener);
unregisterChannelHandler();
}
}
/**
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
*
* @author Kristian
*/
private final class PacketInterceptor extends ChannelDuplexHandler {
// Updated by the login event
public volatile Player player;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Intercept channel
final Channel channel = ctx.channel();
handleLoginStart(channel, msg);
try {
msg = onPacketInAsync(player, channel, msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
}
if (msg != null) {
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, msg);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
try {
msg = onPacketOutAsync(player, ctx.channel(), msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
}
if (msg != null) {
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, msg);
}
}
private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
GameProfile profile = getGameProfile.get(packet);
channelLookup.put(profile.getName(), channel);
}
}
}
}
@@ -1,558 +0,0 @@
/*
* This file is part of Hawk Anticheat.
* Copyright (C) 2018 Hawk Development Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package io.github.retrooper.packetevents.packetmanager.tinyprotocol;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.mojang.authlib.GameProfile;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.FieldAccessor;
import io.github.retrooper.packetevents.packetmanager.tinyprotocol.Reflection.MethodInvoker;
import io.netty.channel.*;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.server.PluginDisableEvent;
import org.bukkit.plugin.Plugin;
import org.bukkit.scheduler.BukkitRunnable;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
/**
* Represents a very tiny alternative to ProtocolLib.
* <p>
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
*
* @author Kristian
*/
//BROKEN: NPEs when player joins while server is starting, and using PlayerJoinEvent instead will cause NPE for protocol version lookup.
//Protocol version number lookup method from DeprecatedLuke's version of TinyProtocol
public class TinyProtocol8 {
private static final AtomicInteger ID = new AtomicInteger();
// Used in order to lookup a channel
private static final MethodInvoker getPlayerHandle = Reflection.getMethod("{obc}.entity.CraftPlayer", "getHandle");
private static final FieldAccessor<Object> getConnection = Reflection.getField("{nms}.EntityPlayer", "playerConnection", Object.class);
private static final FieldAccessor<Object> getManager = Reflection.getField("{nms}.PlayerConnection", "networkManager", Object.class);
private static final FieldAccessor<Channel> getChannel = Reflection.getField("{nms}.NetworkManager", Channel.class, 0);
// Looking up ServerConnection
private static final Class<Object> minecraftServerClass = Reflection.getUntypedClass("{nms}.MinecraftServer");
private static final Class<Object> serverConnectionClass = Reflection.getUntypedClass("{nms}.ServerConnection");
private static final FieldAccessor<Object> getMinecraftServer = Reflection.getField("{obc}.CraftServer", minecraftServerClass, 0);
private static final FieldAccessor<Object> getServerConnection = Reflection.getField(minecraftServerClass, serverConnectionClass, 0);
private static final MethodInvoker getNetworkMarkers = Reflection.getTypedMethod(serverConnectionClass, null, List.class, serverConnectionClass);
// Packets we have to intercept
private static final Class<?> PACKET_LOGIN_IN_START = Reflection.getMinecraftClass("PacketLoginInStart");
private static final Class<?> PACKET_HANDSHAKING_IN_SET_PROTOCOL = Reflection.getMinecraftClass("PacketHandshakingInSetProtocol");
private static final FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
private static final FieldAccessor<Integer> protocolId = Reflection.getField(PACKET_HANDSHAKING_IN_SET_PROTOCOL, int.class, 0);
private static final FieldAccessor<Enum> protocolType = Reflection.getField(PACKET_HANDSHAKING_IN_SET_PROTOCOL, Enum.class, 0);
// Speedup channel/protocol lookup
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
private Listener listener;
// Channels that have already been removed
public Set<Channel> uninjectedChannels = Collections.newSetFromMap(new MapMaker().weakKeys().<Channel, Boolean>makeMap());
// List of network markers
private List<Object> networkManagers;
// Injected channel handlers
private List<Channel> serverChannels = Lists.newArrayList();
private ChannelInboundHandlerAdapter serverChannelHandler;
private ChannelInitializer<Channel> beginInitProtocol;
private ChannelInitializer<Channel> endInitProtocol;
// Current handler name
private String handlerName;
protected volatile boolean closed;
protected Plugin plugin;
/**
* Construct a new instance of TinyProtocol, and start intercepting packets for all connected clients and future clients.
* <p>
* You can construct multiple instances per plugin.
*
* @param plugin - the plugin.
*/
public TinyProtocol8(final Plugin plugin) {
this.plugin = plugin;
// Compute handler name
this.handlerName = getHandlerName();
try {
registerChannelHandler();
registerPlayers(plugin);
} catch (IllegalArgumentException ex) {
// Damn you, late bind
plugin.getLogger().info("Delaying server channel injection due to late bind.");
new BukkitRunnable() {
@Override
public void run() {
registerChannelHandler();
registerPlayers(plugin);
plugin.getLogger().info("Late bind injection successful.");
}
}.runTask(plugin);
}
}
private void createServerChannelHandler() {
// Handle connected channels
endInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
// Stop injecting channels
if (!closed) {
channel.eventLoop().submit(() -> injectChannelInternal(channel));
}
}
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e);
}
}
};
// This is executed before Minecraft's channel handler
beginInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
channel.pipeline().addLast(endInitProtocol);
}
};
serverChannelHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel channel = (Channel) msg;
// Prepare to initialize ths channel
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
}
/**
* Register bukkit events.
*/
@SuppressWarnings("unchecked")
private void registerChannelHandler() {
Object mcServer = getMinecraftServer.get(Bukkit.getServer());
Object serverConnection = getServerConnection.get(mcServer);
boolean looking = true;
// We need to synchronize against this list
networkManagers = (List<Object>) getNetworkMarkers.invoke(null, serverConnection);
createServerChannelHandler();
// Find the correct list, or implicitly throw an exception
for (int i = 0; looking; i++) {
List<Object> list = Reflection.getField(serverConnection.getClass(), List.class, i).get(serverConnection);
for (Object item : list) {
if (!(item instanceof ChannelFuture))
break;
// Channel future that contains the server connection
Channel serverChannel = ((ChannelFuture) item).channel();
serverChannels.add(serverChannel);
serverChannel.pipeline().addFirst(serverChannelHandler);
looking = false;
}
}
}
private void unregisterChannelHandler() {
if (serverChannelHandler == null)
return;
for (Channel serverChannel : serverChannels) {
final ChannelPipeline pipeline = serverChannel.pipeline();
// Remove channel handler
serverChannel.eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
pipeline.remove(serverChannelHandler);
} catch (NoSuchElementException e) {
// That's fine
}
}
});
}
}
private void registerPlayers(Plugin plugin) {
for (Player player : plugin.getServer().getOnlinePlayers()) {
injectPlayer(player);
}
}
/**
* Invoked when the server is starting to send a packet to a player.
* <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 PacketEvents.getAPI().packetManager.write(receiver, channel, packet);
}
/**
* Invoked when the server has received a packet from a given player.
* <p>
* 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.
* @param channel - channel that received the packet. Never NULL.
* @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 PacketEvents.getAPI().packetManager.read(sender, channel, packet);
}
/**
* 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 packet - the packet to send.
*/
public void sendPacket(Player player, Object packet) {
sendPacket(getChannel(player), packet);
}
/**
* 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 packet - the packet to send.
*/
public void sendPacket(Channel channel, Object packet) {
channel.pipeline().writeAndFlush(packet);
}
public void sendPacket(Object channel, Object packet) {
sendPacket((Channel) channel, packet);
}
/**
* 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 packet - the packet that will be received by the server.
*/
public void receivePacket(Player player, Object packet) {
receivePacket(getChannel(player), packet);
}
/**
* 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 packet - the packet that will be received by the server.
*/
public void receivePacket(Channel channel, Object packet) {
channel.pipeline().context("encoder").fireChannelRead(packet);
}
/**
* Retrieve the name of the channel injector, default implementation is "tiny-" + plugin name + "-" + a unique ID.
* <p>
* Note that this method will only be invoked once. It is no longer necessary to override this to support multiple instances.
*
* @return A unique channel handler name.
*/
protected String getHandlerName() {
return "PacketEvents-" + ID.incrementAndGet();
}
/**
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
* <p>
* This will automatically be called when a player has logged in.
*
* @param player - the player to inject.
*/
public void injectPlayer(Player player) {
injectChannelInternal(getChannel(player)).player = player;
}
public void injectPlayerAsync(Player player) {
Channel channel = getChannel(player);
injectChannelInternalAsync(channel).player = player;
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
*/
public void injectChannel(Channel channel) {
injectChannelInternal(channel);
}
public void injectChannelAsync(Channel channel) {
injectChannelInternalAsync(channel);
}
/**
* Add a custom channel handler to the given channel.
*
* @param channel - the channel to inject.
* @return The packet interceptor.
*/
private PacketInterceptor injectChannelInternal(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
channel.pipeline().addBefore("packet_handler", handlerName, interceptor);
uninjectedChannels.remove(channel);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
private PacketInterceptor injectChannelInternalAsync(Channel channel) {
try {
PacketInterceptor interceptor = (PacketInterceptor) channel.pipeline().get(handlerName);
// Inject our packet interceptor
if (interceptor == null) {
interceptor = new PacketInterceptor();
final PacketInterceptor pi = interceptor;
NettyPacketManager.executorService.execute(new Runnable() {
@Override
public void run() {
channel.pipeline().addBefore("packet_handler", handlerName, pi);
}
});
uninjectedChannels.remove(channel);
}
return interceptor;
} catch (IllegalArgumentException e) {
// Try again
return (PacketInterceptor) channel.pipeline().get(handlerName);
}
}
/**
* Retrieve the Netty channel associated with a player. This is cached.
*
* @param player - the player.
* @return The Netty channel.
*/
public Channel getChannel(Player player) {
Channel channel = channelLookup.get(player.getName());
// Lookup channel again
if (channel == null) {
Object connection = getConnection.get(getPlayerHandle.invoke(player));
Object manager = getManager.get(connection);
channelLookup.put(player.getName(), channel = getChannel.get(manager));
}
return channel;
}
/**
* Uninject a specific player.
*
* @param player - the injected player.
*/
public void uninjectPlayer(Player player) {
uninjectChannel(getChannel(player));
}
public void uninjectPlayerAsync(Player player) {
Channel channel = getChannel(player);
uninjectChannelAsync(channel);
}
/**
* Uninject a specific channel.
* <p>
* This will also disable the automatic channel injection that occurs when a player has properly logged in.
*
* @param channel - the injected channel.
*/
public void uninjectChannel(final Channel channel) {
// No need to guard against this if we're closing
if (!closed) {
uninjectedChannels.add(channel);
}
// See ChannelInjector in ProtocolLib, line 590
channel.pipeline().remove(handlerName);
}
public void uninjectChannelAsync(Channel channel) {
// No need to guard against this if we're closing
if (!closed) {
uninjectedChannels.add(channel);
}
// See ChannelInjector in ProtocolLib, line 590
NettyPacketManager.executorService.execute(new Runnable() {
@Override
public void run() {
channel.pipeline().remove(handlerName);
}
});
}
/**
* Determine if the given player has been injected by TinyProtocol.
*
* @param player - the player.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Player player) {
return hasInjected(getChannel(player));
}
/**
* Determine if the given channel has been injected by TinyProtocol.
*
* @param channel - the channel.
* @return TRUE if it is, FALSE otherwise.
*/
public boolean hasInjected(Channel channel) {
return channel.pipeline().get(handlerName) != null;
}
/**
* Cease listening for packets. This is called automatically when your plugin is disabled.
*/
public final void close() {
if (!closed) {
closed = true;
// Remove our handlers
for (Player player : plugin.getServer().getOnlinePlayers()) {
uninjectPlayer(player);
}
// Clean up Bukkit
HandlerList.unregisterAll(listener);
unregisterChannelHandler();
}
}
/**
* Channel handler that is inserted into the player's channel pipeline, allowing us to intercept sent and received packets.
*
* @author Kristian
*/
private final class PacketInterceptor extends ChannelDuplexHandler {
// Updated by the login event
public volatile Player player;
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Intercept channel
final Channel channel = ctx.channel();
handleLoginStart(channel, msg);
try {
msg = onPacketInAsync(player, channel, msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error in onPacketInAsync().", e);
}
if (msg != null) {
super.channelRead(ctx, msg);
PacketEvents.getAPI().packetManager.postRead(player, msg);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
try {
msg = onPacketOutAsync(player, ctx.channel(), msg);
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Error in onPacketOutAsync().", e);
}
if (msg != null) {
super.write(ctx, msg, promise);
PacketEvents.getAPI().packetManager.postWrite(player, msg);
}
}
private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
GameProfile profile = getGameProfile.get(packet);
channelLookup.put(profile.getName(), channel);
}
}
}
}
@@ -28,35 +28,8 @@ import java.util.HashMap;
import java.util.Map;
public class PacketType {
public static class Status {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final byte PING = 0, PONG = 1;
public static void init() {
packetIds.put(PacketTypeClasses.Status.PING, PING);
packetIds.put(PacketTypeClasses.Status.PONG, PONG);
}
}
public static class Login {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final byte HANDSHAKE = 0,
IN_CUSTOM_PAYLOAD = 1, OUT_CUSTOM_PAYLOAD = 2,IN_START = 3, IN_ENCRYPTION_BEGIN = 4,
DISCONNECT = 5, OUT_ENCRYPTION_BEGIN = 6, OUT_SUCCESS = 7;
public static void init() {
packetIds.put(PacketTypeClasses.Login.HANDSHAKE, HANDSHAKE);
packetIds.put(PacketTypeClasses.Login.IN_CUSTOM_PAYLOAD, IN_CUSTOM_PAYLOAD);
packetIds.put(PacketTypeClasses.Login.OUT_CUSTOM_PAYLOAD, OUT_CUSTOM_PAYLOAD);
packetIds.put(PacketTypeClasses.Login.IN_START, IN_START);
packetIds.put(PacketTypeClasses.Login.IN_ENCRYPTION_BEGIN, IN_ENCRYPTION_BEGIN);
packetIds.put(PacketTypeClasses.Login.DISCONNECT, DISCONNECT);
packetIds.put(PacketTypeClasses.Login.OUT_ENCRYPTION_BEGIN, OUT_ENCRYPTION_BEGIN);
packetIds.put(PacketTypeClasses.Login.OUT_SUCCESS, OUT_SUCCESS);
}
}
public static class Client {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final Map<Class<?>, Byte> packetIds = new HashMap<Class<?>, Byte>();
public static final byte TELEPORT_ACCEPT = 0,
TILE_NBT_QUERY = 1, DIFFICULTY_CHANGE = 2, CHAT = 3, CLIENT_COMMAND = 4,
SETTINGS = 5, TAB_COMPLETE = 6, TRANSACTION = 7, ENCHANT_ITEM = 8,
@@ -124,7 +97,6 @@ public class PacketType {
public static class Util {
/**
* Is the packet an instance of the PacketPlayInFlying packet?
*
* @param packetID
* @return packetID == FLYING or POSITION or POSITION_LOOK or LOOK
*/
@@ -138,7 +110,7 @@ public class PacketType {
}
public static class Server {
public static final Map<Class<?>, Byte> packetIds = new HashMap<>();
public static final Map<Class<?>, Byte> packetIds = new HashMap<Class<?>, Byte>();
public static final byte SPAWN_ENTITY = 0, SPAWN_ENTITY_EXPERIENCE_ORB = 1, SPAWN_ENTITY_WEATHER = 2, SPAWN_ENTITY_LIVING = 3,
SPAWN_ENTITY_PAINTING = 4, SPAWN_ENTITY_SPAWN = 5, ANIMATION = 6, STATISTIC = 7,
BLOCK_BREAK = 8, BLOCK_BREAK_ANIMATION = 9, TILE_ENTITY_DATA = 10, BLOCK_ACTION = 11,
@@ -265,7 +237,6 @@ public class PacketType {
public static class Util {
/**
* Is the packet an instance of the PacketPlayOutEntity packet?
*
* @param packetID
* @return packetID == ENTITY or REL_ENTITY_MOVE or REL_ENTITY_MOVE_LOOK or ENTITY_LOOK
*/
@@ -24,38 +24,11 @@
package io.github.retrooper.packetevents.packettype;
import io.github.retrooper.packetevents.packettype.PacketType;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.SubclassUtil;
public class PacketTypeClasses {
public static class Status {
public static Class<?> PING, PONG;
public static void load() {
PING = NMSUtils.getNMSClassWithoutException("PacketStatusInPing");
PONG = NMSUtils.getNMSClassWithoutException("PacketStatusOutPong");
PacketType.Status.init();
}
}
public static class Login {
public static Class<?> HANDSHAKE,
IN_CUSTOM_PAYLOAD, OUT_CUSTOM_PAYLOAD,IN_START, IN_ENCRYPTION_BEGIN,
DISCONNECT, OUT_ENCRYPTION_BEGIN, OUT_SUCCESS;
public static void load() {
HANDSHAKE = NMSUtils.getNMSClassWithoutException("PacketHandshakingInSetProtocol");
//In and Out custom payload login packets have been here since AROUND 1.13.2?
IN_CUSTOM_PAYLOAD = NMSUtils.getNMSClassWithoutException("PacketLoginInCustomPayload");
OUT_CUSTOM_PAYLOAD = NMSUtils.getNMSClassWithoutException("PacketLoginOutCustomPayload");
IN_START = NMSUtils.getNMSClassWithoutException("PacketLoginInStart");
IN_ENCRYPTION_BEGIN = NMSUtils.getNMSClassWithoutException("PacketLoginInEncryptionBegin");
DISCONNECT = NMSUtils.getNMSClassWithoutException("PacketLoginOutDisconnect");
OUT_ENCRYPTION_BEGIN = NMSUtils.getNMSClassWithoutException("PacketLoginOutEncryptionBegin");
OUT_SUCCESS = NMSUtils.getNMSClassWithoutException("PacketLoginOutSuccess");
PacketType.Login.init();
}
}
public static class Client {
private static final String c = "PacketPlayIn";
public static Class<?> FLYING, POSITION, POSITION_LOOK, LOOK, CLIENT_COMMAND,
@@ -134,16 +107,17 @@ public class PacketTypeClasses {
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//Block place
try {
BLOCK_PLACE = NMSUtils.getNMSClass(c + "BlockPlace");
} catch (ClassNotFoundException e) {
}
try {
USE_ITEM = NMSUtils.getNMSClass(c + "UseItem");
} catch (ClassNotFoundException e2) {
//They are just on a newer version
try {
USE_ITEM = NMSUtils.getNMSClass(c + "UseItem");
} catch (ClassNotFoundException e2) {
e.printStackTrace();
e2.printStackTrace();
}
}
PacketType.Client.init();
@@ -36,16 +36,13 @@ import io.github.retrooper.packetevents.packetwrappers.in.settings.WrappedPacket
import io.github.retrooper.packetevents.packetwrappers.in.updatesign.WrappedPacketInUpdateSign;
import io.github.retrooper.packetevents.packetwrappers.in.useentity.WrappedPacketInUseEntity;
import io.github.retrooper.packetevents.packetwrappers.in.windowclick.WrappedPacketInWindowClick;
import io.github.retrooper.packetevents.packetwrappers.out.entityteleport.WrappedPacketOutEntityTeleport;
import io.github.retrooper.packetevents.packetwrappers.out.abilities.WrappedPacketOutAbilities;
import io.github.retrooper.packetevents.packetwrappers.out.animation.WrappedPacketOutAnimation;
import io.github.retrooper.packetevents.packetwrappers.out.chat.WrappedPacketOutChat;
import io.github.retrooper.packetevents.packetwrappers.out.custompayload.WrappedPacketOutCustomPayload;
import io.github.retrooper.packetevents.packetwrappers.out.entity.WrappedPacketOutEntity;
import io.github.retrooper.packetevents.packetwrappers.out.entitystatus.WrappedPacketOutEntityStatus;
import io.github.retrooper.packetevents.packetwrappers.out.entityteleport.WrappedPacketOutEntityTeleport;
import io.github.retrooper.packetevents.packetwrappers.out.entityvelocity.WrappedPacketOutEntityVelocity;
import io.github.retrooper.packetevents.packetwrappers.out.experience.WrappedPacketOutExperience;
import io.github.retrooper.packetevents.packetwrappers.out.explosion.WrappedPacketOutExplosion;
import io.github.retrooper.packetevents.packetwrappers.out.gamestatechange.WrappedPacketOutGameStateChange;
import io.github.retrooper.packetevents.packetwrappers.out.keepalive.WrappedPacketOutKeepAlive;
import io.github.retrooper.packetevents.packetwrappers.out.kickdisconnect.WrappedPacketOutKickDisconnect;
@@ -60,10 +57,9 @@ import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
private static final Map<Class<?>, Map<Class<?>, Field[]>> fieldCache = new HashMap<>();
private static final HashMap<Class<?>, HashMap<Class<?>, Field[]>> fieldCache = new HashMap<>();
public static ServerVersion version;
protected final Player player;
protected Object packet;
@@ -71,6 +67,8 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
public WrappedPacket() {
this.player = null;
this.packet = null;
this.packetClass = null;
}
public WrappedPacket(final Object packet) {
@@ -155,7 +153,7 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
}
}
Map<Class<?>, Field[]> map = new HashMap<>();
HashMap<Class<?>, Field[]> map = new HashMap<>();
if (!boolFields.isEmpty()) {
map.put(boolean.class, boolFields.toArray(new Field[0]));
}
@@ -253,9 +251,6 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
WrappedPacketOutUpdateHealth.load();
WrappedPacketOutGameStateChange.load();
WrappedPacketOutCustomPayload.load();
WrappedPacketOutExplosion.load();
WrappedPacketOutEntityStatus.load();
WrappedPacketOutExperience.load();
}
protected void setup() {
@@ -264,45 +259,93 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public boolean readBoolean(int index) {
return (boolean) read(boolean.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(boolean.class)[index].getBoolean(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, boolean.class, index);
}
@Override
public byte readByte(int index) {
return (byte) read(byte.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(byte.class)[index].getByte(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, byte.class, index);
}
@Override
public short readShort(int index) {
return (short) read(short.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(short.class)[index].getShort(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, short.class, index);
}
@Override
public int readInt(int index) {
return (int) read(int.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(int.class)[index].getInt(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, int.class, index);
}
@Override
public long readLong(int index) {
return (long) read(long.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(long.class)[index].getLong(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, long.class, index);
}
@Override
public float readFloat(int index) {
return (float) read(float.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(float.class)[index].getFloat(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, float.class, index);
}
@Override
public double readDouble(int index) {
return (double) read(double.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
return fieldCache.get(packetClass).get(double.class)[index].getDouble(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, double.class, index);
}
@Override
public boolean[] readBooleanArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (boolean[]) cached.get(boolean[].class)[index].get(packet);
return (boolean[]) fieldCache.get(packetClass).get(boolean[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -325,10 +368,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public byte[] readByteArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (byte[]) cached.get(byte[].class)[index].get(packet);
return (byte[]) fieldCache.get(packetClass).get(byte[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -351,10 +393,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public short[] readShortArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (short[]) cached.get(short[].class)[index].get(packet);
return (short[]) fieldCache.get(packetClass).get(short[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -377,10 +418,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public int[] readIntArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (int[]) cached.get(int[].class)[index].get(packet);
return (int[]) fieldCache.get(packetClass).get(int[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -403,10 +443,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public long[] readLongArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (long[]) cached.get(long[].class)[index].get(packet);
return (long[]) fieldCache.get(packetClass).get(long[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -429,10 +468,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public float[] readFloatArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (float[]) cached.get(float[].class)[index].get(packet);
return (float[]) fieldCache.get(packetClass).get(float[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -455,10 +493,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public double[] readDoubleArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
return (double[]) cached.get(double[].class)[index].get(packet);
return (double[]) fieldCache.get(packetClass).get(double[].class)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -481,10 +518,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public String[] readStringArray(int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (fieldCache.containsKey(packetClass)) {
try {
Object[] array = (Object[]) cached.get(String[].class)[index].get(packet);
Object[] array = (Object[]) fieldCache.get(packetClass).get(String[].class)[index].get(packet);
int len = array.length;
String[] stringArray = new String[len];
for (int i = 0; i < len; i++) {
@@ -500,7 +536,16 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public String readString(int index) {
return (String) read(String.class, index);
if (fieldCache.containsKey(packetClass)) {
try {
Field[] fields = fieldCache.get(packetClass).get(String.class);
Object obj = fields[index].get(packet);
return obj.toString();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
throw new WrapperFieldNotFoundException(packetClass, String.class, index);
}
public Object readAnyObject(int index) {
@@ -521,9 +566,9 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
}
public Object readObject(int index, Class<?> type) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached != null) {
if (!cached.containsKey(type)) {
if (fieldCache.containsKey(packetClass)) {
HashMap<Class<?>, Field[]> map = fieldCache.get(packetClass);
if (!map.containsKey(type)) {
List<Field> typeFields = new ArrayList<>();
for (Field f : packetClass.getDeclaredFields()) {
f.setAccessible(true);
@@ -532,13 +577,13 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
}
}
if (!typeFields.isEmpty()) {
cached.put(type, typeFields.toArray(new Field[0]));
map.put(type, typeFields.toArray(new Field[0]));
}
}
}
try {
return cached.get(type)[index].get(packet);
return fieldCache.get(packetClass).get(type)[index].get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
@@ -551,79 +596,113 @@ public class WrappedPacket implements WrapperPacketReader, WrapperPacketWriter {
@Override
public void writeBoolean(int index, boolean value) {
write(boolean.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(boolean.class)[index].setBoolean(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if(e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, boolean.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeByte(int index, byte value) {
write(byte.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(byte.class)[index].setByte(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if(e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, byte.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeShort(int index, short value) {
write(short.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(short.class)[index].setShort(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if (e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, short.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeInt(int index, int value) {
write(int.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(int.class)[index].setInt(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if (e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, int.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeLong(int index, long value) {
write(long.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(long.class)[index].setLong(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if(e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, long.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeFloat(int index, float value) {
write(float.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(float.class)[index].setFloat(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if(e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, float.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeDouble(int index, double value) {
write(double.class, index, value);
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(double.class)[index].setDouble(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if(e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, double.class, index);
}
e.printStackTrace();
}
}
}
@Override
public void writeString(int index, String value) {
write(String.class, index, value);
}
private void write(Class<?> type, int index, Object value) throws WrapperFieldNotFoundException {
Field field = getField(type, index);
if(field == null) {
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
try {
field.set(packet, value);
} catch (IllegalAccessException e) {
e.printStackTrace();
if (fieldCache.containsKey(packetClass)) {
try {
fieldCache.get(packetClass).get(String.class)[index].set(packet, value);
} catch (IllegalAccessException | NullPointerException e) {
if(e instanceof NullPointerException) {
throw new WrapperFieldNotFoundException(packetClass, String.class, index);
}
e.printStackTrace();
}
}
}
private Object read(Class<?> type, int index) throws WrapperFieldNotFoundException {
Field field = getField(type, index);
if(field == null) {
throw new WrapperFieldNotFoundException(packetClass, type, index);
}
try {
return field.get(packet);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
private Field getField(Class<?> type, int index) {
Map<Class<?>, Field[]> cached = fieldCache.get(packetClass);
if (cached == null) {
return null;
}
Field[] fields = cached.get(type);
if (fields != null) {
return fields[index];
}
return null;
}
}
@@ -78,7 +78,7 @@ public final class WrappedPacketInEntityAction extends WrappedPacket {
*/
public Entity getEntity() {
if(entity == null) {
return entity = NMSUtils.getEntityById(getEntityId());
return entity = NMSUtils.getEntityById(getEntityID());
}
return entity;
}
@@ -90,7 +90,7 @@ public final class WrappedPacketInEntityAction extends WrappedPacket {
*
* @return Entity ID
*/
public int getEntityId() {
public int getEntityID() {
if(entityId != -1) {
return entityId;
}
@@ -1,45 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketLoginHandshake extends WrappedPacket {
public WrappedPacketLoginHandshake(Object packet) {
super(packet);
}
public int getProtocolVersion() {
return readInt(0);
}
public String getHostName() {
return readString(0);
}
public int getPort() {
return readInt(1);
}
}
@@ -1,42 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketLoginInCustomPayload extends WrappedPacket {
public WrappedPacketLoginInCustomPayload(Object packet) {
super(packet);
}
/* TODO wrappers
* net.minecraft.server.v1_16_R2.PacketLoginInCustomPayload inCP;
* net.minecraft.server.v1_16_R2.PacketLoginOutCustomPayload outCP;
* net.minecraft.server.v1_16_R2.PacketPlayOutLogin outLogin;
* Find out about the Status Response packet
*/
}
@@ -1,40 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.gameprofile.GameProfileUtil;
import io.github.retrooper.packetevents.utils.gameprofile.WrappedGameProfile;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
public class WrappedPacketLoginInStart extends WrappedPacket {
public WrappedPacketLoginInStart(Object packet) {
super(packet);
}
public WrappedGameProfile getGameProfile() {
return GameProfileUtil.getWrappedGameProfile(readObject(0, NMSUtils.gameProfileClass));
}
}
@@ -1,41 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.in;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrapppedPacketLoginInEncryptionBegin extends WrappedPacket {
public WrapppedPacketLoginInEncryptionBegin(Object packet) {
super(packet);
}
public byte[] getPublicKey() {
return readByteArray(0);
}
public byte[] getVerifyToken() {
return readByteArray(1);
}
}
@@ -1,40 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.packetwrappers.out.chat.WrappedPacketOutChat;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
public class WrappedPacketLoginDisconnect extends WrappedPacket {
public WrappedPacketLoginDisconnect(Object packet) {
super(packet);
}
public String getReason() {
Object iChatBaseComponent = readObject(0, NMSUtils.iChatBaseComponentClass);
return WrappedPacketOutChat.toStringFromIChatBaseComponent(iChatBaseComponent);
}
}
@@ -1,47 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import java.security.PublicKey;
public class WrappedPacketLoginOutEncryptionBegin extends WrappedPacket {
public WrappedPacketLoginOutEncryptionBegin(Object packet) {
super(packet);
}
public String getEncodedString() {
return readString(0);
}
public PublicKey getPublicKey() {
return (PublicKey) readObject(1, PublicKey.class);
}
public byte[] getByteArray() {
return readByteArray(0);
}
}
@@ -1,41 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
//This packet does not exist on 1.7.10
public class WrappedPacketLoginOutSetCompression extends WrappedPacket {
public WrappedPacketLoginOutSetCompression(Object packet) {
super(packet);
}
/**
* Maximum size of a packet before it can be compressed.
*/
public int getThreshold() {
return readInt(0);
}
}
@@ -1,40 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.login.out;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.gameprofile.GameProfileUtil;
import io.github.retrooper.packetevents.utils.gameprofile.WrappedGameProfile;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
public class WrappedPacketLoginOutSuccess extends WrappedPacket {
public WrappedPacketLoginOutSuccess(Object packet) {
super(packet);
}
public WrappedGameProfile getGameProfile() {
return GameProfileUtil.getWrappedGameProfile(readObject(0, NMSUtils.gameProfileClass));
}
}
@@ -94,7 +94,7 @@ public final class WrappedPacketOutAnimation extends WrappedPacket implements Se
if (entity != null) {
return entity;
}
return entity = NMSUtils.getEntityById(getEntityId());
return entity = NMSUtils.getEntityById(getEntityID());
}
/**
@@ -104,7 +104,7 @@ public final class WrappedPacketOutAnimation extends WrappedPacket implements Se
*
* @return Entity ID
*/
public int getEntityId() {
public int getEntityID() {
if (entityID == -1) {
entityID = readInt(0);
}
@@ -25,18 +25,16 @@
package io.github.retrooper.packetevents.packetwrappers.out.entity;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import org.bukkit.entity.Entity;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class WrappedPacketOutEntity extends WrappedPacket implements SendableWrapper {
public class WrappedPacketOutEntity extends WrappedPacket {
private static Class<?> packetClass;
private int entityID = -1;
//Byte = 1.7.10->1.8.8, Int = 1.9->1.15.x, Short = 1.16.x
private static byte mode = 0; //byte = 0, int = 1, short = 2
private static double dXYZDivisor = 0.0;
@@ -44,36 +42,12 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
private static int pitchByteIndex = 1;
private Entity entity;
private boolean isListening = false;
private static Constructor<?> entityPacketConstructor;
private int entityID;
private double deltaX, deltaY, deltaZ;
private byte pitch, yaw;
private boolean onGround;
public WrappedPacketOutEntity(Object packet) {
super(packet);
isListening = true;
}
public WrappedPacketOutEntity(int entityID, double deltaX, double deltaY, double deltaZ,
byte pitch, byte yaw, boolean onGround) {
this.entityID = entityID;
this.deltaX = deltaX;
this.deltaY = deltaY;
this.deltaZ = deltaZ;
this.pitch = pitch;
this.yaw = yaw;
this.onGround = onGround;
//Get entity player then pass it into the packetplayoutnamedentityspawn!
// net.minecraft.server.v1_7_R4.EntityPlayer cp = null;
//net.minecraft.server.v1_7_R4.PacketPlayOutNamedEntitySpawn es = new net.minecraft.server.v1_7_R4.PacketPlayOutNamedEntitySpawn(cp);
}
public WrappedPacketOutEntity(Entity entity, double deltaX, double deltaY, double deltaZ,
byte pitch, byte yaw, boolean onGround) {
this(entity.getEntityId(), deltaX, deltaY, deltaZ, pitch, yaw, onGround);
}
public static void load() {
packetClass = PacketTypeClasses.Server.ENTITY;
@@ -94,11 +68,6 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
} else {
dXYZDivisor = 4096.0;
}
try {
entityPacketConstructor = packetClass.getConstructor(int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@@ -111,7 +80,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
if (isListening) {
return readByte(pitchByteIndex);
} else {
return pitch;
return 0;
}
}
@@ -124,7 +93,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
if (isListening) {
return readByte(yawByteIndex);
} else {
return yaw;
return 0;
}
}
@@ -144,7 +113,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
return readShort(0) / dXYZDivisor;
}
} else {
return deltaX;
}
return 0.0;
}
@@ -165,7 +134,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
return readShort(1) / dXYZDivisor;
}
} else {
return deltaY;
}
return 0.0;
}
@@ -186,7 +155,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
return readShort(2) / dXYZDivisor;
}
} else {
return deltaZ;
}
return 0.0;
}
@@ -200,7 +169,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
if (entity != null) {
return entity;
}
return entity = NMSUtils.getEntityById(getEntityId());
return entity = NMSUtils.getEntityById(getEntityID());
}
/**
@@ -210,7 +179,7 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
*
* @return Entity ID
*/
public int getEntityId() {
public int getEntityID() {
if (entityID != -1) {
return entityID;
} else {
@@ -227,39 +196,8 @@ public class WrappedPacketOutEntity extends WrappedPacket implements SendableWra
if (isListening) {
return readBoolean(0);
} else {
return onGround;
}
}
@Override
public Object asNMSPacket() {
try {
Object packetInstance = entityPacketConstructor.newInstance(entityID);
WrappedPacket wrapper = new WrappedPacket(packetInstance);
switch(mode) {
case 0:
wrapper.writeByte(0, (byte)(deltaX * dXYZDivisor));
wrapper.writeByte(1, (byte)(deltaY * dXYZDivisor));
wrapper.writeByte(2, (byte)(deltaZ * dXYZDivisor));
break;
case 1:
wrapper.writeInt(1, (int)(deltaX * dXYZDivisor));
wrapper.writeInt(2, (int)(deltaY * dXYZDivisor));
wrapper.writeInt(3, (int)(deltaZ * dXYZDivisor));
break;
case 2:
wrapper.writeShort(0, (short)(deltaX * dXYZDivisor));
wrapper.writeShort(1, (short)(deltaY * dXYZDivisor));
wrapper.writeShort(2, (short)(deltaZ * dXYZDivisor));
break;
}
wrapper.writeByte(yawByteIndex, yaw);
wrapper.writeByte(pitchByteIndex, pitch);
wrapper.writeBoolean(0, onGround);
return packetInstance;
} catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
return false;
}
}
@@ -28,17 +28,18 @@ import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketOutEntityMetadata extends WrappedPacket {
private boolean isListening = false;
private int entityID;
public WrappedPacketOutEntityMetadata(Object packet) {
super(packet);
isListening = true;
}
public int getEntityId() {
public int getEntityID() {
if (isListening) {
return readInt(0);
} else {
return entityID;
}
return -1;
}
}
@@ -1,103 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.out.entitystatus;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.bukkit.entity.Entity;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class WrappedPacketOutEntityStatus extends WrappedPacket implements SendableWrapper {
private static Constructor<?> packetConstructor;
public static void load() {
try {
packetConstructor =
PacketTypeClasses.Server.ENTITY_STATUS.getConstructor(NMSUtils.nmsEntityClass, byte.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private Entity entity;
private byte status;
private int entityID = -1;
public WrappedPacketOutEntityStatus(Object packet) {
super(packet);
}
public WrappedPacketOutEntityStatus(Entity entity, byte status) {
this.entityID = entity.getEntityId();
this.entity = entity;
this.status = status;
}
public WrappedPacketOutEntityStatus(int entityID, byte status) {
this.entityID = entityID;
this.status = status;
}
public int getEntityId() {
if (packet == null) {
if (entityID != -1) {
return entityID;
}
return entityID = readInt(0);
} else {
return entityID;
}
}
public Entity getEntity() {
if (entity == null) {
return entity = NMSUtils.getEntityById(getEntityId());
}
return entity;
}
public byte getEntityStatus() {
if (packet == null) {
return status;
} else {
return readByte(0);
}
}
@Override
public Object asNMSPacket() {
try {
return packetConstructor.newInstance(NMSUtils.getNMSEntity(getEntity()), status);
} catch (InstantiationException | InvocationTargetException
| IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
@@ -91,12 +91,12 @@ public class WrappedPacketOutEntityTeleport extends WrappedPacket implements Sen
public Entity getEntity() {
if(entity == null) {
entity = NMSUtils.getEntityById(getEntityId());
entity = NMSUtils.getEntityById(getEntityID());
}
return entity;
}
public int getEntityId() {
public int getEntityID() {
if (listeningMode) {
if (entityID != -1) {
return readInt(0);
@@ -103,7 +103,7 @@ public final class WrappedPacketOutEntityVelocity extends WrappedPacket implemen
if (entity != null) {
return entity;
}
return entity = NMSUtils.getEntityById(getEntityId());
return entity = NMSUtils.getEntityById(getEntityID());
}
/**
@@ -113,7 +113,7 @@ public final class WrappedPacketOutEntityVelocity extends WrappedPacket implemen
*
* @return Entity ID
*/
public int getEntityId() {
public int getEntityID() {
if (entityID != -1) {
return entityID;
}
@@ -1,93 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.out.experience;
import io.github.retrooper.packetevents.packettype.PacketTypeClasses;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class WrappedPacketOutExperience extends WrappedPacket implements SendableWrapper {
private static Constructor<?> packetConstructor;
public static void load() {
try {
packetConstructor = PacketTypeClasses.Server.EXPERIENCE.getConstructor(float.class,
int.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private float expBar;
private int expLevel, totalExp;
public WrappedPacketOutExperience(Object packet) {
super(packet);
}
public WrappedPacketOutExperience(float experienceBar, int experienceLevel,
int totalExperience) {
this.expBar = experienceBar;
this.expLevel = experienceLevel;
this.totalExp = totalExperience;
}
public float getExperienceBar() {
if (packet == null) {
return expBar;
} else {
//constructor = float, int, int
return readFloat(0);
}
}
public int getExperienceLevel() {
if (packet == null) {
return expLevel;
} else {
return readInt(0);
}
}
public int getTotalExperience() {
if (packet == null) {
return totalExp;
} else {
return readInt(1);
}
}
@Override
public Object asNMSPacket() {
try {
return packetConstructor.newInstance(expBar, expLevel, totalExp);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
@@ -1,199 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.out.explosion;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.vector.Vector3i;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
public class WrappedPacketOutExplosion extends WrappedPacket implements SendableWrapper {
private static Class<?> chunkPosClass, blockPosClass, vec3DClass;
private static Constructor<?> chunkPosConstructor, blockPosConstructor, packetConstructor, vec3dConstructor;
public static void load() {
chunkPosClass = NMSUtils.getNMSClassWithoutException("ChunkPosition");
blockPosClass = NMSUtils.getNMSClassWithoutException("BlockPosition");
Class<?> packetClass = NMSUtils.getNMSClassWithoutException("PacketPlayOutExplosion");
vec3DClass = NMSUtils.getNMSClassWithoutException("Vec3D");
try {
packetConstructor = packetClass.getConstructor(double.class, double.class, double.class, float.class, List.class, vec3DClass);
vec3dConstructor = vec3DClass.getDeclaredConstructor(double.class, double.class, double.class);
if (chunkPosClass != null) {
chunkPosConstructor = chunkPosClass.getConstructor(int.class, int.class, int.class);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
if (blockPosClass != null) {
blockPosConstructor = blockPosClass.getConstructor(int.class, int.class, int.class);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
private boolean isListening = false;
private double x, y, z;
private float strength;
private List<Vector3i> records;
private float playerMotionX, playerMotionY, playerMotionZ;
public WrappedPacketOutExplosion(Object packet) {
super(packet);
isListening = true;
}
public WrappedPacketOutExplosion(double x, double y, double z, float strength, List<Vector3i> records,
float playerMotionX, float playerMotionY, float playerMotionZ) {
this.x = x;
this.y = y;
this.z = z;
this.strength = strength;
this.records = records;
this.playerMotionX = playerMotionX;
this.playerMotionY = playerMotionY;
this.playerMotionZ = playerMotionZ;
}
public double getX() {
if (isListening) {
return readDouble(0);
} else {
return x;
}
}
public double getY() {
if (isListening) {
return readDouble(1);
} else {
return y;
}
}
public double getZ() {
if (isListening) {
return readDouble(2);
} else {
return z;
}
}
public float getStrength() {
if (isListening) {
return readFloat(0);
} else {
return strength;
}
}
public List<Vector3i> getRecords() {
if (isListening) {
List<Vector3i> recordsList = new ArrayList<>();
List<?> rawRecordsList = (List<?>) readObject(0, List.class);
if (rawRecordsList.isEmpty()) {
return new ArrayList<>();
}
for (Object position : rawRecordsList) {
WrappedPacket posWrapper = new WrappedPacket(position);
recordsList.add(new Vector3i(posWrapper.readInt(0), posWrapper.readInt(1), posWrapper.readInt(2)));
}
return recordsList;
} else {
return records;
}
}
public float getPlayerMotionX() {
if (isListening) {
return readFloat(1);
} else {
return playerMotionX;
}
}
public float getPlayerMotionY() {
if (isListening) {
return readFloat(2);
} else {
return playerMotionY;
}
}
public float getPlayerMotionZ() {
if (isListening) {
return readFloat(3);
} else {
return playerMotionZ;
}
}
@Override
public Object asNMSPacket() {
if (version.equals(ServerVersion.v_1_7_10)) {
List<Object> chunkPositions = new ArrayList<>();
for (Vector3i vec : records) {
try {
chunkPositions.add(chunkPosConstructor.newInstance(vec.x, vec.y, vec.z));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
try {
Object vec = vec3dConstructor.newInstance(playerMotionX, playerMotionY, playerMotionZ);
return packetConstructor.newInstance(x, y, z, strength, chunkPositions, vec);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
} else {
List<Object> blockPositions = new ArrayList<>();
for (Vector3i vec : records) {
try {
blockPositions.add(blockPosConstructor.newInstance(vec.x, vec.y, vec.z));
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
try {
Object vec = vec3dConstructor.newInstance(playerMotionX, playerMotionY, playerMotionZ);
return packetConstructor.newInstance(x, y, z, strength, blockPositions, vec);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
}
return null;
}
}
@@ -0,0 +1,117 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.out.playerinfo;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import org.bukkit.GameMode;
import java.util.ArrayList;
import java.util.List;
class WrappedPacketOutPlayerInfo extends WrappedPacket implements SendableWrapper {
//TODO load this wrapper
private boolean isListening = false;
private PlayerInfoAction action;
private List<PlayerInfoData> playerInfoDataList = new ArrayList<>();
private static byte mode = 0; //0 = 1.7.10
public static void load() {
}
public WrappedPacketOutPlayerInfo(Object packet) {
super(packet);
isListening = true;
}
public WrappedPacketOutPlayerInfo(PlayerInfoAction action, Object gameProfile,
int ping, GameMode gameMode, String displayName) {
this.action = action;
playerInfoDataList.add(new PlayerInfoData(gameProfile, ping, gameMode, displayName));
}
@Override
protected void setup() {
switch (mode) {
case 0:
int actionInteger= readInt(0);
break;
case 1:
break;
case 2:
break;
}
}
@Override
public Object asNMSPacket() {
return null;
}
public PlayerInfoAction getAction() {
return action;
}
public List<PlayerInfoData> getPlayerInfoData() {
return playerInfoDataList;
}
public enum PlayerInfoAction {
ADD_PLAYER, UPDATE_GAME_MODE, UPDATE_LATENCY, UPDATE_DISPLAY_NAME, REMOVE_PLAYER;
}
public class PlayerInfoData {
private final int ping;
private final GameMode gameMode;
private final Object gameProfile;
private final String displayName;
public PlayerInfoData(Object gameProfile, int ping,
GameMode gameMode, String displayName) {
this.ping = ping;
this.gameMode = gameMode;
this.gameProfile = gameProfile;
this.displayName = displayName;
}
public int getPing() {
return ping;
}
public GameMode getGameMode() {
return gameMode;
}
public Object getGameProfile() {
return gameProfile;
}
public String getDisplayName() {
return displayName;
}
}
}
@@ -1,37 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.status;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketStatusPing extends WrappedPacket {
public WrappedPacketStatusPing(Object packet) {
super(packet);
}
public long getPayload() {
return readLong(0);
}
}
@@ -1,37 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.packetwrappers.status;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
public class WrappedPacketStatusPong extends WrappedPacket {
public WrappedPacketStatusPong(Object packet) {
super(packet);
}
public long getPayload() {
return readLong(0);
}
}
@@ -28,17 +28,21 @@ import io.github.retrooper.packetevents.utils.server.ServerVersion;
public class PacketEventsSettings {
private ServerVersion backupServerVersion = ServerVersion.v_1_7_10;
private boolean autoResolveClientProtocolVersion;
private boolean injectAsync = true;
private boolean ejectAsync = true;
private boolean useProtocolLibIfAvailable = false;
private boolean useProtocolLibIfAvailable;
private boolean checkForUpdates = true;
private boolean injectEarly = true;
public PacketEventsSettings backupServerVersion(ServerVersion serverVersion) {
this.backupServerVersion = serverVersion;
return this;
}
public PacketEventsSettings autoResolveClientProtocolVersion(boolean autoResolveClientProtocolVersion) {
this.autoResolveClientProtocolVersion = autoResolveClientProtocolVersion;
return this;
}
public PacketEventsSettings injectAsync(boolean injectAsync) {
this.injectAsync = injectAsync;
@@ -60,16 +64,14 @@ public class PacketEventsSettings {
return this;
}
public PacketEventsSettings injectEarly(boolean injectEarly) {
this.injectEarly = injectEarly;
return this;
}
public ServerVersion getBackupServerVersion() {
return backupServerVersion;
}
public boolean shouldAutoResolveClientProtocolVersion() {
return autoResolveClientProtocolVersion;
}
public boolean shouldInjectAsync() {
return injectAsync;
}
@@ -85,8 +87,4 @@ public class PacketEventsSettings {
public boolean shouldCheckForUpdates() {
return checkForUpdates;
}
public boolean shouldInjectEarly() {
return injectEarly;
}
}
@@ -25,9 +25,8 @@
package io.github.retrooper.packetevents.updatechecker;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.server.PEVersion;
import io.github.retrooper.packetevents.version.PEVersion;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import java.io.BufferedReader;
import java.io.IOException;
@@ -37,10 +36,10 @@ import java.net.URLConnection;
public class UpdateChecker {
public void handleUpdate() {
PEVersion localVersion = PacketEvents.getVersion();
try {
String line = readLatestVersion();
PEVersion newVersion = new PEVersion(line);
PEVersion localVersion = PacketEvents.getVersion();
if (localVersion.isOlder(newVersion)) {
inform("[PacketEvents] There is an update available for the PacketEvents API! (" + newVersion.toString() + ")");
}
@@ -51,7 +50,7 @@ public class UpdateChecker {
inform("[PacketEvents] You are on a dev or pre released build of PacketEvents. Your build: (" + localVersion.toString() + ") | Last released build: (" + newVersion.toString() + ")");
}
} catch (IOException ignored) {
report("[PacketEvents] We failed to find the latest released version of PacketEvents. Your build: (" + localVersion.toString() + ")");
//Thats fine, Not important
}
}
@@ -59,10 +58,6 @@ public class UpdateChecker {
Bukkit.getLogger().info(message);
}
private void report(String message) {
Bukkit.getLogger().info(ChatColor.DARK_RED + message);
}
private String readLatestVersion() throws IOException {
URLConnection connection = new URL("https://api.spigotmc.org/legacy/update.php?resource=80279").openConnection();
connection.addRequestProperty("User-Agent", "Mozilla/4.0");
@@ -24,11 +24,11 @@
package io.github.retrooper.packetevents.utils.bytebuf;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.nettyhandler.NettyPacketHandler;
public class ByteBufUtil {
public static Object copiedBuffer(byte[] bytes) {
if (NettyPacketManager.v1_7_nettyMode) {
if (NettyPacketHandler.v1_7_nettyMode) {
return ByteBufUtil_7.copiedBuffer(bytes);
} else {
return ByteBufUtil_8.copiedBuffer(bytes);
@@ -36,7 +36,7 @@ public class ByteBufUtil {
}
public static byte[] getBytes(Object byteBuf) {
if(NettyPacketManager.v1_7_nettyMode) {
if(NettyPacketHandler.v1_7_nettyMode) {
return ByteBufUtil_7.getBytes(byteBuf);
}
else {
@@ -24,26 +24,17 @@
package io.github.retrooper.packetevents.utils.gameprofile;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.nettyhandler.NettyPacketHandler;
import java.util.UUID;
public class GameProfileUtil {
public static Object getGameProfile(UUID uuid, String username) {
if(NettyPacketManager.v1_7_nettyMode) {
if(NettyPacketHandler.v1_7_nettyMode) {
return GameProfileUtil_7.getGameProfile(uuid, username);
}
else {
return GameProfileUtil_8.getGameProfile(uuid, username);
}
}
public static WrappedGameProfile getWrappedGameProfile(Object gameProfile) {
if(NettyPacketManager.v1_7_nettyMode) {
return GameProfileUtil_7.getWrappedGameProfile(gameProfile);
}
else {
return GameProfileUtil_8.getWrappedGameProfile(gameProfile);
}
}
}
@@ -32,9 +32,4 @@ class GameProfileUtil_7 {
public static Object getGameProfile(UUID uuid, String username) {
return new GameProfile(uuid, username);
}
public static WrappedGameProfile getWrappedGameProfile(Object gameProfile) {
GameProfile gp = (GameProfile) gameProfile;
return new WrappedGameProfile(gp.getId(), gp.getName(), gp.isLegacy());
}
}
@@ -32,9 +32,4 @@ class GameProfileUtil_8 {
public static Object getGameProfile(UUID uuid, String username) {
return new GameProfile(uuid, username);
}
public static WrappedGameProfile getWrappedGameProfile(Object gameProfile) {
GameProfile gp = (GameProfile)gameProfile;
return new WrappedGameProfile(gp.getId(), gp.getName(), gp.isLegacy());
}
}
@@ -1,69 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.gameprofile;
import java.util.UUID;
public class WrappedGameProfile {
public UUID id;
public String name;
public boolean legacy;
public WrappedGameProfile(UUID id, String name, boolean legacy) {
this.id = id;
this.name = name;
this.legacy = legacy;
}
public UUID getId() {
return id;
}
public String getName() {
return name;
}
public boolean isLegacy() {
return legacy;
}
public boolean isComplete() {
return id != null && !isBlank(name);
}
private boolean isBlank(CharSequence cs) {
int strLen;
if (cs != null && (strLen = cs.length()) != 0) {
for (int i = 0; i < strLen; ++i) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
} else {
return true;
}
}
}
@@ -24,12 +24,13 @@
package io.github.retrooper.packetevents.utils.nms;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.annotations.Nullable;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.nettyhandler.NettyPacketHandler;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.packetwrappers.WrappedPacket;
import io.github.retrooper.packetevents.utils.entityfinder.EntityFinderUtils;
import io.github.retrooper.packetevents.utils.reflection.Reflection;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Entity;
@@ -49,8 +50,8 @@ public final class NMSUtils {
public static String nettyPrefix = "io.netty";
public static Class<?> nmsEntityClass, minecraftServerClass, craftWorldClass, playerInteractManagerClass, entityPlayerClass, playerConnectionClass, craftServerClass,
craftPlayerClass, serverConnectionClass, craftEntityClass,
craftItemStack, nmsItemStackClass, networkManagerClass, nettyChannelClass, gameProfileClass, iChatBaseComponentClass;
private static Method craftWorldGetHandle, getCraftWorldHandleMethod, getServerConnection, getCraftPlayerHandle, getCraftEntityHandle, asBukkitCopy;
craftItemStack, nmsItemStackClass, networkManagerClass, nettyChannelClass;
private static Method craftWorldGetHandle,getCraftWorldHandleMethod, getServerConnection, getCraftPlayerHandle, getCraftEntityHandle, asBukkitCopy;
private static Field entityPlayerPingField, playerConnectionField;
public static final HashMap<UUID, Object> channelCache = new HashMap<>();
@@ -81,12 +82,6 @@ public final class NMSUtils {
nmsItemStackClass = getNMSClass("ItemStack");
networkManagerClass = getNMSClass("NetworkManager");
playerInteractManagerClass = getNMSClass("PlayerInteractManager");
try {
gameProfileClass = Class.forName("com.mojang.authlib.GameProfile");
} catch (ClassNotFoundException e) {
gameProfileClass = Class.forName("net.minecraft.util.com.mojang.authlib.GameProfile");
}
iChatBaseComponentClass = NMSUtils.getNMSClass("IChatBaseComponent");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
@@ -116,19 +111,6 @@ public final class NMSUtils {
return Reflection.getMethod(minecraftServerClass, "getServer", 0).invoke(null);
}
public static Object getMinecraftServerConnection() {
WrappedPacket wrapper = null;
try {
wrapper = new WrappedPacket(getMinecraftServerInstance());
} catch (InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
if (wrapper == null) {
return null;
}
return wrapper.readObject(0, serverConnectionClass);
}
public static double[] recentTPS() throws IllegalAccessException, InvocationTargetException {
final Object minecraftServerObj = getMinecraftServerInstance();
return (double[]) Reflection.getField(minecraftServerClass, double[].class, 0).get(minecraftServerObj);
@@ -216,32 +198,29 @@ public final class NMSUtils {
}
public static Object getNetworkManager(final Player player) {
WrappedPacket wrapper = new WrappedPacket(getPlayerConnection(player));
return wrapper.readObject(0, networkManagerClass);
try {
return Reflection.getField(playerConnectionClass, networkManagerClass, 0).get(getPlayerConnection(player));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static Object getChannel(final Player player) {
if (PacketEvents.getAPI().packetManager.tinyProtocol == null) {
UUID uuid = player.getUniqueId();
Object channel = channelCache.get(uuid);
if (channel == null) {
Object newChannel = getChannelNoCache(player);
channelCache.put(uuid, newChannel);
return newChannel;
}
return channel;
} else {
return PacketEvents.getAPI().packetManager.tinyProtocol.getChannel(player);
UUID uuid = player.getUniqueId();
if (!channelCache.containsKey(uuid)) {
channelCache.put(uuid, getChannelNoCache(player));
}
return channelCache.get(uuid);
}
public static Object getChannelNoCache(final Player player) {
if (PacketEvents.getAPI().packetManager.tinyProtocol == null) {
WrappedPacket wrapper = new WrappedPacket(getNetworkManager(player));
return wrapper.readObject(0, nettyChannelClass);
} else {
return PacketEvents.getAPI().packetManager.tinyProtocol.getChannel(player);
try {
return Reflection.getField(networkManagerClass, nettyChannelClass, 0).get(getNetworkManager(player));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static int getPlayerPing(final Player player) {
@@ -268,16 +247,17 @@ public final class NMSUtils {
WrappedPacket wrapper = new WrappedPacket(craftServer);
return wrapper.readObject(0, minecraftServerClass);
}
public static Object convertBukkitWorldToNMSWorld(World world) {
Object craftWorld = craftWorldClass.cast(world);
Object worldServer = null;
try {
return craftWorldGetHandle.invoke(craftWorld);
worldServer = craftWorldGetHandle.invoke(craftWorld);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
return worldServer;
}
public static Object createNewEntityPlayer(Server server, World world, Object gameProfile) {
@@ -305,4 +285,12 @@ public final class NMSUtils {
}
return null;
}
public static void sendSendableWrapper(final Player player, final SendableWrapper sendableWrapper) {
NMSUtils.sendNMSPacket(player, sendableWrapper.asNMSPacket());
}
public static void sendNMSPacket(final Player player, final Object nmsPacket) {
NettyPacketHandler.sendPacket(getChannel(player), nmsPacket);
}
}
@@ -61,7 +61,7 @@ public enum ClientVersion {
*/
ANY_PRE_RELEASE_VERSION(0),
UNRESOLVED(-1);
UNKNOWN(-1);
private final int protocolVersion;
@@ -96,8 +96,8 @@ public enum ClientVersion {
}
public static ClientVersion getClientVersion(int protocolVersion) {
if(protocolVersion == -1) {
return ClientVersion.UNRESOLVED;
if(protocolVersion == -1 && PacketEvents.getSettings().shouldAutoResolveClientProtocolVersion()) {
protocolVersion = PacketEvents.getAPI().getServerUtils().getVersion().toProtocolVersion();
}
for(ClientVersion version : ClientVersion.values()) {
if(version.protocolVersion > protocolVersion) {
@@ -117,6 +117,6 @@ public enum ClientVersion {
&& protocolVersion < highestSupportedProtocolVersion) {
return ANY_PRE_RELEASE_VERSION;
}
return UNRESOLVED;
return UNKNOWN;
}
}
@@ -26,7 +26,7 @@ package io.github.retrooper.packetevents.utils.player;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.event.impl.PlayerEjectEvent;
import io.github.retrooper.packetevents.packetmanager.netty.NettyPacketManager;
import io.github.retrooper.packetevents.nettyhandler.NettyPacketHandler;
import io.github.retrooper.packetevents.packetwrappers.SendableWrapper;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import io.github.retrooper.packetevents.utils.versionlookup.VersionLookupUtils;
@@ -36,43 +36,28 @@ import java.util.HashMap;
import java.util.UUID;
public final class PlayerUtils {
public final HashMap<UUID, Short> playerPingMap = new HashMap<>();
public final HashMap<UUID, Short> playerSmoothedPingMap = new HashMap<>();
/**
* This map stores each player's client version.
*/
public final HashMap<Object, ClientVersion> clientVersionsMap = new HashMap<>();
public final HashMap<UUID, ClientVersion> clientVersionsMap = new HashMap<UUID, ClientVersion>();
/**
* Use reflection to read the ping value NMS calculates for the player.
* NMS smooths the player ping.
* Get the player's ping.
* @param player
* @return Get NMS smoothed Player Ping
* @return Get Player Ping
*/
public int getNMSPing(final Player player) {
public int getPing(final Player player) {
return NMSUtils.getPlayerPing(player);
}
/**
* Use the ping PacketEvents calculates for the player. (Updates every incoming Keep Alive packet)
* @param player Player
* @return Get Ping
* Get the client version by a UUID.
* @param uuid
* @return Get Client Version
*/
public short getPing(final Player player) {
return playerPingMap.getOrDefault(player.getUniqueId(), (short)0);
}
public short getSmoothedPing(final Player player) {
return playerSmoothedPingMap.getOrDefault(player.getUniqueId(), (short)0);
}
public short getPing(UUID uuid) {
return playerPingMap.getOrDefault(uuid, (short)0);
}
public short getSmoothedPing(UUID uuid) {
return playerSmoothedPingMap.getOrDefault(uuid, (short)0);
public ClientVersion getClientVersion(final UUID uuid) {
return clientVersionsMap.get(uuid);
}
/**
@@ -81,7 +66,16 @@ public final class PlayerUtils {
* @return Get Client Version
*/
public ClientVersion getClientVersion(final Player player) {
return clientVersionsMap.get(NMSUtils.getChannel(player));
return clientVersionsMap.get(player.getUniqueId());
}
/**
* Get the protocol version.
* @param player
* @return Get Protocol Version
*/
public int getProtocolVersion(Player player) {
return VersionLookupUtils.getProtocolVersion(player);
}
/**
@@ -91,7 +85,11 @@ public final class PlayerUtils {
* @param player
*/
public void injectPlayer(final Player player) {
PacketEvents.getAPI().packetManager.injectPlayer(player);
if (PacketEvents.getSettings().shouldInjectAsync()) {
NettyPacketHandler.injectPlayerAsync(player);
} else {
NettyPacketHandler.injectPlayer(player);
}
}
/**
@@ -100,7 +98,11 @@ public final class PlayerUtils {
* @param player
*/
public void ejectPlayer(final Player player) {
PacketEvents.getAPI().packetManager.ejectPlayer(player);
if (PacketEvents.getSettings().shouldEjectAsync()) {
NettyPacketHandler.ejectPlayerAsync(player);
} else {
NettyPacketHandler.ejectPlayer(player);
}
}
/**
@@ -109,7 +111,7 @@ public final class PlayerUtils {
* @param sendableWrapper
*/
public void sendPacket(final Player player, final SendableWrapper sendableWrapper) {
PacketEvents.getAPI().packetManager.sendPacket(NMSUtils.getChannel(player), sendableWrapper.asNMSPacket());
NMSUtils.sendSendableWrapper(player, sendableWrapper);
}
/**
@@ -118,6 +120,6 @@ public final class PlayerUtils {
* @param nmsPacket
*/
public void sendNMSPacket(final Player player, Object nmsPacket) {
PacketEvents.getAPI().packetManager.sendPacket(NMSUtils.getChannel(player), nmsPacket);
NMSUtils.sendNMSPacket(player, nmsPacket);
}
}
}
@@ -38,8 +38,6 @@ import io.github.retrooper.packetevents.event.impl.PacketSendEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ProtocolLibListener {
@@ -70,15 +68,9 @@ public class ProtocolLibListener {
priority = ListenerPriority.NORMAL;
break;
}
Set<PacketType> clientValues = new HashSet<>();
for(PacketType type : PacketType.Play.Client.getInstance().values()) {
if(type.isSupported()) {
clientValues.add(type);
}
}
ProtocolLibrary.getProtocolManager().
addPacketListener(new PacketAdapter(PacketEvents.getPlugins().get(0),
priority, clientValues) {
priority, PacketType.Play.Client.getInstance().values()) {
@Override
public void onPacketReceiving(PacketEvent event) {
event.setReadOnly(false);
@@ -114,17 +106,9 @@ public class ProtocolLibListener {
priority = ListenerPriority.NORMAL;
break;
}
Set<PacketType> serverValues = new HashSet<>();
for(PacketType serverType : PacketType.Play.Server.getInstance().values()) {
if(serverType.isSupported()) {
serverValues.add(serverType);
}
}
ProtocolLibrary.getProtocolManager().
addPacketListener(new PacketAdapter(PacketEvents.getPlugins().get(0),
priority, serverValues) {
priority, PacketType.Play.Server.getInstance().values()) {
@Override
public void onPacketSending(PacketEvent event) {
event.setReadOnly(false);
@@ -28,14 +28,15 @@ import java.util.HashMap;
import java.util.Map;
public class ClassUtil {
private static final Map<String, String> classSimpleNameCache = new HashMap<String, String>();
private static final Map<Class<?>, String> classSimpleNameCache = new HashMap<Class<?>, String>();
public static String getClassSimpleName(Class<?> cls) {
String simpleClassName = classSimpleNameCache.get(cls.getName());
if(simpleClassName == null) {
String name = simpleClassName = cls.getSimpleName();
classSimpleNameCache.put(cls.getName(), name);
String tmp = classSimpleNameCache.get(cls);
if(tmp == null) {
String name = cls.getSimpleName();
classSimpleNameCache.put(cls, name);
return name;
}
return simpleClassName;
return tmp;
}
}
@@ -24,8 +24,8 @@
package io.github.retrooper.packetevents.utils.server;
import io.github.retrooper.packetevents.enums.SystemOS;
import io.github.retrooper.packetevents.utils.nms.NMSUtils;
import org.spigotmc.SpigotConfig;
import java.lang.reflect.InvocationTargetException;
@@ -43,12 +43,13 @@ public final class ServerUtils {
* @return Get Recent TPS
*/
public double[] getRecentTPS() {
double[] tpsArray = new double[0];
try {
return NMSUtils.recentTPS();
tpsArray = NMSUtils.recentTPS();
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return new double[0];
return tpsArray;
}
/**
@@ -66,8 +67,4 @@ public final class ServerUtils {
public SystemOS getOS() {
return SystemOS.getOperatingSystem();
}
public boolean isBungeeCordEnabled() {
return SpigotConfig.bungee;
}
}
@@ -32,124 +32,170 @@ import org.bukkit.Bukkit;
*/
public enum ServerVersion {
v_1_7_10((short) 5), v_1_8((short) 47), v_1_8_3((short) 47), v_1_8_4((short) 47), v_1_8_5((short) 47),
v_1_8_6((short) 47), v_1_8_7((short) 47), v_1_8_8((short) 47), v_1_9((short) 107), v_1_9_2((short) 109),
v_1_9_4((short) 110), v_1_10((short) 210), v_1_10_2((short) 210), v_1_11((short) 315), v_1_11_1((short) 316),
v_1_11_2((short) 316), v_1_12((short) 335), v_1_12_1((short) 338), v_1_12_2((short) 340), v_1_13((short) 393),
v_1_13_1((short) 401), v_1_13_2((short) 404), v_1_14((short) 477), v_1_14_1((short) 480), v_1_14_2((short) 485),
v_1_14_3((short) 490), v_1_14_4((short) 498), v_1_15((short) 573), v_1_15_1((short) 575), v_1_15_2((short) 578),
v_1_16((short) 735), v_1_16_1((short) 736), v_1_16_2((short) 751), v_1_16_3((short) 753), ERROR((short) -1), EMPTY((short) -1);
v_1_7_10, v_1_8, v_1_8_3, v_1_8_4, v_1_8_5, v_1_8_6, v_1_8_7, v_1_8_8,
v_1_9, v_1_9_2, v_1_9_4, v_1_10, v_1_10_2, v_1_11, v_1_11_1, v_1_11_2,
v_1_12, v_1_12_1, v_1_12_2, v_1_13, v_1_13_1, v_1_13_2, v_1_14, v_1_14_1,
v_1_14_2, v_1_14_3, v_1_14_4, v_1_15, v_1_15_1, v_1_15_2, v_1_16, v_1_16_1,
v_1_16_2, v_1_16_3, ERROR, EMPTY;
private static final String nmsVersionSuffix = Bukkit.getServer().getClass().getPackage().getName()
.replace(".", ",").split(",")[3];
public static ServerVersion[] reversedValues = new ServerVersion[values().length];
private static ServerVersion cachedVersion;
private final short protocolId;
private static final String nmsVersionSuffix = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
public static ServerVersion[] reversedValues = new ServerVersion[values().length];
private static ServerVersion cachedVersion;
ServerVersion(short protocolId) {
this.protocolId = protocolId;
}
public short toProtocolVersion() {
return protocolId;
}
private static ServerVersion getVersionNoCache() {
if (reversedValues[0] == null) {
reversedValues = ServerVersion.reverse(values());
}
for (final ServerVersion val : reversedValues) {
String valName = val.name().substring(2).replace("_", ".");
if (Bukkit.getBukkitVersion().contains(valName)) {
return val;
}
}
if(PacketEvents.getSettings().getBackupServerVersion() != null) {
private static ServerVersion getVersionNoCache() {
if(reversedValues[0] == null) {
reversedValues = ServerVersion.reverse(values());
}
for (final ServerVersion val : reversedValues) {
String valName = val.name().substring(2).replace("_", ".");
if (Bukkit.getBukkitVersion().contains(valName)) {
return val;
}
}
if(PacketEvents.getSettings().getBackupServerVersion() != null) {
return PacketEvents.getSettings().getBackupServerVersion();
}
return ERROR;
}
return ERROR;
}
public static ServerVersion getVersion() {
if (cachedVersion == null) {
cachedVersion = getVersionNoCache();
}
return cachedVersion;
}
public static ServerVersion getVersion() {
if (cachedVersion == null) {
cachedVersion = getVersionNoCache();
}
return cachedVersion;
}
public static ServerVersion[] reverse(final ServerVersion[] arr) {
ServerVersion[] array = arr.clone();
if (array == null) {
return null;
}
int i = 0;
int j = array.length - 1;
ServerVersion tmp;
while (j > i) {
tmp = array[j];
array[j--] = array[i];
array[i++] = tmp;
}
return array;
}
public static String getNmsSuffix() {
return nmsVersionSuffix;
}
public static ServerVersion[] reverse(final ServerVersion[] arr) {
ServerVersion[] array = arr.clone();
if (array == null) {
return null;
}
int i = 0;
int j = array.length - 1;
ServerVersion tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
return array;
}
public static String getNMSDirectory() {
return "net.minecraft.server." + getNmsSuffix();
}
public static String getNmsSuffix() {
return nmsVersionSuffix;
}
public static String getOBCDirectory() {
return "org.bukkit.craftbukkit." + getNmsSuffix();
}
public static String getNMSDirectory() {
return "net.minecraft.server." + getNmsSuffix();
}
/**
* Returns if the current version is more up to date than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is lower, false if it is equal or higher
* than the server's version.
*/
public boolean isHigherThan(final ServerVersion version) {
return protocolId > version.protocolId;
}
/**
* Returns if the current version is more up to date than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is lower or equal, false if it is higher
* than the server's version.
*/
public boolean isAtLeast(final ServerVersion version) {
return protocolId >= version.protocolId;
}
public static String getOBCDirectory() {
return "org.bukkit.craftbukkit." + getNmsSuffix();
}
/**
* Returns if the current version is more older than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is higher, false if it is equal or lower
* than the server's version.
*/
public boolean isLowerThan(final ServerVersion version) {
return version.protocolId > protocolId;
}
/**
* Returns if the current version is more older than the argument passed
* version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is higher or equal, false if it is lower
* than the server's version.
*/
public boolean isAtMost(final ServerVersion version) {
return version.protocolId >= protocolId;
}
/**
* Returns if the current version is more up to date than the argument passed version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is lower, false if it is equal or higher than the server's version.
*/
public boolean isHigherThan(final ServerVersion version) {
if (this == version) return false;
return !isLowerThan(version);
}
/**
* Returns if the current version is more outdated than the argument passed version
*
* @param version The version to compare to the server's value.
* @return True if the supplied version is higher, false if it is equal or lower than the server's version.
*/
public boolean isLowerThan(final ServerVersion version) {
if (this == version) return false;
final int len = ServerVersion.values().length;
for (byte i = 0; i < len; i++) {
final ServerVersion v = ServerVersion.values()[i];
if (v == this) {
return true;
} else if (v == version) {
return false;
}
}
return false;
}
/**
* Converts the server version to a protocol version.
* Recommended to cache.
* @return protocol version
*/
public short toProtocolVersion() {
switch (this) {
case v_1_7_10:
return 5;
case v_1_8:
case v_1_8_3:
case v_1_8_4:
case v_1_8_5:
case v_1_8_6:
case v_1_8_7:
case v_1_8_8:
return 47;
case v_1_9:
return 107;
case v_1_9_2:
return 109;
case v_1_9_4:
return 110;
case v_1_10:
case v_1_10_2:
return 210;
case v_1_11:
return 315;
case v_1_11_1:
case v_1_11_2:
return 316;
case v_1_12:
return 335;
case v_1_12_1:
return 338;
case v_1_12_2:
return 340;
case v_1_13:
return 393;
case v_1_13_1:
return 401;
case v_1_13_2:
return 404;
case v_1_14:
return 477;
case v_1_14_1:
return 480;
case v_1_14_2:
return 485;
case v_1_14_3:
return 490;
case v_1_14_4:
return 498;
case v_1_15:
return 573;
case v_1_15_1:
return 575;
case v_1_15_2:
return 578;
case v_1_16:
return 735;
case v_1_16_1:
return 736;
case v_1_16_2:
return 751;
case v_1_16_3:
return 753;
default:
return -1;
}
}
}
@@ -1,56 +0,0 @@
/*
* MIT License
*
* Copyright (c) 2020 retrooper
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.vector;
public class Vector3i {
public int x, y, z;
public Vector3i() {
}
public Vector3i(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Vector3i(int[] coordinates) {
x = coordinates[0];
y = coordinates[1];
z = coordinates[2];
}
public final int getX() {
return x;
}
public final int getY() {
return y;
}
public final int getZ() {
return z;
}
}
@@ -25,9 +25,9 @@
package io.github.retrooper.packetevents.utils.versionlookup;
import io.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.protocollib.ProtocolLibUtils;
import io.github.retrooper.packetevents.utils.protocolsupport.ProtocolSupportUtils;
import io.github.retrooper.packetevents.utils.server.ServerVersion;
import io.github.retrooper.packetevents.utils.v_1_7_10.ProtocolVersionAccessor_v_1_7;
import io.github.retrooper.packetevents.utils.viaversion.ViaUtils;
import org.bukkit.entity.Player;
@@ -36,7 +36,7 @@ public class VersionLookupUtils {
private static byte protocolAccessMode = -2;
public static void handleLoadedDependencies() {
public static void load() {
protocolAccessMode = (byte) (ViaUtils.isAvailable() ?
0 : ProtocolSupportUtils.isAvailable() ?
1 : ProtocolLibUtils.isAvailable() ?
@@ -44,15 +44,10 @@ public class VersionLookupUtils {
3 : -1);
}
public static boolean hasHandledLoadedDependencies() {
public static boolean hasLoaded() {
return protocolAccessMode != -2;
}
public static boolean isDependencyAvailable() {
return ViaUtils.isAvailable()
|| ProtocolSupportUtils.isAvailable()
|| ProtocolLibUtils.isAvailable();
}
/**
@@ -65,7 +60,7 @@ public class VersionLookupUtils {
* @return protocol version of the player if ViaVersion or ProtocolSupport or ProtocolLib is present. Otherwise -1
*/
public static int getProtocolVersion(final Player player) {
switch (protocolAccessMode) {
switch(protocolAccessMode) {
case 0:
return ViaUtils.getProtocolVersion(player);
case 1:
@@ -22,12 +22,13 @@
* SOFTWARE.
*/
package io.github.retrooper.packetevents.utils.server;
package io.github.retrooper.packetevents.version;
import java.util.ArrayList;
import java.util.List;
//I was lazy while making this class, I know
public class PEVersion {
private final int[] version = new int[4];
@@ -35,9 +36,18 @@ public class PEVersion {
if (version.length > 4) {
throw new IllegalArgumentException("You are not allowed to have more than 4 arguments!");
} else if (version.length < 2) {
throw new IllegalArgumentException("You need at least two arguments.");
throw new IllegalArgumentException("You need atleast two arguments.");
}
int len = version.length;
if (len < 4) {
this.version[0] = version[0];
this.version[1] = version[1];
if (len == 3) {
this.version[2] = version[2];
}
} else {
System.arraycopy(version, 0, this.version, 0, version.length);
}
System.arraycopy(version, 0, this.version, 0, version.length);
}
public PEVersion(String text) {
@@ -49,8 +59,7 @@ public class PEVersion {
text += ".";
int dotCount = 0;
char[] chars = text.toCharArray();
for (char c : chars) {
for (char c : text.toCharArray()) {
if (c == '.') {
dotCount++;
}
@@ -61,12 +70,12 @@ public class PEVersion {
int[] version = new int[4];
// String t = "1.2.3.4";
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
for (int i = 0; i < text.toCharArray().length; i++) {
char c = text.toCharArray()[i];
if (c == '.') {
version[arrayIndex++] =
Integer.parseInt(Character.toString(chars[i - 1]));
Integer.parseInt(Character.toString(text.toCharArray()[i - 1]));
}
}
return version;
@@ -98,23 +107,26 @@ public class PEVersion {
return false;
}
// TODO: Remove "AsByteArray"
public final int[] getVersionAsByteArray() {
return version;
}
// TODO: Remove "AsByteArray"
public final int[] getVersionAsByteArrayShortened() {
int length = 2;
if(version[2] != 0) {
length++;
List<Integer> versionBoxed = new ArrayList<>();
if (version[3] == 0) {
versionBoxed.add(version[0]);
versionBoxed.add(version[1]);
versionBoxed.add(version[2]);
if (version[2] == 0) {
versionBoxed.clear();
versionBoxed.add(version[0]);
versionBoxed.add(version[1]);
}
return convertIntListToIntArray(versionBoxed);
} else {
return version;
}
if(version[3] != 0) {
length++;
}
int[] shortened = new int[length];
System.arraycopy(version, 0, shortened, 0, length);
return shortened;
}
private int[] convertIntListToIntArray(List<Integer> list) {