Compare commits

..
12 Commits
214 changed files with 4017 additions and 13301 deletions

No files matched your search

+8 -17
View File
@@ -2,21 +2,21 @@
## Eclipse
#################
# Generic project files
.project
.classpath
.settings/
bin/
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
target/
.gitignore
# External tool builders
.externalToolBuilders/
@@ -30,12 +30,6 @@ local.properties
# PDT-specific
.buildpath
#################
## Maven
#################
target/
dependency-reduced-pom.xml
#################
## Visual Studio
@@ -161,14 +155,11 @@ pip-log.txt
.coverage
.tox
# Translations
#Translations
*.mo
# Mr Developer
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
# Log4J files
logs/
-13
View File
@@ -1,13 +0,0 @@
language: java
jdk:
- oraclejdk8
- oraclejdk7
script: mvn clean test -U
before_install: cd ProtocolLib
install: true
notifications:
email:
recipients:
- "dmulloy2@live.com"
on_success: change
on_failure: always
+165
View File
@@ -0,0 +1,165 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
target/
.gitignore
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
@@ -1,27 +1,27 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.comphenix.itemdisguise</groupId>
<artifactId>ItemDisguise</artifactId>
<version>1.1.0</version>
<version>1.0.0</version>
<name>Item Disguise</name>
<description>Change the appearance of inventory items.</description>
<properties>
<project.build.sourceEncoding>cp1252</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
<id>bukkit-rep</id>
<url>http://repo.bukkit.org/content/groups/public</url>
</repository>
<repository>
<id>dmulloy2-repo</id>
<url>http://repo.dmulloy2.net/content/groups/public/</url>
<id>comphenix-rep</id>
<name>Comphenix Maven Releases</name>
<url>http://repo.comphenix.net/content/groups/public</url>
</repository>
</repositories>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
@@ -43,13 +43,13 @@
</plugin>
</plugins>
</build>
<scm>
<connection>scm:git:git://github.com/aadnk/ProtocolLib.git</connection>
<developerConnection>scm:git:git@github.com:aadnk/ProtocolLib.git</developerConnection>
<url>https://github.com/aadnk/ProtocolLib</url>
</scm>
<licenses>
<license>
<name>GNU GENERAL PUBLIC LICENSE - Version 2, June 1991</name>
@@ -58,21 +58,15 @@
</license>
</licenses>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.8.7-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.8.7-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>3.6.4</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.3.2-R1.0</version>
</dependency>
<dependency>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
</project>
@@ -2,16 +2,16 @@
* ItemDisguise - A simple Bukkit plugin that illustrates how to use ProtocolLib.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -25,8 +25,8 @@ import org.bukkit.enchantments.Enchantment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
@@ -36,52 +36,62 @@ public class HideEnchantmentsListener {
private final Server server;
private final Logger logger;
public HideEnchantmentsListener(Server server, Logger logger) {
this.server = server;
this.logger = logger;
}
public void addListener(ProtocolManager protocolManager, JavaPlugin plugin) {
// Hide all enchantments
protocolManager.addPacketListener(new PacketAdapter(plugin, PacketType.Play.Server.SET_SLOT, PacketType.Play.Server.WINDOW_ITEMS,
PacketType.Play.Server.NAMED_SOUND_EFFECT) {
protocolManager.addPacketListener(new PacketAdapter(plugin, ConnectionSide.SERVER_SIDE, 0x67, 0x68, 0x3E) {
@Override
public void onPacketSending(PacketEvent event) {
PacketContainer packet = event.getPacket();
try {
// Item packets
if (event.getPacketType() == PacketType.Play.Server.SET_SLOT) {
switch (event.getPacketID()) {
case 0x67: // Set slot
removeEnchantments(packet.getItemModifier().read(0));
} else if (event.getPacketType() == PacketType.Play.Server.WINDOW_ITEMS) {
break;
case 0x68: // Set Window Items
ItemStack[] elements = packet.getItemArrayModifier().read(0);
for (int i = 0; i < elements.length; i++) {
if (elements[i] != null) {
removeEnchantments(elements[i]);
}
}
} else if (event.getPacketType() == PacketType.Play.Server.NAMED_SOUND_EFFECT) {
break;
case 0x3E: // Sound effect
event.setCancelled(true);
break;
}
} catch (FieldAccessException e) {
logger.log(Level.SEVERE, "Couldn't access field.", e);
}
}
});
// Censor
protocolManager.addPacketListener(new PacketAdapter(plugin, PacketType.Play.Client.CHAT) {
protocolManager.addPacketListener(new PacketAdapter(plugin, ConnectionSide.CLIENT_SIDE, 0x3) {
@Override
public void onPacketReceiving(PacketEvent event) {
if (event.getPacketType() == PacketType.Play.Client.CHAT) {
if (event.getPacketID() == 0x3) {
try {
String message = event.getPacket().getSpecificModifier(String.class).read(0);
String message = event.getPacket().
getSpecificModifier(String.class).read(0);
if (message.contains("shit") || message.contains("fuck")) {
event.setCancelled(true);
event.getPlayer().sendMessage("Bad manners!");
}
} catch (FieldAccessException e) {
logger.log(Level.SEVERE, "Couldn't access field.", e);
}
@@ -89,23 +99,24 @@ public class HideEnchantmentsListener {
}
});
}
public Server getServer() {
return server;
}
public void removeListener(ProtocolManager protocolManager, JavaPlugin plugin) {
// Just remove every adapter with this plugin
protocolManager.removePacketListeners(plugin);
}
private void removeEnchantments(ItemStack stack) {
if (stack == null)
return;
Enchantment[] copy = stack.getEnchantments().keySet().toArray(new Enchantment[0]);
for (Enchantment enchantment : copy) {
stack.removeEnchantment(enchantment);
Object[] copy = stack.getEnchantments().keySet().toArray();
for (Object enchantment : copy) {
stack.removeEnchantment((Enchantment) enchantment);
}
}
}
@@ -2,16 +2,16 @@
* ItemDisguise - A simple Bukkit plugin that illustrates how to use ProtocolLib.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -24,23 +24,23 @@ import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.ProtocolManager;
import com.comphenix.protocol.events.PacketContainer;
public class ItemDisguiseMod extends JavaPlugin {
private ProtocolManager protocolManager;
private Logger logger;
private HideEnchantmentsListener enchantmentsListener;
@Override
public void onEnable() {
logger = getLoggerSafely();
protocolManager = ProtocolLibrary.getProtocolManager();
enchantmentsListener = new HideEnchantmentsListener(getServer(), logger);
enchantmentsListener.addListener(protocolManager, this);
}
@@ -49,42 +49,49 @@ public class ItemDisguiseMod extends JavaPlugin {
public void onDisable() {
enchantmentsListener.removeListener(protocolManager, this);
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
if (label.equalsIgnoreCase("explosion")) {
PacketContainer fakeExplosion = protocolManager.createPacket(PacketType.Play.Server.EXPLOSION);
PacketContainer fakeExplosion = protocolManager.createPacket(0x3C);
// Set the coordinates
try {
fakeExplosion.getSpecificModifier(double.class).write(0, player.getLocation().getX()).write(1, player.getLocation().getY()).write(2, player.getLocation().getZ());
fakeExplosion.getSpecificModifier(float.class).write(0, 3.0F);
fakeExplosion.getSpecificModifier(double.class).
write(0, player.getLocation().getX()).
write(1, player.getLocation().getY()).
write(2, player.getLocation().getZ());
fakeExplosion.getSpecificModifier(float.class).
write(0, 3.0F);
protocolManager.sendServerPacket(player, fakeExplosion);
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
return false;
}
// Get the Bukkit logger first, before we try to create our own
private Logger getLoggerSafely() {
Logger log = null;
try {
log = getLogger();
} catch (Throwable e) {
// We'll handle it
}
if (log == null)
log = Logger.getLogger("Minecraft");
return log;
+165
View File
@@ -0,0 +1,165 @@
#################
## Eclipse
#################
*.pydevproject
.project
.metadata
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.classpath
.settings/
.loadpath
target/
.gitignore
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# PDT-specific
.buildpath
#################
## Visual Studio
#################
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Build results
[Dd]ebug/
[Rr]elease/
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.vspscc
.builds
*.dotCover
## TODO: If you have NuGet Package Restore enabled, uncomment this
#packages/
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
# Visual Studio profiler
*.psess
*.vsp
# ReSharper is a .NET coding add-in
_ReSharper*
# Installshield output folder
[Ee]xpress
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish
# Others
[Bb]in
[Oo]bj
sql
TestResults
*.Cache
ClientBin
stylecop.*
~$*
*.dbmdl
Generated_Code #added for RIA/Silverlight projects
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
############
## Windows
############
# Windows image file caches
Thumbs.db
# Folder config file
Desktop.ini
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
@@ -3,25 +3,32 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.comphenix.tinyprotocol</groupId>
<artifactId>TinyProtocol</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>0.1.0</version>
<name>TinyProtocol</name>
<description>Intercept packets without ProtocolLib.</description>
<parent>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib-Parent</artifactId>
<version>v3-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<distributionManagement>
<repository>
<id>comphenix-releases</id>
<name>Comphenix Maven Releases</name>
<url>http://repo.comphenix.net/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>comphenix-snapshots</id>
<name>Comphenix Maven Snapshots</name>
<url>http://repo.comphenix.net/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
<id>md_5-repo</id>
<url>http://repo.md-5.net/content/repositories/public/</url>
</repository>
<repository>
<id>dmulloy2-repo</id>
<url>http://repo.dmulloy2.net/content/groups/public/</url>
<id>comphenix-rep</id>
<name>Comphenix Maven Releases</name>
<url>http://repo.comphenix.net/content/groups/public</url>
</repository>
</repositories>
@@ -42,34 +49,6 @@
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<finalName>TinyProtocol</finalName>
<outputDirectory>../../target/</outputDirectory>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-javadocs</id>
</execution>
</executions>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
@@ -77,13 +56,12 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.8.7-R0.1-SNAPSHOT</version>
<version>1.7.10-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.8.7-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<version>1.7.10-R0.1-SNAPSHOT</version>
</dependency>
</dependencies>
@@ -1,7 +1,5 @@
package com.comphenix.tinyprotocol;
import io.netty.channel.Channel;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.Command;
@@ -12,13 +10,13 @@ import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.tinyprotocol.Reflection.ConstructorInvoker;
import com.comphenix.tinyprotocol.Reflection.FieldAccessor;
/**
* Represents an example plugin utilizing TinyProtocol
*/
import net.minecraft.util.io.netty.channel.Channel;
public class ExamplePlugin extends JavaPlugin {
// Chat packets
private FieldAccessor<String> CHAT_MESSAGE = Reflection.getField("{nms}.PacketPlayInChat", String.class, 0);
private FieldAccessor<String> CHAT_MESSAGE = Reflection.getField(
"{nms}.PacketPlayInChat", String.class, 0);
// Explosion packet
private Class<?> particleClass = Reflection.getClass("{nms}.PacketPlayOutWorldParticles");
private FieldAccessor<String> particleName = Reflection.getField(particleClass, String.class, 0);
@@ -26,7 +24,7 @@ public class ExamplePlugin extends JavaPlugin {
private FieldAccessor<Float> particleY = Reflection.getField(particleClass, float.class, 1);
private FieldAccessor<Float> particleZ = Reflection.getField(particleClass, float.class, 2);
private FieldAccessor<Integer> particleCount = Reflection.getField(particleClass, int.class, 0);
// Server info packet
private Class<?> serverInfoClass = Reflection.getClass("{nms}.PacketStatusOutServerInfo");
private Class<Object> serverPingClass = Reflection.getUntypedClass("{nms}.ServerPing");
@@ -34,13 +32,12 @@ public class ExamplePlugin extends JavaPlugin {
private FieldAccessor<Object> serverPing = Reflection.getField(serverInfoClass, serverPingClass, 0);
private FieldAccessor<Object> playerSample = Reflection.getField(serverPingClass, playerSampleClass, 0);
private ConstructorInvoker playerSampleInvoker = Reflection.getConstructor(playerSampleClass, int.class, int.class);
private TinyProtocol protocol;
@Override
public void onEnable() {
protocol = new TinyProtocol(this) {
@Override
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
// Cancel chat packets
@@ -50,28 +47,24 @@ public class ExamplePlugin extends JavaPlugin {
return null;
}
}
if (particleName.hasField(packet)) {
System.out.println("Sending particle field:" + packet);
}
return super.onPacketInAsync(sender, channel, packet);
}
@Override
public Object onPacketOutAsync(Player reciever, Channel channel, Object packet) {
if (serverInfoClass.isInstance(packet)) {
Object ping = serverPing.get(packet);
playerSample.set(ping, playerSampleInvoker.invoke(1000, 0));
// Which is equivalent to:
// serverPing.get(packet).setPlayerSample(new ServerPingPlayerSample(1000, 0));
//serverPing.get(packet).setPlayerSample(new ServerPingPlayerSample(1000, 0));
return packet;
}
return super.onPacketOutAsync(reciever, channel, packet);
}
};
}
@@ -79,7 +72,7 @@ public class ExamplePlugin extends JavaPlugin {
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (sender instanceof Player) {
Player player = (Player) sender;
// Toggle injection
if (protocol.hasInjected(player)) {
protocol.uninjectPlayer(player);
@@ -88,15 +81,13 @@ public class ExamplePlugin extends JavaPlugin {
protocol.injectPlayer(player);
sender.sendMessage(ChatColor.DARK_GREEN + "Player " + player + " has been injected.");
}
return true;
} else {
sender.sendMessage(ChatColor.RED + "Can only be invoked by a player.");
}
return false;
}
}
private void sendExplosion(Player player) {
try {
// Only visible for the client
@@ -110,8 +101,9 @@ public class ExamplePlugin extends JavaPlugin {
// Send the packet to the player
protocol.sendPacket(player, explosionPacket);
} catch (Exception e) {
throw new RuntimeException("Cannot send packet.", e);
}
}
}
}
@@ -0,0 +1,375 @@
package com.comphenix.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.
*/
public 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.
*/
public 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.
*/
public 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.
*/
public 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.
*/
public 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>() {
@SuppressWarnings("unchecked")
@Override
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 publically 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 publically 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 publically 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<Object>)(Class)getClass(lookupName);
return clazz;
}
/**
* Retrieve a class from its full name.
* <p>
* Strings enclosed with curly brackets - such as {TEXT} - will be replaced according
* to the following table:
* <p>
* <table border="1">
* <tr>
* <th>Variable</th>
* <th>Content</th>
* </tr>
* <tr>
* <td>{nms}</td>
* <td>Actual package name of net.minecraft.server.VERSION</td>
* </tr>
* <tr>
* <td>{obc}</td>
* <td>Actual pacakge name of org.bukkit.craftbukkit.VERSION</td>
* </tr>
* <tr>
* <td>{version}</td>
* <td>The current Minecraft package VERSION, if any.</td>
* </tr>
* </table>
* @param lookupName - the class name with variables.
* @return The looked up class.
* @throws IllegalArgumentException If a variable or class could not be found.
*/
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,14 +1,5 @@
package com.comphenix.tinyprotocol;
import io.netty.channel.Channel;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -17,6 +8,17 @@ import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import net.minecraft.util.com.mojang.authlib.GameProfile;
// These are not versioned, but they require CraftBukkit
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelDuplexHandler;
import net.minecraft.util.io.netty.channel.ChannelFuture;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.util.io.netty.channel.ChannelInitializer;
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;
import org.bukkit.event.EventHandler;
@@ -26,213 +28,182 @@ 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 com.comphenix.tinyprotocol.Reflection.FieldAccessor;
import com.comphenix.tinyprotocol.Reflection.MethodInvoker;
import com.google.common.collect.Lists;
import com.google.common.collect.MapMaker;
import com.mojang.authlib.GameProfile;
/**
* Represents a very tiny alternative to ProtocolLib.
* Represents a very tiny alternative to ProtocolLib in 1.7.2.
* <p>
* It now supports intercepting packets during login and status ping (such as OUT_SERVER_PING)!
*
* @author Kristian
*/
public abstract class TinyProtocol {
private static final AtomicInteger ID = new AtomicInteger(0);
// 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 FieldAccessor<GameProfile> getGameProfile = Reflection.getField(PACKET_LOGIN_IN_START, GameProfile.class, 0);
// Speedup channel lookup
private Map<String, Channel> channelLookup = new MapMaker().weakValues().makeMap();
private Listener listener;
// Channels that have already been removed
private 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.
* 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 TinyProtocol(final Plugin plugin) {
public TinyProtocol(Plugin plugin) {
this.plugin = plugin;
// Compute handler name
this.handlerName = getHandlerName();
// Prepare existing players
registerBukkitEvents();
try {
registerChannelHandler();
registerPlayers(plugin);
} catch (IllegalArgumentException ex) {
// Damn you, late bind
plugin.getLogger().info("[TinyProtocol] Delaying server channel injection due to late bind.");
// Damn you, late bind
new BukkitRunnable() {
@Override
public void run() {
registerChannelHandler();
registerPlayers(plugin);
plugin.getLogger().info("[TinyProtocol] Late bind injection successful.");
}
}.runTask(plugin);
}
registerChannelHandler();
registerPlayers(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) {
injectChannelInternal(channel);
}
// 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)
return;
injectChannelInternal(channel);
}
} catch (Exception e) {
plugin.getLogger().log(Level.SEVERE, "Cannot inject incomming channel " + channel, e);
}
}
} 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;
};
// 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);
}
};
// Prepare to initialize ths channel
channel.pipeline().addFirst(beginInitProtocol);
ctx.fireChannelRead(msg);
}
};
}
/**
* Register bukkit events.
*/
private void registerBukkitEvents() {
listener = new Listener() {
@EventHandler(priority = EventPriority.LOWEST)
public final void onPlayerLogin(PlayerLoginEvent e) {
if (closed)
if (closed)
return;
Channel channel = getChannel(e.getPlayer());
// Don't inject players that have been explicitly uninjected
if (!uninjectedChannels.contains(channel)) {
injectPlayer(e.getPlayer());
}
}
@EventHandler
public final void onPluginDisable(PluginDisableEvent e) {
if (e.getPlugin().equals(plugin)) {
close();
}
}
};
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
this.plugin.getServer().getPluginManager().registerEvents(listener, plugin);
}
@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 (!ChannelFuture.class.isInstance(item))
if (!ChannelFuture.class.isInstance(item))
break;
// Channel future that contains the server connection
Channel serverChannel = ((ChannelFuture) item).channel();
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);
@@ -240,24 +211,21 @@ public abstract class TinyProtocol {
// 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 reciever - the receiving player, NULL for early login/status packets.
* @param channel - the channel that received the packet. Never NULL.
* @param remoteAddress - remote address of the sending client. Never NULL.
* @param packet - the packet being sent.
* @return The packet to send instead, or NULL to cancel the transmission.
@@ -270,7 +238,6 @@ public abstract class TinyProtocol {
* 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.
@@ -279,145 +246,133 @@ public abstract class TinyProtocol {
public Object onPacketInAsync(Player sender, Channel channel, Object packet) {
return packet;
}
/**
* Send a packet to a particular player.
* <p>
* Note that {@link #onPacketOutAsync(Player, 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, 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);
}
/**
* Pretend that a given packet has been received from a player.
* <p>
* Note that {@link #onPacketInAsync(Player, 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, 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 "tiny-" + plugin.getName() + "-" + ID.incrementAndGet();
}
/**
* Add a custom channel handler to the given player's channel pipeline, allowing us to intercept sent and received packets.
* 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;
}
/**
* Add a custom channel handler to the given channel.
*
* @param player - the channel to inject.
* @return The intercepted channel, or NULL if it has already been injected.
*/
public void injectChannel(Channel channel) {
injectChannelInternal(channel);
}
/**
* Add a custom channel handler to the given channel.
*
* @param player - 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;
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));
}
/**
* 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) {
@@ -425,95 +380,88 @@ public abstract class TinyProtocol {
if (!closed) {
uninjectedChannels.add(channel);
}
// See ChannelInjector in ProtocolLib, line 590
channel.eventLoop().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 {
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);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
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);
}
}
private void handleLoginStart(Channel channel, Object packet) {
if (PACKET_LOGIN_IN_START.isInstance(packet)) {
GameProfile profile = getGameProfile.get(packet);
@@ -521,4 +469,4 @@ public abstract class TinyProtocol {
}
}
}
}
}
-2
View File
@@ -163,5 +163,3 @@ pip-log.txt
# Mac crap
.DS_Store
/target
/target
+53 -84
View File
@@ -1,26 +1,42 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>ProtocolLib</artifactId>
<name>ProtocolLib</name>
<version>3.6.5</version>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib-Legacy</artifactId>
<version>3.7.0</version>
<name>ProtocolLib-Legacy</name>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>http://www.spigotmc.org/resources/protocollib.1997/</url>
<packaging>jar</packaging>
<parent>
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib-Parent</artifactId>
<version>v3-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.number></project.build.number>
<project.build.sourceEncoding>cp1252</project.build.sourceEncoding>
<powermock.version>1.5</powermock.version>
</properties>
<distributionManagement>
<repository>
<id>dmulloy2-releases</id>
<url>http://repo.dmulloy2.net/content/repositories/releases/</url>
</repository>
<snapshotRepository>
<id>dmulloy2-snapshots</id>
<url>http://repo.dmulloy2.net/content/repositories/snapshots/</url>
</snapshotRepository>
</distributionManagement>
<repositories>
<repository>
<id>dmulloy2-repo</id>
<url>http://repo.dmulloy2.net/content/groups/public/</url>
</repository>
<repository>
<id>md_5-repo</id>
<url>http://repo.md-5.net/content/repositories/public/</url>
</repository>
</repositories>
<build>
<defaultGoal>clean install</defaultGoal>
<sourceDirectory>src/main/java</sourceDirectory>
@@ -39,7 +55,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<version>2.0</version>
<executions>
<execution>
<phase>package</phase>
@@ -71,7 +87,7 @@
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
@@ -81,40 +97,19 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
<version>2.1</version>
<configuration>
<archive>
<manifestEntries>
<Main-Class>com.comphenix.protocol.Application</Main-Class>
<Implementation-Title>ProtocolLib</Implementation-Title>
<Implementation-Version>${project.version}${project.build.number}</Implementation-Version>
<Implementation-Vendor>dmulloy2</Implementation-Vendor>
</manifestEntries>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
<finalName>ProtocolLib</finalName>
<finalName>${project.name}</finalName>
</configuration>
</plugin>
<!--<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<phase>package</phase>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
<goal>javadoc</goal>
</goals>
</execution>
</executions>
</plugin>-->
</plugins>
</build>
<!--<reporting>
<reporting>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
@@ -125,34 +120,10 @@
<effort>Default</effort>
</configuration>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.7</version>
<configuration>
<failOnError>false</failOnError>
<links>
<link>http://download.oracle.com/javase/6/docs/api/</link>
</links>
</configuration>
</plugin>
</plugins>
</reporting>-->
</reporting>
<profiles>
<profile>
<id>jenkins</id>
<activation>
<property>
<name>env.BUILD_NUMBER</name>
</property>
</activation>
<properties>
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
</properties>
</profile>
<profile>
<id>release-sign-artifacts</id>
<activation>
@@ -166,7 +137,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<version>2.2</version>
<executions>
<execution>
<id>attach-sources</id>
@@ -180,7 +151,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.1</version>
<version>2.9</version>
<executions>
<execution>
<id>attach-javadocs</id>
@@ -194,7 +165,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<version>1.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
@@ -212,9 +183,9 @@
</profiles>
<scm>
<connection>scm:git:git://github.com/dmulloy2/ProtocolLib.git</connection>
<developerConnection>scm:git:git@github.com:dmulloy2/ProtocolLib.git</developerConnection>
<url>https://github.com/dmulloy2/ProtocolLib</url>
<connection>scm:git:git://github.com/aadnk/ProtocolLib.git</connection>
<developerConnection>scm:git:git@github.com:aadnk/ProtocolLib.git</developerConnection>
<url>https://github.com/aadnk/ProtocolLib</url>
</scm>
<licenses>
@@ -248,18 +219,6 @@
</developers>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.8.8-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.8.8-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
@@ -272,6 +231,16 @@
<version>1.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.7.10-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -287,13 +256,13 @@
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.5</version>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.5</version>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -52,7 +52,7 @@ public interface AsynchronousManager {
/**
* Unregisters and closes the first asynchronous handler associated with the given listener.
* @param listener - asynchronous listener
* @param handler - asynchronous handler.
*/
public abstract void unregisterAsyncHandler(PacketListener listener);
@@ -63,7 +63,7 @@ public interface AsynchronousManager {
public void unregisterAsyncHandlers(Plugin plugin);
/**
* Retrieves a immutable set containing the ID of the sent server packets that will be
* Retrieves a immutable set containing the ID of the sent server packets that will be
* observed by the asynchronous listeners.
* <p>
* Deprecated: Use {@link #getSendingTypes()} instead.
@@ -73,7 +73,7 @@ public interface AsynchronousManager {
public abstract Set<Integer> getSendingFilters();
/**
* Retrieves a immutable set containing the types of the sent server packets that will be
* Retrieves a immutable set containing the types of the sent server packets that will be
* observed by the asynchronous listeners.
* @return Every filtered server packet.
*/
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -66,7 +66,6 @@ abstract class CommandBase implements CommandExecutor {
reporter.reportWarning(this, Report.newBuilder(REPORT_UNEXPECTED_COMMAND).messageParam(this));
return false;
}
if (permission != null && !sender.hasPermission(permission)) {
sender.sendMessage(ChatColor.RED + "You haven't got permission to run this command.");
return true;
@@ -76,12 +75,13 @@ abstract class CommandBase implements CommandExecutor {
if (args != null && args.length >= minimumArgumentCount) {
return handleCommand(sender, args);
} else {
sender.sendMessage(ChatColor.RED + "Insufficient arguments. You need at least " + minimumArgumentCount);
sender.sendMessage(ChatColor.RED + "Insufficient commands. You need at least " + minimumArgumentCount);
return false;
}
} catch (Throwable ex) {
reporter.reportDetailed(this,
Report.newBuilder(REPORT_COMMAND_ERROR).error(ex).messageParam(name).callerParam(sender, label, args)
} catch (Exception e) {
reporter.reportDetailed(this,
Report.newBuilder(REPORT_COMMAND_ERROR).error(e).messageParam(name).callerParam(sender, label, args)
);
return true;
}
@@ -295,7 +295,7 @@ public class CommandFilter extends CommandBase {
@Override
public boolean handle(PacketEvent event, Filter filter, Exception ex) {
reporter.reportMinimal(plugin, "filterEvent(PacketEvent)", ex, event);
reporter.reportWarning(this,
reporter.reportWarning(this,
Report.newBuilder(REPORT_FILTER_REMOVED_FOR_ERROR).messageParam(filter.getName(), ex.getClass().getSimpleName())
);
return false;
@@ -321,6 +321,7 @@ public class CommandFilter extends CommandBase {
* @param event - the event.
* @param handler - failure handler.
* @return TRUE if we should, FALSE otherwise.
* @throws FilterFailedException If one of the filters failed.
*/
public boolean filterEvent(PacketEvent event, FilterFailedHandler handler) {
for (Iterator<Filter> it = filters.iterator(); it.hasNext(); ) {
@@ -388,7 +389,7 @@ public class CommandFilter extends CommandBase {
// Make sure we can use the conversable interface
if (sender instanceof Conversable) {
final MultipleLinesPrompt prompt =
final MultipleLinesPrompt prompt =
new MultipleLinesPrompt(new CompilationSuccessCanceller(), "function(event, packet) {");
new ConversationFactory(plugin).
@@ -423,7 +424,7 @@ public class CommandFilter extends CommandBase {
whom.sendRawMessage(ChatColor.RED + "Cancelled filter.");
}
} catch (Exception e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_HANDLE_CONVERSATION).error(e).callerParam(event)
);
}
@@ -1,4 +1,4 @@
/**
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
@@ -14,30 +14,20 @@
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
import java.util.logging.Level;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import com.comphenix.protocol.error.DetailedErrorReporter;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.timing.TimedListenerManager;
import com.comphenix.protocol.timing.TimingReportGenerator;
import com.comphenix.protocol.updater.Updater;
import com.comphenix.protocol.updater.Updater.UpdateType;
import com.comphenix.protocol.utility.Closer;
/**
* Handles the "protocol" administration command.
@@ -49,105 +39,55 @@ class CommandProtocol extends CommandBase {
* Name of this command.
*/
public static final String NAME = "protocol";
private Plugin plugin;
private Updater updater;
private ProtocolConfig config;
public CommandProtocol(ErrorReporter reporter, Plugin plugin, Updater updater, ProtocolConfig config) {
public CommandProtocol(ErrorReporter reporter, Plugin plugin, ProtocolConfig config) {
super(reporter, CommandBase.PERMISSION_ADMIN, NAME, 1);
this.plugin = plugin;
this.updater = updater;
this.config = config;
}
@Override
protected boolean handleCommand(CommandSender sender, String[] args) {
String subCommand = args[0];
// Only return TRUE if we executed the correct command
if (subCommand.equalsIgnoreCase("config") || subCommand.equalsIgnoreCase("reload")) {
if (subCommand.equalsIgnoreCase("config") || subCommand.equalsIgnoreCase("reload"))
reloadConfiguration(sender);
} else if (subCommand.equalsIgnoreCase("check")) {
checkVersion(sender, true);
} else if (subCommand.equalsIgnoreCase("update")) {
updateVersion(sender, true);
} else if (subCommand.equalsIgnoreCase("timings")) {
else if (subCommand.equalsIgnoreCase("timings"))
toggleTimings(sender, args);
} else if (subCommand.equalsIgnoreCase("listeners")) {
printListeners(sender);
} else if (subCommand.equalsIgnoreCase("version")) {
printVersion(sender);
} else if (subCommand.equalsIgnoreCase("dump")) {
dump(sender);
} else {
else if (subCommand.equalsIgnoreCase("listeners"))
printListeners(sender, args);
else
return false;
}
return true;
}
public void checkVersion(final CommandSender sender, boolean command) {
performUpdate(sender, UpdateType.NO_DOWNLOAD, command);
}
public void updateVersion(final CommandSender sender, boolean command) {
performUpdate(sender, UpdateType.DEFAULT, command);
}
// Display every listener on the server
private void printListeners(final CommandSender sender) {
private void printListeners(final CommandSender sender, String[] args) {
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
sender.sendMessage(ChatColor.GOLD + "Packet listeners:");
for (PacketListener listener : manager.getPacketListeners()) {
sender.sendMessage(ChatColor.GOLD + " - " + listener);
sender.sendMessage(ChatColor.GOLD + "Packet listeners:");
sender.sendMessage(ChatColor.GOLD + " " + listener);
}
// Along with every asynchronous listener
sender.sendMessage(ChatColor.GOLD + "Asynchronous listeners:");
for (PacketListener listener : manager.getAsynchronousManager().getAsyncHandlers()) {
sender.sendMessage(ChatColor.GOLD + " - " + listener);
sender.sendMessage(ChatColor.GOLD + "Asynchronous listeners:");
sender.sendMessage(ChatColor.GOLD + " " + listener);
}
}
private void performUpdate(final CommandSender sender, UpdateType type, final boolean command) {
if (updater.isChecking()) {
sender.sendMessage(ChatColor.RED + "Already checking for an update.");
return;
}
// Perform on an async thread
Runnable notify = new Runnable() {
@Override
public void run() {
if (command) {
sender.sendMessage(ChatColor.YELLOW + "[ProtocolLib] " + updater.getResult());
String remoteVersion = updater.getRemoteVersion();
if (remoteVersion != null) {
sender.sendMessage(ChatColor.YELLOW + "Remote version: " + remoteVersion);
sender.sendMessage(ChatColor.YELLOW + "Current version: " + plugin.getDescription().getVersion());
}
} else if (updater.shouldNotify() || config.isDebug()) {
sender.sendMessage(ChatColor.YELLOW + "[ProtocolLib] " + updater.getResult());
}
updater.removeListener(this);
updateFinished();
}
};
updater.start(type);
updater.addListener(notify);
}
private void toggleTimings(CommandSender sender, String[] args) {
TimedListenerManager manager = TimedListenerManager.getInstance();
boolean state = !manager.isTiming(); // toggle
// Parse the boolean parameter
if (args.length == 2) {
Boolean parsed = parseBoolean(toQueue(args, 2), "start");
if (parsed != null) {
state = parsed;
} else {
@@ -158,7 +98,7 @@ class CommandProtocol extends CommandBase {
sender.sendMessage(ChatColor.RED + "Too many parameters.");
return;
}
// Now change the state
if (state) {
if (manager.startTiming())
@@ -174,21 +114,21 @@ class CommandProtocol extends CommandBase {
}
}
}
private void saveTimings(TimedListenerManager manager) {
try {
File destination = new File(plugin.getDataFolder(), "Timings - " + System.currentTimeMillis() + ".txt");
TimingReportGenerator generator = new TimingReportGenerator();
// Print to a text file
generator.saveTo(destination, manager);
manager.clear();
} catch (IOException e) {
reporter.reportMinimal(plugin, "saveTimings()", e);
}
}
/**
* Prevent further automatic updates until the next delay.
*/
@@ -198,75 +138,9 @@ class CommandProtocol extends CommandBase {
config.setAutoLastTime(currentTime);
config.saveAll();
}
public void reloadConfiguration(CommandSender sender) {
plugin.reloadConfig();
sender.sendMessage(ChatColor.YELLOW + "Reloaded configuration!");
}
private void printVersion(CommandSender sender) {
PluginDescriptionFile desc = plugin.getDescription();
sender.sendMessage(ChatColor.GREEN + desc.getName() + ChatColor.WHITE + " v" + ChatColor.GREEN + desc.getVersion());
sender.sendMessage(ChatColor.WHITE + "Authors: " + ChatColor.GREEN + "dmulloy2" + ChatColor.WHITE + " and " + ChatColor.GREEN + "Comphenix");
sender.sendMessage(ChatColor.WHITE + "Issues: " + ChatColor.GREEN + "https://github.com/dmulloy2/ProtocolLib/issues");
}
private static SimpleDateFormat FILE_FORMAT;
private static SimpleDateFormat TIMESTAMP_FORMAT;
private void dump(CommandSender sender) {
Closer closer = Closer.create();
if (FILE_FORMAT == null)
FILE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss");
if (TIMESTAMP_FORMAT == null)
TIMESTAMP_FORMAT = new SimpleDateFormat("MM/dd/yy HH:mm:ss");
try {
Date date = new Date();
File file = new File(plugin.getDataFolder(), "dump-" + FILE_FORMAT.format(date) + ".txt");
if (file.exists()) {
file.delete();
}
file.createNewFile();
FileWriter fw = closer.register(new FileWriter(file));
PrintWriter pw = closer.register(new PrintWriter(fw));
pw.println("ProtocolLib Dump");
pw.println("Timestamp: " + TIMESTAMP_FORMAT.format(date));
pw.println();
pw.println("ProtocolLib Version: " + plugin.toString());
pw.println("Bukkit Version: " + plugin.getServer().getBukkitVersion());
pw.println("Server Version: " + plugin.getServer().getVersion());
pw.println("Java Version: " + System.getProperty("java.version"));
pw.println();
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
pw.println("ProtocolLib: " + DetailedErrorReporter.getStringDescription(plugin));
pw.println("Manager: " + DetailedErrorReporter.getStringDescription(manager));
pw.println();
Set<PacketListener> listeners = manager.getPacketListeners();
if (listeners.size() > 0) {
pw.println("Listeners:");
for (PacketListener listener : listeners) {
pw.println(DetailedErrorReporter.getStringDescription(listener));
}
} else {
pw.println("No listeners");
}
sender.sendMessage("Data dump written to " + file.getAbsolutePath());
} catch (IOException ex) {
ProtocolLibrary.log(Level.SEVERE, "Failed to create dump:", ex);
sender.sendMessage(ChatColor.RED + "Failed to create dump! Check console!");
} finally {
closer.close();
}
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -24,7 +24,6 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.injector.netty.WirePacket;
/**
* Represents a object capable of sending or receiving packets.
@@ -38,7 +37,7 @@ public interface PacketStream {
* @param packet - packet to send.
* @throws InvocationTargetException - if an error occured when sending the packet.
*/
public void sendServerPacket(Player receiver, PacketContainer packet)
public void sendServerPacket(Player receiver, PacketContainer packet)
throws InvocationTargetException;
/**
@@ -62,22 +61,6 @@ public interface PacketStream {
public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters)
throws InvocationTargetException;
/**
* Send a wire packet to the given player.
* @param receiver - the receiver.
* @param id - packet id.
* @param bytes - packet bytes.
* @throws InvocationTargetException if an error occured when sending the packet.
*/
public void sendWirePacket(Player receiver, int id, byte[] bytes) throws InvocationTargetException;
/**
* Send a wire packet to the given player.
* @param receiver - the receiver.
* @param packet - packet to send.
* @throws InvocationTargetException if an error occured when sending the packet.
*/
public void sendWirePacket(Player receiver, WirePacket packet) throws InvocationTargetException;
/**
* Simulate recieving a certain packet from a given player.
@@ -86,7 +69,7 @@ public interface PacketStream {
* @throws InvocationTargetException If the reflection machinery failed.
* @throws IllegalAccessException If the underlying method caused an error.
*/
public void recieveClientPacket(Player sender, PacketContainer packet)
public void recieveClientPacket(Player sender, PacketContainer packet)
throws IllegalAccessException, InvocationTargetException;
/**
@@ -4,15 +4,13 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import org.apache.commons.lang.WordUtils;
import org.bukkit.Bukkit;
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
import com.comphenix.protocol.annotations.Spigot;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.reflect.ObjectEnum;
@@ -28,7 +26,8 @@ import com.google.common.util.concurrent.Futures;
/**
* Represents the type of a packet in a specific protocol.
* <p>
* Note that vanilla Minecraft reuses packet IDs per protocol (ping, game, login) and IDs are subject to change, so they are not reliable.
* Note that vanilla Minecraft reuses packet IDs per protocol (ping, game, login), so you cannot
* rely on IDs alone.
* @author Kristian
*/
public class PacketType implements Serializable, Comparable<PacketType> {
@@ -56,7 +55,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
/**
* Legacy name: HANDSHAKE.
*/
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 2, "SetProtocol");
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 2);
private final static Client INSTANCE = new Client();
@@ -107,92 +106,86 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Server extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0, "KeepAlive");
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x01, 1, "Login");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x02, 3, "Chat");
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x03, 4, "UpdateTime");
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x04, 5, "EntityEquipment");
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x05, 6, "SpawnPosition");
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x06, 8, "UpdateHealth");
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x07, 9, "Respawn");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x08, 13, "Position");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16, "HeldItemSlot");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0);
public static final PacketType LOGIN = new PacketType(PROTOCOL, SENDER, 0x01, 1);
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x02, 3);
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x03, 4);
public static final PacketType ENTITY_EQUIPMENT = new PacketType(PROTOCOL, SENDER, 0x04, 5);
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x05, 6);
public static final PacketType UPDATE_HEALTH = new PacketType(PROTOCOL, SENDER, 0x06, 8);
public static final PacketType RESPAWN = new PacketType(PROTOCOL, SENDER, 0x07, 9);
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x08, 13);
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16);
/**
* Note that this was Packets.Server.ENTITY_LOCATION_ACTION.
*/
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x0A, 17, "Bed");
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0B, 18, "Animation");
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x0C, 20, "NamedEntitySpawn");
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x0D, 22, "Collect");
public static final PacketType SPAWN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0E, 23, "SpawnEntity");
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x0F, 24, "SpawnEntityLiving");
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x10, 25, "SpawnEntityPainting");
public static final PacketType BED = new PacketType(PROTOCOL, SENDER, 0x0A, 17);
public static final PacketType ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0B, 18);
public static final PacketType NAMED_ENTITY_SPAWN = new PacketType(PROTOCOL, SENDER, 0x0C, 20);
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x0D, 22);
public static final PacketType SPAWN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x0E, 23);
public static final PacketType SPAWN_ENTITY_LIVING = new PacketType(PROTOCOL, SENDER, 0x0F, 24);
public static final PacketType SPAWN_ENTITY_PAINTING = new PacketType(PROTOCOL, SENDER, 0x10, 25);
public static final PacketType SPAWN_ENTITY_EXPERIENCE_ORB =
new PacketType(PROTOCOL, SENDER, 0x11, 26, "SpawnEntityExperienceOrb");
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x12, 28, "EntityVelocity");
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x13, 29, "EntityDestroy");
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x14, 30, "Entity");
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x15, 31, "RelEntityMove");
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x16, 32, "EntityLook");
public static final PacketType ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x17, 33, "RelEntityMoveLook");
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x18, 34, "EntityTeleport");
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x19, 35, "EntityHeadRotation");
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1A, 38, "EntityStatus");
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x1B, 39, "AttachEntity");
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x1C, 40, "EntityMetadata");
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1D, 41, "EntityEffect");
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1E, 42, "RemoveEntityEffect");
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x1F, 43, "Experience");
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x20, 44, "UpdateAttributes");
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x21, 51, "MapChunk");
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x22, 52, "MultiBlockChange");
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x23, 53, "BlockChange");
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x24, 54, "BlockAction");
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x25, 55, "BlockBreakAnimation");
public static final PacketType MAP_CHUNK_BULK = new PacketType(PROTOCOL, SENDER, 0x26, 56, "MapChunkBulk");
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x27, 60, "Explosion");
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x28, 61, "WorldEvent");
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x29, 62, "NamedSoundEffect");
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x2A, 63, "WorldParticles");
new PacketType(PROTOCOL, SENDER, 0x11, 26);
public static final PacketType ENTITY_VELOCITY = new PacketType(PROTOCOL, SENDER, 0x12, 28);
public static final PacketType ENTITY_DESTROY = new PacketType(PROTOCOL, SENDER, 0x13, 29);
public static final PacketType ENTITY = new PacketType(PROTOCOL, SENDER, 0x14, 30);
public static final PacketType REL_ENTITY_MOVE = new PacketType(PROTOCOL, SENDER, 0x15, 31);
public static final PacketType ENTITY_LOOK = new PacketType(PROTOCOL, SENDER, 0x16, 32);
public static final PacketType ENTITY_MOVE_LOOK = new PacketType(PROTOCOL, SENDER, 0x17, 33);
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x18, 34);
public static final PacketType ENTITY_HEAD_ROTATION = new PacketType(PROTOCOL, SENDER, 0x19, 35);
public static final PacketType ENTITY_STATUS = new PacketType(PROTOCOL, SENDER, 0x1A, 38);
public static final PacketType ATTACH_ENTITY = new PacketType(PROTOCOL, SENDER, 0x1B, 39);
public static final PacketType ENTITY_METADATA = new PacketType(PROTOCOL, SENDER, 0x1C, 40);
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1D, 41);
public static final PacketType REMOVE_ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x1E, 42);
public static final PacketType EXPERIENCE = new PacketType(PROTOCOL, SENDER, 0x1F, 43);
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x20, 44);
public static final PacketType MAP_CHUNK = new PacketType(PROTOCOL, SENDER, 0x21, 51);
public static final PacketType MULTI_BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x22, 52);
public static final PacketType BLOCK_CHANGE = new PacketType(PROTOCOL, SENDER, 0x23, 53);
public static final PacketType BLOCK_ACTION = new PacketType(PROTOCOL, SENDER, 0x24, 54);
public static final PacketType BLOCK_BREAK_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x25, 55);
public static final PacketType MAP_CHUNK_BULK = new PacketType(PROTOCOL, SENDER, 0x26, 56);
public static final PacketType EXPLOSION = new PacketType(PROTOCOL, SENDER, 0x27, 60);
public static final PacketType WORLD_EVENT = new PacketType(PROTOCOL, SENDER, 0x28, 61);
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x29, 62);
public static final PacketType WORLD_PARTICLES = new PacketType(PROTOCOL, SENDER, 0x2A, 63);
/**
* Note that this was Packets.Server.BED.
*/
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x2B, 70, "GameStateChange");
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x2C, 71, "SpawnEntityWeather");
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2D, 100, "OpenWindow");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2E, 101, "CloseWindow");
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x2F, 103, "SetSlot");
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x30, 104, "WindowItems");
/**
* Should be WINDOW_DATA.
*/
public static final PacketType CRAFT_PROGRESS_BAR = new PacketType(PROTOCOL, SENDER, 0x31, 105, "WindowData");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x32, 106, "Transaction");
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x33, 130, "UpdateSign");
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x34, 131, "Map");
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x35, 132, "TileEntityData");
public static final PacketType OPEN_SIGN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x36, 133, "OpenSignEditor");
public static final PacketType STATISTICS = new PacketType(PROTOCOL, SENDER, 0x37, 200, "Statistic");
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x38, 201, "PlayerInfo");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x39, 202, "Abilities");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x3A, 203, "TabComplete");
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x3B, 206, "ScoreboardObjective");
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x3C, 207, "ScoreboardScore");
public static final PacketType GAME_STATE_CHANGE = new PacketType(PROTOCOL, SENDER, 0x2B, 70);
public static final PacketType SPAWN_ENTITY_WEATHER = new PacketType(PROTOCOL, SENDER, 0x2C, 71);
public static final PacketType OPEN_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2D, 100);
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x2E, 101);
public static final PacketType SET_SLOT = new PacketType(PROTOCOL, SENDER, 0x2F, 103);
public static final PacketType WINDOW_ITEMS = new PacketType(PROTOCOL, SENDER, 0x30, 104);
public static final PacketType CRAFT_PROGRESS_BAR = new PacketType(PROTOCOL, SENDER, 0x31, 105);
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x32, 106);
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x33, 130);
public static final PacketType MAP = new PacketType(PROTOCOL, SENDER, 0x34, 131);
public static final PacketType TILE_ENTITY_DATA = new PacketType(PROTOCOL, SENDER, 0x35, 132);
public static final PacketType OPEN_SIGN_ENTITY = new PacketType(PROTOCOL, SENDER, 0x36, 133);
public static final PacketType STATISTICS = new PacketType(PROTOCOL, SENDER, 0x37, 200);
public static final PacketType PLAYER_INFO = new PacketType(PROTOCOL, SENDER, 0x38, 201);
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x39, 202);
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x3A, 203);
public static final PacketType SCOREBOARD_OBJECTIVE = new PacketType(PROTOCOL, SENDER, 0x3B, 206);
public static final PacketType SCOREBOARD_SCORE = new PacketType(PROTOCOL, SENDER, 0x3C, 207);
public static final PacketType SCOREBOARD_DISPLAY_OBJECTIVE =
new PacketType(PROTOCOL, SENDER, 0x3D, 208, "ScoreboardDisplayObjective");
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x3E, 209, "ScoreboardTeam");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x3F, 250, "CustomPayload");
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x40, 255, "KickDisconnect");
public static final PacketType SERVER_DIFFICULTY = new PacketType(PROTOCOL, SENDER, 0x41, -1, "ServerDifficulty");
public static final PacketType COMBAT_EVENT = new PacketType(PROTOCOL, SENDER, 0x42, -1, "CombatEvent");
public static final PacketType CAMERA = new PacketType(PROTOCOL, SENDER, 0x43, -1, "Camera");
public static final PacketType WORLD_BORDER = new PacketType(PROTOCOL, SENDER, 0x44, -1, "WorldBorder");
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x45, -1, "Title");
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x46, -1, "SetCompression");
public static final PacketType PLAYER_LIST_HEADER_FOOTER =
new PacketType(PROTOCOL, SENDER, 0x47, -1, "PlayerListHeaderFooter");
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x48, -1, "ResourcePackSend");
public static final PacketType UPDATE_ENTITY_NBT = new PacketType(PROTOCOL, SENDER, 0x49, -1, "UpdateEntityNBT");
new PacketType(PROTOCOL, SENDER, 0x3D, 208);
public static final PacketType SCOREBOARD_TEAM = new PacketType(PROTOCOL, SENDER, 0x3E, 209);
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x3F, 250);
public static final PacketType KICK_DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x40, 255);
@Spigot(minimumBuild = 1628)
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x45, -1);
@Spigot(minimumBuild = 1628)
public static final PacketType TAB_HEADER = new PacketType(PROTOCOL, SENDER, 0x47, -1);
@Spigot(minimumBuild = 1628)
public static final PacketType RESOURCE_PACK_SEND = new PacketType(PROTOCOL, SENDER, 0x48, -1);
// The instance must
private final static Server INSTANCE = new Server();
@@ -215,32 +208,33 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0, "KeepAlive");
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x01, 3, "Chat");
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x02, 7, "UseEntity");
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x03, 10, "Flying");
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x04, 11, "Position");
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x05, 12, "Look");
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x06, 13, "PositionLook");
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x07, 14, "BlockDig");
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x08, 15, "BlockPlace");
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16, "HeldItemSlot");
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0A, 18, "ArmAnimation");
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x0B, 19, "EntityAction");
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x0C, 27, "SteerVehicle");
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x0D, 101, "CloseWindow");
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x0E, 102, "WindowClick");
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x0F, 106, "Transaction");
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x10, 107, "SetCreativeSlot");
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x11, 108, "EnchantItem");
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x12, 130, "UpdateSign");
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x13, 202, "Abilities");
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x14, 203, "TabComplete");
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x15, 204, "Settings");
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x16, 205, "ClientCommand");
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x17, 250, "CustomPayload");
public static final PacketType SPECTATE = new PacketType(PROTOCOL, SENDER, 0x18, -1, "Spectate");
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x19, -1, "ResourcePackStatus");
public static final PacketType KEEP_ALIVE = new PacketType(PROTOCOL, SENDER, 0x00, 0);
public static final PacketType CHAT = new PacketType(PROTOCOL, SENDER, 0x01, 3);
public static final PacketType USE_ENTITY = new PacketType(PROTOCOL, SENDER, 0x02, 7);
public static final PacketType FLYING = new PacketType(PROTOCOL, SENDER, 0x03, 10);
public static final PacketType POSITION = new PacketType(PROTOCOL, SENDER, 0x04, 11);
public static final PacketType LOOK = new PacketType(PROTOCOL, SENDER, 0x05, 12);
public static final PacketType POSITION_LOOK = new PacketType(PROTOCOL, SENDER, 0x06, 13);
public static final PacketType BLOCK_DIG = new PacketType(PROTOCOL, SENDER, 0x07, 14);
public static final PacketType BLOCK_PLACE = new PacketType(PROTOCOL, SENDER, 0x08, 15);
public static final PacketType HELD_ITEM_SLOT = new PacketType(PROTOCOL, SENDER, 0x09, 16);
public static final PacketType ARM_ANIMATION = new PacketType(PROTOCOL, SENDER, 0x0A, 18);
public static final PacketType ENTITY_ACTION = new PacketType(PROTOCOL, SENDER, 0x0B, 19);
public static final PacketType STEER_VEHICLE = new PacketType(PROTOCOL, SENDER, 0x0C, 27);
public static final PacketType CLOSE_WINDOW = new PacketType(PROTOCOL, SENDER, 0x0D, 101);
public static final PacketType WINDOW_CLICK = new PacketType(PROTOCOL, SENDER, 0x0E, 102);
public static final PacketType TRANSACTION = new PacketType(PROTOCOL, SENDER, 0x0F, 106);
public static final PacketType SET_CREATIVE_SLOT = new PacketType(PROTOCOL, SENDER, 0x10, 107);
public static final PacketType ENCHANT_ITEM = new PacketType(PROTOCOL, SENDER, 0x11, 108);
public static final PacketType UPDATE_SIGN = new PacketType(PROTOCOL, SENDER, 0x12, 130);
public static final PacketType ABILITIES = new PacketType(PROTOCOL, SENDER, 0x13, 202);
public static final PacketType TAB_COMPLETE = new PacketType(PROTOCOL, SENDER, 0x14, 203);
public static final PacketType SETTINGS = new PacketType(PROTOCOL, SENDER, 0x15, 204);
public static final PacketType CLIENT_COMMAND = new PacketType(PROTOCOL, SENDER, 0x16, 205);
public static final PacketType CUSTOM_PAYLOAD = new PacketType(PROTOCOL, SENDER, 0x17, 250);
@Spigot(minimumBuild = 1628)
public static final PacketType RESOURCE_PACK_STATUS = new PacketType(PROTOCOL, SENDER, 0x19, -1);
private final static Client INSTANCE = new Client();
@@ -274,8 +268,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Server extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType OUT_SERVER_INFO = new PacketType(PROTOCOL, SENDER, 0x00, 255, "ServerInfo").forceAsync(true);
public static final PacketType OUT_PING = new PacketType(PROTOCOL, SENDER, 0x01, 230, "Pong");
public static final PacketType OUT_SERVER_INFO = new PacketType(PROTOCOL, SENDER, 0x00, 255);
@SuppressWarnings("deprecation")
public static final PacketType OUT_PING = new PacketType(PROTOCOL, SENDER, 0x01, Packets.Server.PING_TIME);
private final static Server INSTANCE = new Server();
@@ -297,8 +292,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType IN_START = new PacketType(PROTOCOL, SENDER, 0x00, 254, "Start");
public static final PacketType IN_PING = new PacketType(PROTOCOL, SENDER, 0x01, 230, "Ping");
public static final PacketType IN_START = new PacketType(PROTOCOL, SENDER, 0x00, 254);
@SuppressWarnings("deprecation")
public static final PacketType IN_PING = new PacketType(PROTOCOL, SENDER, 0x01, Packets.Client.PING_TIME);
private final static Client INSTANCE = new Client();
@@ -332,10 +328,13 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Server extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.SERVER;
public static final PacketType DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x00, 255, "Disconnect");
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 253, "EncryptionBegin");
public static final PacketType SUCCESS = new PacketType(PROTOCOL, SENDER, 0x02, 232, "Success");
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x03, -1, "SetCompression");
public static final PacketType DISCONNECT = new PacketType(PROTOCOL, SENDER, 0x00, 255);
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 253);
@SuppressWarnings("deprecation")
public static final PacketType SUCCESS = new PacketType(PROTOCOL, SENDER, 0x02, Packets.Server.LOGIN_SUCCESS);
@Spigot(minimumBuild = 1628)
public static final PacketType LOGIN_COMPRESSION = new PacketType(PROTOCOL, SENDER, 0x03, -1);
private final static Server INSTANCE = new Server();
@@ -357,8 +356,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public static class Client extends ObjectEnum<PacketType> {
private final static Sender SENDER = Sender.CLIENT;
public static final PacketType START = new PacketType(PROTOCOL, SENDER, 0x00, 231, "Start");
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 252, "EncryptionBegin");
@SuppressWarnings("deprecation")
public static final PacketType START = new PacketType(PROTOCOL, SENDER, 0x00, Packets.Client.LOGIN_START);
public static final PacketType ENCRYPTION_BEGIN = new PacketType(PROTOCOL, SENDER, 0x01, 252);
private final static Client INSTANCE = new Client();
@@ -479,7 +479,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
String name = vanilla.name();
if ("HANDSHAKING".equals(name))
return HANDSHAKING;
return HANDSHAKING;
if ("PLAY".equals(name))
return PLAY;
if ("STATUS".equals(name))
@@ -488,10 +488,6 @@ public class PacketType implements Serializable, Comparable<PacketType> {
return LOGIN;
throw new IllegalArgumentException("Unrecognized vanilla enum " + vanilla);
}
public String getPacketName() {
return WordUtils.capitalize(name().toLowerCase());
}
}
/**
@@ -517,10 +513,6 @@ public class PacketType implements Serializable, Comparable<PacketType> {
public ConnectionSide toSide() {
return this == CLIENT ? ConnectionSide.CLIENT_SIDE : ConnectionSide.SERVER_SIDE;
}
public String getPacketName() {
return this == CLIENT ? "In" : "Out";
}
}
// Lookup of packet types
@@ -529,17 +521,13 @@ public class PacketType implements Serializable, Comparable<PacketType> {
/**
* Protocol version of all the current IDs.
*/
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.BOUNTIFUL_UPDATE;
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.WORLD_UPDATE;
private final Protocol protocol;
private final Sender sender;
private final int currentId;
private final int legacyId;
private final MinecraftVersion version;
private final String[] classNames;
private boolean forceAsync;
private boolean dynamic;
/**
* Retrieve the current packet/legacy lookup.
@@ -619,6 +607,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
/**
* Determine if the given legacy packet exists.
* @param packetId - the legacy packet ID.
* @param preference - the sender preference.
* @return TRUE if it does, FALSE otherwise.
*/
public static boolean hasLegacy(int packetId) {
@@ -637,9 +626,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param packetId - the packet ID.
* @return The corresponding packet type.
* @throws IllegalArgumentException If the current packet could not be found.
* @deprecated IDs are no longer reliable
*/
@Deprecated
public static PacketType findCurrent(Protocol protocol, Sender sender, int packetId) {
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
@@ -649,34 +636,13 @@ public class PacketType implements Serializable, Comparable<PacketType> {
"(Protocol: " + protocol + ", Sender: " + sender + ")");
}
public static PacketType findCurrent(Protocol protocol, Sender sender, String name) {
name = format(protocol, sender, name);
PacketType type = getLookup().getFromCurrent(protocol, sender, name);
if (type != null) {
return type;
} else {
throw new IllegalArgumentException("Cannot find packet " + name +
"(Protocol: " + protocol + ", Sender: " + sender + ")");
}
}
private static String format(Protocol protocol, Sender sender, String name) {
if (name.contains("Packet"))
return name;
return String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), name);
}
/**
* Determine if the given packet exists.
* @param protocol - the protocol.
* @param sender - the sender.
* @param packetId - the packet ID.
* @return TRUE if it exists, FALSE otherwise.
* @deprecated IDs are no longer reliable
*/
@Deprecated
public static boolean hasCurrent(Protocol protocol, Sender sender, int packetId) {
return getLookup().getFromCurrent(protocol, sender, packetId) != null;
}
@@ -705,68 +671,24 @@ public class PacketType implements Serializable, Comparable<PacketType> {
}
/**
* Retrieve a packet type from a protocol, sender and packet ID, for pre-1.8.
* Retrieve a packet type from a protocol, sender and packet ID.
* <p>
* The packet will automatically be registered if its missing.
* @param protocol - the current protocol.
* @param sender - the sender.
* @param packetId - the packet ID. Can be UNKNOWN_PACKET.
* @param packetClass - the packet class
* @param legacyId - the legacy packet ID. Can be UNKNOWN_PACKET.
* @return The corresponding packet type.
*/
public static PacketType fromID(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
public static PacketType fromCurrent(Protocol protocol, Sender sender, int packetId, int legacyId) {
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
if (type == null) {
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, packetClass.getName());
type.dynamic = true;
type = new PacketType(protocol, sender, packetId, legacyId);
// Many may be scheduled, but only the first will be executed
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
}
return type;
}
/**
* Retrieve a packet type from a protocol, sender, ID, and class for 1.8+
* <p>
* The packet will automatically be registered if its missing.
* @param protocol - the current protocol.
* @param sender - the sender.
* @param packetId - the packet ID. Can be UNKNOWN_PACKET.
* @param packetClass - the packet class.
* @return The corresponding packet type.
*/
public static PacketType fromCurrent(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
ClassLookup lookup = getLookup().getClassLookup();
Map<String, PacketType> map = lookup.getMap(protocol, sender);
// Check the map first
String className = packetClass.getSimpleName();
PacketType type = map.get(className);
if (type == null) {
// Then check any aliases
for (PacketType check : map.values()) {
String[] aliases = check.getClassNames();
if (aliases.length > 1) {
for (String alias : aliases) {
if (alias.equals(className)) {
// We have a match!
type = check;
}
}
}
}
// Guess we don't support this packet :/
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, className);
type.dynamic = true;
// Many may be scheduled, but only the first will be executed
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
}
return type;
}
@@ -868,8 +790,8 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param currentId - the current packet ID, or
* @param legacyId - the legacy packet ID.
*/
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId, String... names) {
this(protocol, sender, currentId, legacyId, PROTOCOL_VERSION, names);
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId) {
this(protocol, sender, currentId, legacyId, PROTOCOL_VERSION);
}
/**
@@ -880,24 +802,18 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* @param legacyId - the legacy packet ID.
* @param version - the version of the current ID.
*/
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId, MinecraftVersion version, String... names) {
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId, MinecraftVersion version) {
this.protocol = Preconditions.checkNotNull(protocol, "protocol cannot be NULL");
this.sender = Preconditions.checkNotNull(sender, "sender cannot be NULL");
this.currentId = currentId;
this.legacyId = legacyId;
this.version = version;
this.classNames = new String[names.length];
for (int i = 0; i < classNames.length; i++) {
classNames[i] = format(protocol, sender, names[i]);
}
}
/**
* Construct a legacy packet type.
* @param sender - client or server.
* @param legacyId - the legacy packet ID.
* @return Legacy packet type
*/
public static PacketType newLegacy(Sender sender, int legacyId) {
return new PacketType(Protocol.LEGACY, sender, PacketType.UNKNOWN_PACKET, legacyId, MinecraftVersion.WORLD_UPDATE);
@@ -950,17 +866,11 @@ public class PacketType implements Serializable, Comparable<PacketType> {
* <p>
* It is only unknown if the packet was removed in Minecraft 1.7.2.
* @return The current ID, or {@link #UNKNOWN_PACKET} if unknown.
* @deprecated IDs are subject to change
*/
@Deprecated
public int getCurrentId() {
return currentId;
}
public String[] getClassNames() {
return classNames;
}
/**
* Retrieve the equivalent packet class.
* @return The packet class, or NULL if not found.
@@ -999,27 +909,6 @@ public class PacketType implements Serializable, Comparable<PacketType> {
return legacyId;
}
/**
* Whether or not this packet was dynamically created (i.e. we don't have it registered)
* @return True if dnyamic, false if not.
*/
public boolean isDynamic() {
return dynamic;
}
private PacketType forceAsync(boolean forceAsync) {
this.forceAsync = forceAsync;
return this;
}
/**
* Whether or not this packet must be processed asynchronously.
* @return True if it must be, false if not.
*/
public boolean forceAsync() {
return forceAsync;
}
@Override
public int hashCode() {
return Objects.hashCode(protocol, sender, currentId, legacyId);
@@ -1052,10 +941,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
@Override
public String toString() {
Class<?> clazz = getPacketClass();
Class<?> clazz = getPacketClass();;
if (clazz == null)
return "UNREGISTERED[" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + ", classNames: " + Arrays.toString(classNames) + "]";
return "UNREGISTERED [" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + "]";
else
return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]";
}
@@ -2,8 +2,6 @@ package com.comphenix.protocol;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
@@ -17,7 +15,7 @@ import com.google.common.collect.Multimap;
* @author Kristian
*/
class PacketTypeLookup {
public static class ProtocolSenderLookup {
private static class ProtocolSenderLookup {
// Unroll lookup for performance reasons
public final IntegerMap<PacketType> HANDSHAKE_CLIENT = IntegerMap.newMap();
public final IntegerMap<PacketType> HANDSHAKE_SERVER = IntegerMap.newMap();
@@ -49,39 +47,6 @@ class PacketTypeLookup {
}
}
}
public static class ClassLookup {
// Unroll lookup for performance reasons
public final Map<String, PacketType> HANDSHAKE_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> HANDSHAKE_SERVER = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> GAME_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> GAME_SERVER = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> STATUS_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> STATUS_SERVER = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> LOGIN_CLIENT = new ConcurrentHashMap<String, PacketType>();
public final Map<String, PacketType> LOGIN_SERVER = new ConcurrentHashMap<String, PacketType>();
/**
* Retrieve the correct integer map for a specific protocol and sender.
* @param protocol - the protocol.
* @param sender - the sender.
* @return The integer map of packets.
*/
public Map<String, PacketType> getMap(Protocol protocol, Sender sender) {
switch (protocol) {
case HANDSHAKING:
return sender == Sender.CLIENT ? HANDSHAKE_CLIENT : HANDSHAKE_SERVER;
case PLAY:
return sender == Sender.CLIENT ? GAME_CLIENT : GAME_SERVER;
case STATUS:
return sender == Sender.CLIENT ? STATUS_CLIENT : STATUS_SERVER;
case LOGIN:
return sender == Sender.CLIENT ? LOGIN_CLIENT : LOGIN_SERVER;
default:
throw new IllegalArgumentException("Unable to find protocol " + protocol);
}
}
}
// Packet IDs from 1.6.4 and below
private final IntegerMap<PacketType> legacyLookup = new IntegerMap<PacketType>();
@@ -89,14 +54,11 @@ class PacketTypeLookup {
private final IntegerMap<PacketType> clientLookup = new IntegerMap<PacketType>();
// Packets for 1.7.2
private final ProtocolSenderLookup idLookup = new ProtocolSenderLookup();
// Packets for 1.8+
private final ClassLookup classLookup = new ClassLookup();
private final ProtocolSenderLookup currentLookup = new ProtocolSenderLookup();
// Packets based on name
private final Multimap<String, PacketType> nameLookup = HashMultimap.create();
/**
* Add a collection of packet types to the lookup.
* @param types - the types to add.
@@ -117,9 +79,9 @@ class PacketTypeLookup {
}
// Skip unknown current packets
if (type.getCurrentId() != PacketType.UNKNOWN_PACKET) {
idLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames()[0], type);
currentLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
}
// Save name
nameLookup.put(type.name(), type);
}
return this;
@@ -170,18 +132,8 @@ class PacketTypeLookup {
* @param sender - the sender.
* @param packetId - the packet ID.
* @return The corresponding packet type, or NULL if not found.
* @deprecated IDs are no longer reliable
*/
@Deprecated
public PacketType getFromCurrent(Protocol protocol, Sender sender, int packetId) {
return idLookup.getMap(protocol, sender).get(packetId);
}
public PacketType getFromCurrent(Protocol protocol, Sender sender, String name) {
return classLookup.getMap(protocol, sender).get(name);
}
public ClassLookup getClassLookup() {
return classLookup;
return currentLookup.getMap(protocol, sender).get(packetId);
}
}
@@ -8,14 +8,15 @@ import java.util.Set;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.compat.guava.Guava;
import com.comphenix.protocol.events.ConnectionSide;
import com.google.common.collect.DiscreteDomains;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
import com.google.common.collect.Sets;
class PacketTypeParser {
public final static Range<Integer> DEFAULT_MAX_RANGE = Guava.closedRange(0, 255);
public final static Range<Integer> DEFAULT_MAX_RANGE = Ranges.closed(0, 255);
private Sender side = null;
private Protocol protocol = null;
@@ -71,7 +72,7 @@ class PacketTypeParser {
}
for (Range<Integer> range : ranges) {
for (Integer id : Guava.toSet(range)) {
for (Integer id : range.asSet(DiscreteDomains.integers())) {
// Deprecated packets
if (protocol == null) {
if (PacketType.hasLegacy(id)) {
@@ -142,5 +143,5 @@ class PacketTypeParser {
return Protocol.STATUS;
else
return null;
}
}
}
@@ -1,4 +1,4 @@
/**
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
@@ -14,11 +14,11 @@
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.configuration.Configuration;
@@ -38,49 +38,53 @@ import com.google.common.io.Files;
*/
public class ProtocolConfig {
private static final String LAST_UPDATE_FILE = "lastupdate";
private static final String SECTION_GLOBAL = "global";
private static final String SECTION_AUTOUPDATER = "auto updater";
private static final String METRICS_ENABLED = "metrics";
private static final String IGNORE_VERSION_CHECK = "ignore version check";
private static final String IGNORE_VERSION_CHECK = "ignore version check";
private static final String BACKGROUND_COMPILER_ENABLED = "background compiler";
private static final String DEBUG_MODE_ENABLED = "debug";
private static final String DETAILED_ERROR = "detailed error";
private static final String INJECTION_METHOD = "injection method";
private static final String SCRIPT_ENGINE_NAME = "script engine";
private static final String SUPPRESSED_REPORTS = "suppressed reports";
private static final String UPDATER_NOTIFY = "notify";
private static final String UPDATER_DOWNLAD = "download";
private static final String UPDATER_DELAY = "delay";
// Defaults
private static final long DEFAULT_UPDATER_DELAY = 43200;
private Plugin plugin;
private Configuration config;
private boolean loadingSections;
private ConfigurationSection global;
private ConfigurationSection updater;
// Last update time
private long lastUpdateTime;
private boolean configChanged;
private boolean valuesChanged;
// Modifications
private int modCount;
public ProtocolConfig(Plugin plugin) {
this(plugin, plugin.getConfig());
}
public ProtocolConfig(Plugin plugin, Configuration config) {
this.plugin = plugin;
reloadConfig();
}
/**
* Reload configuration file.
*/
@@ -89,20 +93,19 @@ public class ProtocolConfig {
configChanged = false;
valuesChanged = false;
modCount++;
this.config = plugin.getConfig();
this.lastUpdateTime = loadLastUpdate();
loadSections(!loadingSections);
}
/**
* Load the last update time stamp from the file system.
*
* @return Last update time stamp.
*/
private long loadLastUpdate() {
File dataFile = getLastUpdateFile();
if (dataFile.exists()) {
try {
return Long.parseLong(Files.toString(dataFile, Charsets.UTF_8));
@@ -115,40 +118,37 @@ public class ProtocolConfig {
// Default last update
return 0;
}
/**
* Store the given time stamp.
*
* @param value - time stamp to store.
*/
private void saveLastUpdate(long value) {
File dataFile = getLastUpdateFile();
// The data folder must exist
dataFile.getParentFile().mkdirs();
if (dataFile.exists())
dataFile.delete();
try {
Files.write(Long.toString(value), dataFile, Charsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("Cannot write " + dataFile, e);
}
}
/**
* Retrieve the file that is used to store the update time stamp.
*
* @return File storing the update time stamp.
*/
private File getLastUpdateFile() {
return new File(plugin.getDataFolder(), LAST_UPDATE_FILE);
}
/**
* Load data sections.
*
* @param copyDefaults - whether or not to copy configuration defaults.
*/
private void loadSections(boolean copyDefaults) {
@@ -162,21 +162,20 @@ public class ProtocolConfig {
// Automatically copy defaults
if (copyDefaults && (!getFile().exists() || global == null || updater == null)) {
loadingSections = true;
if (config != null)
config.options().copyDefaults(true);
plugin.saveDefaultConfig();
plugin.reloadConfig();
loadingSections = false;
loadingSections = false;
// Inform the user
plugin.getLogger().info("Created default configuration.");
System.out.println("[ProtocolLib] Created default configuration.");
}
}
/**
* Set a particular configuration key value pair.
*
* @param section - the configuration root.
* @param path - the path to the key.
* @param value - the value to set.
@@ -186,122 +185,93 @@ public class ProtocolConfig {
section.set(path, value);
}
@SuppressWarnings("unchecked")
private <T> T getGlobalValue(String path, T def) {
try {
return (T) global.get(path, def);
} catch (Throwable ex) {
return def;
}
}
@SuppressWarnings("unchecked")
private <T> T getUpdaterValue(String path, T def) {
try {
return (T) updater.get(path, def);
} catch (Throwable ex) {
return def;
}
}
/**
* Retrieve a reference to the configuration file.
*
* @return Configuration file on disk.
*/
public File getFile() {
return new File(plugin.getDataFolder(), "config.yml");
}
/**
* Determine if detailed error reporting is enabled. Default FALSE.
*
* @return TRUE if it is enabled, FALSE otherwise.
*/
public boolean isDetailedErrorReporting() {
return getGlobalValue(DETAILED_ERROR, false);
return global.getBoolean(DETAILED_ERROR, false);
}
/**
* Set whether or not detailed error reporting is enabled.
*
* @param value - TRUE if it is enabled, FALSE otherwise.
*/
public void setDetailedErrorReporting(boolean value) {
global.set(DETAILED_ERROR, value);
}
/**
* Retrieve whether or not ProtocolLib should determine if a new version has been released.
*
* @return TRUE if it should do this automatically, FALSE otherwise.
*/
public boolean isAutoNotify() {
return getUpdaterValue(UPDATER_NOTIFY, true);
return updater.getBoolean(UPDATER_NOTIFY, true);
}
/**
* Set whether or not ProtocolLib should determine if a new version has been released.
*
* @param value - TRUE to do this automatically, FALSE otherwise.
*/
public void setAutoNotify(boolean value) {
setConfig(updater, UPDATER_NOTIFY, value);
modCount++;
}
/**
* Retrieve whether or not ProtocolLib should automatically download the new version.
*
* @return TRUE if it should, FALSE otherwise.
*/
public boolean isAutoDownload() {
return updater != null && getUpdaterValue(UPDATER_DOWNLAD, true);
return updater != null && updater.getBoolean(UPDATER_DOWNLAD, true);
}
/**
* Set whether or not ProtocolLib should automatically download the new version.
*
* @param value - TRUE if it should. FALSE otherwise.
*/
public void setAutoDownload(boolean value) {
setConfig(updater, UPDATER_DOWNLAD, value);
modCount++;
}
/**
* Determine whether or not debug mode is enabled.
* <p>
* This grants access to the filter command.
*
* @return TRUE if it is, FALSE otherwise.
*/
public boolean isDebug() {
return getGlobalValue(DEBUG_MODE_ENABLED, false);
return global.getBoolean(DEBUG_MODE_ENABLED, false);
}
/**
* Set whether or not debug mode is enabled.
*
* @param value - TRUE if it is enabled, FALSE otherwise.
*/
public void setDebug(boolean value) {
setConfig(global, DEBUG_MODE_ENABLED, value);
modCount++;
}
/**
* Retrieve an immutable list of every suppressed report type.
*
* @return Every suppressed report type.
*/
public ImmutableList<String> getSuppressedReports() {
return ImmutableList.copyOf(getGlobalValue(SUPPRESSED_REPORTS, new ArrayList<String>()));
return ImmutableList.copyOf(global.getStringList(SUPPRESSED_REPORTS));
}
/**
* Set the list of suppressed report types,
*
* @param reports - suppressed report types.
*/
public void setSuppressedReports(List<String> reports) {
@@ -311,19 +281,17 @@ public class ProtocolConfig {
/**
* Retrieve the amount of time to wait until checking for a new update.
*
* @return The amount of time to wait.
*/
public long getAutoDelay() {
// Note that the delay must be greater than 59 seconds
return Math.max(getUpdaterValue(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY);
return Math.max(updater.getInt(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY);
}
/**
* Set the amount of time to wait until checking for a new update.
* <p>
* This time must be greater than 59 seconds.
*
* @param delaySeconds - the amount of time to wait.
*/
public void setAutoDelay(long delaySeconds) {
@@ -333,20 +301,20 @@ public class ProtocolConfig {
setConfig(updater, UPDATER_DELAY, delaySeconds);
modCount++;
}
/**
* The version of Minecraft to ignore the built-in safety feature.
*
* @return The version to ignore ProtocolLib's satefy.
*/
public String getIgnoreVersionCheck() {
return getGlobalValue(IGNORE_VERSION_CHECK, "");
return global.getString(IGNORE_VERSION_CHECK, "");
}
/**
* Sets under which version of Minecraft the version safety feature will be ignored.
* <p>
* This is useful if a server operator has tested and verified that a version of ProtocolLib works, but doesn't want or can't upgrade to a newer version.
* This is useful if a server operator has tested and verified that a version of ProtocolLib works,
* but doesn't want or can't upgrade to a newer version.
*
* @param ignoreVersion - the version of Minecraft where the satefy will be disabled.
*/
@@ -354,16 +322,15 @@ public class ProtocolConfig {
setConfig(global, IGNORE_VERSION_CHECK, ignoreVersion);
modCount++;
}
/**
* Retrieve whether or not metrics is enabled.
*
* @return TRUE if metrics is enabled, FALSE otherwise.
*/
public boolean isMetricsEnabled() {
return getGlobalValue(METRICS_ENABLED, true);
return global.getBoolean(METRICS_ENABLED, true);
}
/**
* Set whether or not metrics is enabled.
* <p>
@@ -375,31 +342,28 @@ public class ProtocolConfig {
setConfig(global, METRICS_ENABLED, enabled);
modCount++;
}
/**
* Retrieve whether or not the background compiler for structure modifiers is enabled or not.
*
* @return TRUE if it is enabled, FALSE otherwise.
*/
public boolean isBackgroundCompilerEnabled() {
return getGlobalValue(BACKGROUND_COMPILER_ENABLED, true);
return global.getBoolean(BACKGROUND_COMPILER_ENABLED, true);
}
/**
* Set whether or not the background compiler for structure modifiers is enabled or not.
* <p>
* This setting will take effect next time ProtocolLib is started.
*
* @param enabled - TRUE if is enabled/running, FALSE otherwise.
*/
public void setBackgroundCompilerEnabled(boolean enabled) {
setConfig(global, BACKGROUND_COMPILER_ENABLED, enabled);
modCount++;
}
/**
* Retrieve the last time we updated, in seconds since 1970.01.01 00:00.
*
* @return Last update time.
*/
public long getAutoLastTime() {
@@ -409,81 +373,75 @@ public class ProtocolConfig {
/**
* Set the last time we updated, in seconds since 1970.01.01 00:00.
* <p>
* Note that this is not considered to modify the configuration, so the modification count will not be incremented.
*
* Note that this is not considered to modify the configuration, so the modification count
* will not be incremented.
* @param lastTimeSeconds - new last update time.
*/
public void setAutoLastTime(long lastTimeSeconds) {
public void setAutoLastTime(long lastTimeSeconds) {
this.valuesChanged = true;
this.lastUpdateTime = lastTimeSeconds;
}
/**
* Retrieve the unique name of the script engine to use for filtering.
*
* @return Script engine to use.
*/
public String getScriptEngineName() {
return getGlobalValue(SCRIPT_ENGINE_NAME, "JavaScript");
return global.getString(SCRIPT_ENGINE_NAME, "JavaScript");
}
/**
* Set the unique name of the script engine to use for filtering.
* <p>
* This setting will take effect next time ProtocolLib is started.
*
* @param name - name of the script engine to use.
*/
public void setScriptEngineName(String name) {
setConfig(global, SCRIPT_ENGINE_NAME, name);
modCount++;
}
/**
* Retrieve the default injection method.
*
* @return Default method.
*/
public PlayerInjectHooks getDefaultMethod() {
return PlayerInjectHooks.NETWORK_SERVER_OBJECT;
}
/**
* Retrieve the injection method that has been set in the configuration, or use a default value.
*
* @return Injection method to use.
* @throws IllegalArgumentException If the configuration option is malformed.
*/
public PlayerInjectHooks getInjectionMethod() throws IllegalArgumentException {
String text = global.getString(INJECTION_METHOD);
// Default hook if nothing has been set
PlayerInjectHooks hook = getDefaultMethod();
if (text != null)
if (text != null)
hook = PlayerInjectHooks.valueOf(text.toUpperCase().replace(" ", "_"));
return hook;
}
/**
* Set the starting injection method to use.
*
* @return Injection method.
*/
public void setInjectionMethod(PlayerInjectHooks hook) {
setConfig(global, INJECTION_METHOD, hook.name());
modCount++;
}
/**
* Retrieve the number of modifications made to this configuration.
*
* @return The number of modifications.
*/
public int getModificationCount() {
return modCount;
}
/**
* Save the current configuration file.
*/
@@ -492,9 +450,9 @@ public class ProtocolConfig {
saveLastUpdate(lastUpdateTime);
if (configChanged)
plugin.saveConfig();
// And we're done
valuesChanged = false;
configChanged = false;
}
}
}
@@ -1,4 +1,4 @@
/**
/*
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
@@ -14,13 +14,11 @@
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.logging.Handler;
import java.util.logging.Level;
@@ -32,7 +30,6 @@ import java.util.regex.Pattern;
import org.bukkit.Server;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
@@ -50,8 +47,6 @@ import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.metrics.Statistics;
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
import com.comphenix.protocol.updater.Updater;
import com.comphenix.protocol.updater.Updater.UpdateType;
import com.comphenix.protocol.utility.ChatExtensions;
import com.comphenix.protocol.utility.EnhancerFactory;
import com.comphenix.protocol.utility.MinecraftVersion;
@@ -87,21 +82,17 @@ public class ProtocolLibrary extends JavaPlugin {
/**
* The minimum version ProtocolLib has been tested with.
*/
public static final String MINIMUM_MINECRAFT_VERSION = "1.0";
public static final String MINIMUM_MINECRAFT_VERSION = "1.0.0";
/**
* The maximum version ProtocolLib has been tested with,
*/
public static final String MAXIMUM_MINECRAFT_VERSION = "1.8.8";
public static final String MAXIMUM_MINECRAFT_VERSION = "1.7.10";
/**
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.8.8) was released.
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version was released.
*/
public static final String MINECRAFT_LAST_RELEASE_DATE = "2015-07-27";
// Update information
static final String BUKKIT_DEV_SLUG = "protocollib";
static final int BUKKIT_DEV_ID = 45564;
public static final String MINECRAFT_LAST_RELEASE_DATE = "2013-12-10";
// Different commands
private enum ProtocolCommand {
@@ -148,12 +139,8 @@ public class ProtocolLibrary extends JavaPlugin {
// Settings/options
private int configExpectedMod = -1;
// Updater
private Updater updater;
private static boolean UPDATES_DISABLED;
// Logger
private static Logger logger;
private Logger logger;
private Handler redirectHandler;
// Commands
@@ -181,10 +168,6 @@ public class ProtocolLibrary extends JavaPlugin {
DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this);
reporter = getFilteredReporter(detailedReporter);
// Configuration
saveDefaultConfig();
reloadConfig();
try {
config = new ProtocolConfig(this);
} catch (Exception e) {
@@ -215,18 +198,8 @@ public class ProtocolLibrary extends JavaPlugin {
// Handle unexpected Minecraft versions
MinecraftVersion version = verifyMinecraftVersion();
// Set updater - this will not perform any update automatically
updater = Updater.create(this, BUKKIT_DEV_ID, getFile(), UpdateType.NO_DOWNLOAD, true);
unhookTask = new DelayedSingleTask(this);
protocolManager = PacketFilterManager.newBuilder()
.classLoader(getClassLoader())
.server(getServer())
.library(this)
.minecraftVersion(version)
.unhookTask(unhookTask)
.reporter(reporter)
.build();
protocolManager = PacketFilterManager.newBuilder().classLoader(getClassLoader()).server(getServer()).library(this).minecraftVersion(version).unhookTask(unhookTask).reporter(reporter).build();
// Setup error reporter
detailedReporter.addGlobalParameter("manager", protocolManager);
@@ -267,7 +240,7 @@ public class ProtocolLibrary extends JavaPlugin {
try {
switch (command) {
case PROTOCOL:
commandProtocol = new CommandProtocol(reporter, this, updater, config);
commandProtocol = new CommandProtocol(reporter, this, config);
break;
case FILTER:
commandFilter = new CommandFilter(reporter, this, config);
@@ -280,11 +253,8 @@ public class ProtocolLibrary extends JavaPlugin {
throw e;
} catch (ThreadDeath e) {
throw e;
} catch (LinkageError e) {
logger.warning("Failed to register command " + command.name() + ": " + e);
} catch (Throwable e) {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND)
.messageParam(command.name(), e.getMessage()).error(e));
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(command.name(), e.getMessage()).error(e));
}
}
}
@@ -376,26 +346,19 @@ public class ProtocolLibrary extends JavaPlugin {
// Don't do anything else!
if (manager == null)
return;
// Silly plugin reloaders!
if (protocolManager == null) {
Logger directLogging = Logger.getLogger("Minecraft");
String[] message = new String[] {
" ProtocolLib does not support plugin reloaders! ", " Please use the built-in reload command! "
};
String[] message = new String[] { " PROTOCOLLIB DOES NOT SUPPORT PLUGIN RELOADERS. ", " PLEASE USE THE BUILT-IN RELOAD COMMAND. ", };
// Print as severe
for (String line : ChatExtensions.toFlowerBox(message, "*", 3, 1)) {
directLogging.severe(line);
}
disablePlugin();
return;
}
// Check for incompatible plugins
checkForIncompatibility(manager);
// Initialize background compiler
if (backgroundCompiler == null && config.isBackgroundCompilerEnabled()) {
backgroundCompiler = new BackgroundCompiler(getClassLoader(), reporter);
@@ -417,6 +380,7 @@ public class ProtocolLibrary extends JavaPlugin {
// Worker that ensures that async packets are eventually sent
// It also performs the update check.
createPacketTask(server);
} catch (OutOfMemoryError e) {
throw e;
} catch (ThreadDeath e) {
@@ -443,25 +407,6 @@ public class ProtocolLibrary extends JavaPlugin {
}
}
// Plugin authors: Notify me to remove these
public static List<String> INCOMPATIBLE = Arrays.asList("TagAPI");
private void checkForIncompatibility(PluginManager manager) {
for (String plugin : INCOMPATIBLE) {
if (manager.getPlugin(plugin) != null) {
// Special case for TagAPI and iTag
if (plugin.equals("TagAPI")) {
Plugin iTag = manager.getPlugin("iTag");
if (iTag == null || iTag.getDescription().getVersion().startsWith("1.0")) {
logger.severe("Detected incompatible plugin: TagAPI");
}
} else {
logger.severe("Detected incompatible plugin: " + plugin);
}
}
}
}
// Used to check Minecraft version
private MinecraftVersion verifyMinecraftVersion() {
MinecraftVersion minimum = new MinecraftVersion(MINIMUM_MINECRAFT_VERSION);
@@ -478,8 +423,8 @@ public class ProtocolLibrary extends JavaPlugin {
if (current.compareTo(maximum) > 0)
logger.warning("Version " + current + " has not yet been tested! Proceed with caution.");
}
return current;
} catch (Exception e) {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_PARSE_MINECRAFT_VERSION).error(e).messageParam(maximum));
@@ -490,7 +435,7 @@ public class ProtocolLibrary extends JavaPlugin {
private void checkConflictingVersions() {
Pattern ourPlugin = Pattern.compile("ProtocolLib-(.*)\\.jar");
MinecraftVersion currentVersion = new MinecraftVersion(getDescription().getVersion());
MinecraftVersion currentVersion = new MinecraftVersion(this.getDescription().getVersion());
MinecraftVersion newestVersion = null;
// Skip the file that contains this current instance however
@@ -498,29 +443,26 @@ public class ProtocolLibrary extends JavaPlugin {
try {
// Scan the plugin folder for newer versions of ProtocolLib
// The plugin folder isn't always plugins/
File pluginFolder = getDataFolder().getParentFile();
File pluginFolder = new File("plugins/");
File[] candidates = pluginFolder.listFiles();
if (candidates != null) {
for (File candidate : pluginFolder.listFiles()) {
if (candidate.isFile() && !candidate.equals(loadedFile)) {
Matcher match = ourPlugin.matcher(candidate.getName());
if (match.matches()) {
MinecraftVersion version = new MinecraftVersion(match.group(1));
for (File candidate : pluginFolder.listFiles()) {
if (candidate.isFile() && !candidate.equals(loadedFile)) {
Matcher match = ourPlugin.matcher(candidate.getName());
if (candidate.length() == 0) {
// Delete and inform the user
logger.info((candidate.delete() ? "Deleted " : "Could not delete ") + candidate);
} else if (newestVersion == null || newestVersion.compareTo(version) < 0) {
newestVersion = version;
}
if (match.matches()) {
MinecraftVersion version = new MinecraftVersion(match.group(1));
if (candidate.length() == 0) {
// Delete and inform the user
logger.info((candidate.delete() ? "Deleted " : "Could not delete ") + candidate);
} else if (newestVersion == null || newestVersion.compareTo(version) < 0) {
newestVersion = version;
}
}
}
}
} catch (Exception e) {
// TODO This shows [ProtocolLib] and [ProtocolLibrary] in the message
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_DETECT_CONFLICTING_PLUGINS).error(e));
}
@@ -529,9 +471,7 @@ public class ProtocolLibrary extends JavaPlugin {
// We don't need to set internal classes or instances to NULL - that would break the other loaded plugin
skipDisable = true;
throw new IllegalStateException(String.format(
"Detected a newer version of ProtocolLib (%s) in plugin folder than the current (%s). Disabling.",
newestVersion.getVersion(), currentVersion.getVersion()));
throw new IllegalStateException(String.format("Detected a newer version of ProtocolLib (%s) in plugin folder than the current (%s). Disabling.", newestVersion.getVersion(), currentVersion.getVersion()));
}
}
@@ -544,11 +484,11 @@ public class ProtocolLibrary extends JavaPlugin {
PluginCommand command = getCommand(name);
// Try to load the command
if (command != null) {
if (command != null)
command.setExecutor(executor);
} else {
else
throw new RuntimeException("plugin.yml might be corrupt.");
}
} catch (RuntimeException e) {
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_REGISTER_COMMAND).messageParam(name, e.getMessage()).error(e));
}
@@ -577,11 +517,6 @@ public class ProtocolLibrary extends JavaPlugin {
// House keeping
updateConfiguration();
// Check for updates too
if (!UPDATES_DISABLED && (tickCounter % 20) == 0) {
checkUpdates();
}
}
}, ASYNC_MANAGER_DELAY, ASYNC_MANAGER_DELAY);
} catch (OutOfMemoryError e) {
@@ -604,29 +539,6 @@ public class ProtocolLibrary extends JavaPlugin {
}
}
private void checkUpdates() {
// Ignore milliseconds - it's pointless
long currentTime = System.currentTimeMillis() / MILLI_PER_SECOND;
try {
long updateTime = config.getAutoLastTime() + config.getAutoDelay();
// Should we update?
if (currentTime > updateTime && !updater.isChecking()) {
// Initiate the update as if it came from the console
if (config.isAutoDownload())
commandProtocol.updateVersion(getServer().getConsoleSender(), false);
else if (config.isAutoNotify())
commandProtocol.checkVersion(getServer().getConsoleSender(), false);
else
commandProtocol.updateFinished();
}
} catch (Exception e) {
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e));
UPDATES_DISABLED = true;
}
}
@Override
public void onDisable() {
if (skipDisable) {
@@ -740,22 +652,4 @@ public class ProtocolLibrary extends JavaPlugin {
public static ListeningScheduledExecutorService getExecutorSync() {
return executorSync;
}
// ---- Logging Methods
public static void log(Level level, String message, Object... args) {
logger.log(level, MessageFormat.format(message, args));
}
public static void log(String message, Object... args) {
log(Level.INFO, message, args);
}
public static void log(Level level, String message, Throwable ex) {
logger.log(level, message, ex);
}
public void disableUpdates() {
UPDATES_DISABLED = true;
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -53,7 +53,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Send a packet to the given player.
* <p>
* Re-sending a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* Re-sending a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* to delay a packet until a certain condition has been met.
*
* @param receiver - the receiver.
@@ -62,13 +62,13 @@ public interface ProtocolManager extends PacketStream {
* @throws InvocationTargetException - if an error occurred when sending the packet.
*/
@Override
public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters)
public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters)
throws InvocationTargetException;
/**
* Simulate receiving a certain packet from a given player.
* <p>
* Receiving a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* Receiving a previously cancelled packet is discouraged. Use {@link AsyncMarker#incrementProcessingDelay()}
* to delay a packet until a certain condition has been met.
*
* @param sender - the sender.
@@ -78,7 +78,7 @@ public interface ProtocolManager extends PacketStream {
* @throws IllegalAccessException If the underlying method caused an error.
*/
@Override
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
throws IllegalAccessException, InvocationTargetException;
/**
@@ -89,9 +89,9 @@ public interface ProtocolManager extends PacketStream {
public void broadcastServerPacket(PacketContainer packet);
/**
* Broadcast a packet to every player that is receiving information about a given entity.
* Broadcast a packet to every player that is receiving information about a given entity.
* <p>
* This is usually every player in the same world within an observable distance. If the entity is a
* This is usually every player in the same world within an observable distance. If the entity is a
* player, it will only be included if <i>includeTracker</i> is TRUE.
* @param packet - the packet to broadcast.
* @param entity - the entity whose trackers we will inform.
@@ -115,17 +115,17 @@ public interface ProtocolManager extends PacketStream {
public ImmutableSet<PacketListener> getPacketListeners();
/**
* Adds a packet listener.
* Adds a packet listener.
* <p>
* Adding an already registered listener has no effect. If you need to change the packets
* the current listener is observing, you must first remove the packet listener before you
* Adding an already registered listener has no effect. If you need to change the packets
* the current listener is observing, you must first remove the packet listener before you
* can register it again.
* @param listener - new packet listener.
*/
public void addPacketListener(PacketListener listener);
/**
* Removes a given packet listener.
* Removes a given packet listener.
* <p>
* Attempting to remove a listener that doesn't exist has no effect.
* @param listener - the packet listener to remove.
@@ -158,7 +158,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Constructs a new encapsulated Minecraft packet with the given ID.
* <p>
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* give non-primitive fields in the packet sensible default values. For instance, certain
* packets - like Packet60Explosion - require a List or Set to be non-null. If the
* forceDefaults option is true, the List or Set will be automatically created.
@@ -175,7 +175,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Constructs a new encapsulated Minecraft packet with the given ID.
* <p>
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* If set to true, the <i>forceDefaults</i> option will force the system to automatically
* give non-primitive fields in the packet sensible default values. For instance, certain
* packets - like Packet60Explosion - require a List or Set to be non-null. If the
* forceDefaults option is true, the List or Set will be automatically created.
@@ -199,7 +199,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Construct a packet using the special builtin Minecraft constructors.
* @param type - the packet type.
* @param id - the packet type.
* @param arguments - arguments that will be passed to the constructor.
* @return The packet constructor.
*/
@@ -208,7 +208,7 @@ public interface ProtocolManager extends PacketStream {
/**
* Completely resend an entity to a list of clients.
* <p>
* Note that this method is NOT thread safe. If you call this method from anything
* Note that this method is NOT thread safe. If you call this method from anything
* but the main thread, it will throw an exception.
* @param entity - entity to refresh.
* @param observers - the clients to update.
@@ -269,7 +269,7 @@ public interface ProtocolManager extends PacketStream {
public MinecraftVersion getMinecraftVersion();
/**
* Determines whether or not this protocol manager has been disabled.
* Determines whether or not this protocol manager has been disabled.
* @return TRUE if it has, FALSE otherwise.
*/
public boolean isClosed();
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -23,8 +23,9 @@ import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import com.comphenix.protocol.compat.guava.Guava;
import com.google.common.collect.DiscreteDomains;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
/**
* Used to parse ranges in CommandPacket.
@@ -67,7 +68,7 @@ class RangeParser {
throw new IllegalArgumentException("Cannot form a range without a upper limit.");
// This is a proper range
range = Guava.closedRange(Integer.parseInt(current), Integer.parseInt(tokens.get(i + 2)));
range = Ranges.closed(Integer.parseInt(current), Integer.parseInt(tokens.get(i + 2)));
ranges.add(range);
// Skip the two next tokens
@@ -75,7 +76,7 @@ class RangeParser {
} else {
// Just a single number
range = Guava.singleton(Integer.parseInt(current));
range = Ranges.singleton(Integer.parseInt(current));
ranges.add(range);
}
@@ -101,7 +102,7 @@ class RangeParser {
// Set every ID
for (Range<Integer> range : ranges) {
for (int id : Guava.toSet(range)) {
for (int id : range.asSet(DiscreteDomains.integers())) {
set[id] = true;
}
}
@@ -114,7 +115,7 @@ class RangeParser {
}
} else {
if (start >= 0) {
result.add(Guava.closedRange(start, i - 1));
result.add(Ranges.closed(start, i - 1));
start = -1;
}
}
@@ -0,0 +1,27 @@
package com.comphenix.protocol.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Indicate that this API and its descendants are only valid on Spigot.
* @author Kristian
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PACKAGE,
ElementType.PARAMETER, ElementType.TYPE, ElementType.FIELD})
public @interface Spigot {
/**
* The minimum build number of Spigot where this is valid.
* @return The minimum build.
*/
int minimumBuild();
/**
* The maximum build number of Spigot where this is valid, or Integer.MAX_VALUE if not set.
* @return The maximum build number.
*/
int maximumBuild() default Integer.MAX_VALUE;
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -81,7 +81,7 @@ public class AsyncFilterManager implements AsynchronousManager {
/**
* Initialize a asynchronous filter manager.
* <p>
* <b>Internal method</b>. Retrieve the global asynchronous manager from the protocol manager instead.
* <b>Internal method</b>. Retrieve the global asynchronous manager from the protocol manager instead.
* @param reporter - desired error reporter.
* @param scheduler - task scheduler.
*/
@@ -148,7 +148,7 @@ public class AsyncFilterManager implements AsynchronousManager {
ImmutableSet.Builder<PacketListener> builder = ImmutableSet.builder();
// Add every asynchronous packet listener
for (PrioritizedListener<AsyncListenerHandler> handler :
for (PrioritizedListener<AsyncListenerHandler> handler :
Iterables.concat(serverProcessingQueue.values(), clientProcessingQueue.values())) {
builder.add(handler.getListener().getAsyncListener());
}
@@ -221,7 +221,7 @@ public class AsyncFilterManager implements AsynchronousManager {
if (listener == null)
throw new IllegalArgumentException("listener cannot be NULL.");
AsyncListenerHandler handler =
AsyncListenerHandler handler =
findHandler(serverProcessingQueue, listener.getSendingWhitelist(), listener);
if (handler == null) {
@@ -232,7 +232,7 @@ public class AsyncFilterManager implements AsynchronousManager {
// Search for the first correct handler
private AsyncListenerHandler findHandler(PacketProcessingQueue queue, ListeningWhitelist search, PacketListener target) {
if (ListeningWhitelist.isEmpty(search))
if (ListeningWhitelist.isEmpty(search))
return null;
for (PacketType type : search.getTypes()) {
@@ -250,7 +250,7 @@ public class AsyncFilterManager implements AsynchronousManager {
if (handler == null)
throw new IllegalArgumentException("listenerToken cannot be NULL");
handler.cancel();
handler.cancel();
}
// Called by AsyncListenerHandler
@@ -295,7 +295,7 @@ public class AsyncFilterManager implements AsynchronousManager {
private void unregisterAsyncHandlers(PacketProcessingQueue processingQueue, Plugin plugin) {
// Iterate through every packet listener
for (PrioritizedListener<AsyncListenerHandler> listener : processingQueue.values()) {
for (PrioritizedListener<AsyncListenerHandler> listener : processingQueue.values()) {
// Remove the listener
if (Objects.equal(listener.getListener().getPlugin(), plugin)) {
unregisterAsyncHandler(listener.getListener());
@@ -305,28 +305,22 @@ public class AsyncFilterManager implements AsynchronousManager {
/**
* Enqueue a packet for asynchronous processing.
*
* @param syncPacket - synchronous packet event.
* @param asyncMarker - the asynchronous marker to use.
*/
public synchronized void enqueueSyncPacket(PacketEvent syncPacket, AsyncMarker asyncMarker) {
PacketEvent newEvent = PacketEvent.fromSynchronous(syncPacket, asyncMarker);
if (asyncMarker.isQueued() || asyncMarker.isTransmitted())
throw new IllegalArgumentException("Cannot queue a packet that has already been queued.");
asyncMarker.setQueuedSendingIndex(asyncMarker.getNewSendingIndex());
// The player is only be null when they're logged out,
// so this should be a pretty safe check
Player player = newEvent.getPlayer();
if (player != null) {
// Start the process
getSendingQueue(syncPacket).enqueue(newEvent);
// We know this is occuring on the main thread, so pass TRUE
getProcessingQueue(syncPacket).enqueue(newEvent, true);
}
// Start the process
getSendingQueue(syncPacket).enqueue(newEvent);
// We know this is occuring on the main thread, so pass TRUE
getProcessingQueue(syncPacket).enqueue(newEvent, true);
}
@Override
@@ -368,21 +362,23 @@ public class AsyncFilterManager implements AsynchronousManager {
* @return Asynchronous marker.
*/
public AsyncMarker createAsyncMarker() {
return createAsyncMarker(AsyncMarker.DEFAULT_TIMEOUT_DELTA);
return createAsyncMarker(AsyncMarker.DEFAULT_SENDING_DELTA, AsyncMarker.DEFAULT_TIMEOUT_DELTA);
}
/**
* Construct an async marker with the given sending priority delta and timeout delta.
* @param sendingDelta - how many packets we're willing to wait.
* @param timeoutDelta - how long (in ms) until the packet expire.
* @return An async marker.
*/
public AsyncMarker createAsyncMarker(long timeoutDelta) {
return createAsyncMarker(timeoutDelta, currentSendingIndex.incrementAndGet());
public AsyncMarker createAsyncMarker(long sendingDelta, long timeoutDelta) {
return createAsyncMarker(sendingDelta, timeoutDelta,
currentSendingIndex.incrementAndGet(), System.currentTimeMillis());
}
// Helper method
private AsyncMarker createAsyncMarker(long timeoutDelta, long sendingIndex) {
return new AsyncMarker(manager, sendingIndex, System.currentTimeMillis(), timeoutDelta);
private AsyncMarker createAsyncMarker(long sendingDelta, long timeoutDelta, long sendingIndex, long currentTime) {
return new AsyncMarker(manager, sendingIndex, sendingDelta, System.currentTimeMillis(), timeoutDelta);
}
@Override
@@ -472,8 +468,6 @@ public class AsyncFilterManager implements AsynchronousManager {
/**
* Send any due packets, or clean up packets that have expired.
* @param tickCounter Tick counter
* @param onMainThread Whether or not to execute on the main thread
*/
public void sendProcessedPackets(int tickCounter, boolean onMainThread) {
// The server queue is unlikely to need checking that often
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -48,7 +48,7 @@ import com.google.common.base.Joiner;
*/
public class AsyncListenerHandler {
public static final ReportType REPORT_HANDLER_NOT_STARTED = new ReportType(
"Plugin %s did not start the asynchronous handler %s by calling start() or syncStart().");
"Plugin %s did not start the asynchronous handler %s by calling start() or syncStart().");
/**
* Signal an end to packet processing.
@@ -209,7 +209,6 @@ public class AsyncListenerHandler {
* close a specific worker is less efficient than stopping an arbitrary worker.
* <p>
* <b>Warning</b>: Never call the run() method in the main thread.
* @return The listener loop
*/
public AsyncRunnable getListenerLoop() {
return new AsyncRunnable() {
@@ -316,7 +315,7 @@ public class AsyncListenerHandler {
* public Void apply(&#64;Nullable AsyncRunnable workerLoop) {
* Thread thread = Thread.currentThread();
* int prevPriority = thread.getPriority();
*
*
* thread.setPriority(Thread.MIN_PRIORITY);
* workerLoop.run();
* thread.setPriority(prevPriority);
@@ -358,9 +357,9 @@ public class AsyncListenerHandler {
* @return A friendly thread name.
*/
public String getFriendlyWorkerName(int id) {
return String.format("Protocol Worker #%s - %s - [recv: %s, send: %s]",
id,
PacketAdapter.getPluginName(listener),
return String.format("Protocol Worker #%s - %s - [recv: %s, send: %s]",
id,
PacketAdapter.getPluginName(listener),
fromWhitelist(listener.getReceivingWhitelist()),
fromWhitelist(listener.getSendingWhitelist())
);
@@ -384,8 +383,8 @@ public class AsyncListenerHandler {
* This is useful if you need to synchronize with the main thread in your packet listener, but
* you're not performing any expensive processing.
* <p>
* <b>Note</b>: Use a asynchronous worker if the packet listener may use more than 0.5 ms
* of processing time on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* <b>Note</b>: Use a asynchronous worker if the packet listener may use more than 0.5 ms
* of processing time on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* to use the Bukkit API instead.
* @return TRUE if the synchronized processing was successfully started, FALSE if it's already running.
* @throws IllegalStateException If we couldn't start the underlying task.
@@ -400,12 +399,12 @@ public class AsyncListenerHandler {
* This is useful if you need to synchronize with the main thread in your packet listener, but
* you're not performing any expensive processing.
* <p>
* The processing time parameter gives the upper bound for the amount of time spent processing pending packets.
* It should be set to a fairly low number, such as 0.5 ms or 1% of a game tick - to reduce the impact
* The processing time parameter gives the upper bound for the amount of time spent processing pending packets.
* It should be set to a fairly low number, such as 0.5 ms or 1% of a game tick - to reduce the impact
* on the main thread. Never go beyond 50 milliseconds.
* <p>
* <b>Note</b>: Use a asynchronous worker if the packet listener may exceed the ideal processing time
* on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* <b>Note</b>: Use a asynchronous worker if the packet listener may exceed the ideal processing time
* on a single packet. Do as much as possible on the worker thread, and schedule synchronous tasks
* to use the Bukkit API instead.
*
* @param time - the amount of processing time alloted per game tick (20 ticks per second).
@@ -504,7 +503,7 @@ public class AsyncListenerHandler {
}
/**
* Set the current number of workers.
* Set the current number of workers.
* <p>
* This method can only be called with a count of zero when the listener is closing.
* @param count - new number of workers.
@@ -564,7 +563,7 @@ public class AsyncListenerHandler {
*/
private void listenerLoop(int workerID) {
// Danger, danger!
if (Thread.currentThread().getId() == mainThread.getId())
if (Thread.currentThread().getId() == mainThread.getId())
throw new IllegalStateException("Do not call this method from the main thread.");
if (cancelled)
throw new IllegalStateException("Listener has been cancelled. Create a new listener instead.");
@@ -585,7 +584,7 @@ public class AsyncListenerHandler {
// This is a bit slow, but it should be safe
synchronized (stopLock) {
// Are we the one who is supposed to stop?
if (stoppedTasks.contains(workerID))
if (stoppedTasks.contains(workerID))
return;
if (waitForStops())
return;
@@ -617,7 +616,7 @@ public class AsyncListenerHandler {
AsyncMarker marker = packet.getAsyncMarker();
// Here's the core of the asynchronous processing
try {
try {
synchronized (marker.getProcessingLock()) {
marker.setListenerHandler(this);
marker.setWorkerID(workerID);
@@ -625,7 +624,7 @@ public class AsyncListenerHandler {
// We're not THAT worried about performance here
if (timedManager.isTiming()) {
// Retrieve the tracker to use
TimedTracker tracker = timedManager.getTracker(listener,
TimedTracker tracker = timedManager.getTracker(listener,
packet.isServerPacket() ? ListenerType.ASYNC_SERVER_SIDE : ListenerType.ASYNC_CLIENT_SIDE);
long token = tracker.beginTracking();
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -24,18 +24,14 @@ import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import com.comphenix.protocol.PacketStream;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.PrioritizedListener;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.google.common.primitives.Longs;
/**
@@ -110,7 +106,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
* Create a container for asyncronous packets.
* @param initialTime - the current time in milliseconds since 01.01.1970 00:00.
*/
AsyncMarker(PacketStream packetStream, long sendingIndex, long initialTime, long timeoutDelta) {
AsyncMarker(PacketStream packetStream, long sendingIndex, long sendingDelta, long initialTime, long timeoutDelta) {
if (packetStream == null)
throw new IllegalArgumentException("packetStream cannot be NULL");
@@ -127,11 +123,11 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
/**
* Retrieve the time the packet was initially queued for asynchronous processing.
* @return The initial time in number of milliseconds since 01.01.1970 00:00.
* @return The initial time in number of milliseconds since 01.01.1970 00:00.
*/
public long getInitialTime() {
return initialTime;
}
}
/**
* Retrieve the time the packet will be forcefully rejected.
@@ -213,11 +209,11 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
* Increment the number of times the current packet must be signalled as done before its transmitted.
* <p>
* This is useful if an asynchronous listener is waiting for further information before the
* packet can be sent to the user. A packet listener <b>MUST</b> eventually call
* packet can be sent to the user. A packet listener <b>MUST</b> eventually call
* {@link AsyncFilterManager#signalPacketTransmission(PacketEvent)},
* even if the packet is cancelled, after this method is called.
* even if the packet is cancelled, after this method is called.
* <p>
* It is recommended that processing outside a packet listener is wrapped in a synchronized block
* It is recommended that processing outside a packet listener is wrapped in a synchronized block
* using the {@link #getProcessingLock()} method.
*
* @return The new processing delay.
@@ -335,7 +331,7 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
}
/**
* Set the current asynchronous listener handler.
* Set the current asynchronous listener handler.
* <p>
* Used by the worker to update the value.
* @param listenerHandler - new listener handler.
@@ -401,11 +397,10 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
/**
* Determine if Minecraft allows asynchronous processing of this packet.
* @param event - packet event
* @return TRUE if it does, FALSE otherwise.
* @throws FieldAccessException If determining fails for some reasaon
*/
public boolean isMinecraftAsync(PacketEvent event) throws FieldAccessException {
if (isMinecraftAsync == null && !alwaysSync) {
try {
isMinecraftAsync = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethodByName("a_.*");
@@ -420,34 +415,18 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
} else if (methods.size() == 1) {
// We're in 1.2.5
alwaysSync = true;
} else if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
// The centralized async marker was removed in 1.8
// Incoming chat packets can be async
if (event.getPacketType() == PacketType.Play.Client.CHAT) {
String content = event.getPacket().getStrings().readSafely(0);
if (content != null) {
// Incoming chat packets are async only if they aren't commands
return ! content.startsWith("/");
} else {
ProtocolLibrary.log(Level.WARNING, "Failed to determine contents of incoming chat packet!");
alwaysSync = true;
}
} else {
// TODO: Find more cases of async packets
return false;
}
} else {
ProtocolLibrary.log(Level.INFO, "Could not determine asynchronous state of packets (this can probably be ignored)");
System.err.println("[ProtocolLib] Cannot determine asynchronous state of packets!");
alwaysSync = true;
}
}
}
if (alwaysSync) {
return false;
} else {
try {
// Wrap exceptions
// Wrap exceptions
return (Boolean) isMinecraftAsync.invoke(event.getPacket().getHandle());
} catch (IllegalArgumentException e) {
throw new FieldAccessException("Illegal argument", e);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -35,7 +35,6 @@ public interface AsyncRunnable extends Runnable {
* <p>
* This may not occur right away.
* @return TRUE if the thread was stopped, FALSE if it was already stopped.
* @throws InterruptedException if it is interrupted
*/
public boolean stop() throws InterruptedException;
@@ -18,7 +18,6 @@ public class IntegerMap<T> {
/**
* Construct a new integer map.
* @param <T> Parameter type
* @return A new integer map.
*/
public static <T> IntegerMap<T> newMap() {
@@ -52,7 +51,7 @@ public class IntegerMap<T> {
public T put(int key, T value) {
ensureCapacity(key);
T old = array[key];
T old = array[key];
array[key] = Preconditions.checkNotNull(value, "value cannot be NULL");
if (old == null)
@@ -1,67 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.guava;
import java.io.DataInputStream;
import java.util.Set;
import java.util.logging.Level;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.ProtocolLibrary;
import com.google.common.collect.Range;
/**
* @author dmulloy2
*/
public class Guava {
private static GuavaCompat compat;
static {
try {
Range.closed(1, 2);
compat = new Guava17();
} catch (Throwable ex) {
try {
Class<?> clazz = Class.forName("com.comphenix.protocol.compat.guava.Guava10");
compat = (GuavaCompat) clazz.newInstance();
} catch (Throwable ex1) {
ProtocolLibrary.log(Level.SEVERE, "Failed to create Guava 10 compat:", ex1);
}
}
}
private static GuavaCompat getCompat() {
return compat;
}
public static <C extends Comparable<C>> Range<C> closedRange(C lower, C upper) {
return getCompat().closedRange(lower, upper);
}
public static <C extends Comparable<C>> Range<C> singleton(C singleton) {
return getCompat().singletonRange(singleton);
}
public static Set<Integer> toSet(Range<Integer> range) {
return getCompat().toSet(range);
}
public static DataInputStream addHeader(DataInputStream input, PacketType type) {
return getCompat().addHeader(input, type);
}
}
@@ -1,76 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.guava;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.google.common.collect.ContiguousSet;
import com.google.common.collect.DiscreteDomain;
import com.google.common.collect.Range;
import com.google.common.io.ByteSource;
/**
* @author dmulloy2
*/
public class Guava17 implements GuavaCompat {
@Override
public <C extends Comparable<C>> Range<C> closedRange(C lower, C upper) {
return Range.closed(lower, upper);
}
@Override
public <C extends Comparable<C>> Range<C> singletonRange(C singleton) {
return Range.singleton(singleton);
}
@Override
public Set<Integer> toSet(Range<Integer> range) {
return ContiguousSet.create(range, DiscreteDomain.integers());
}
@Override
public DataInputStream addHeader(final DataInputStream input, final PacketType type) {
ByteSource header = new ByteSource() {
@Override
public InputStream openStream() throws IOException {
byte[] data = new byte[] { (byte) type.getLegacyId() };
return new ByteArrayInputStream(data);
}
};
ByteSource data = new ByteSource() {
@Override
public InputStream openStream() throws IOException {
return input;
}
};
// Combine them into a single stream
try {
return new DataInputStream(ByteSource.concat(header, data).openStream());
} catch (IOException e) {
throw new RuntimeException("Cannot add header.", e);
}
}
}
@@ -1,38 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.guava;
import java.io.DataInputStream;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.google.common.collect.Range;
/**
* @author dmulloy2
*/
public interface GuavaCompat {
<C extends Comparable<C>> Range<C> closedRange(C lower, C upper);
<C extends Comparable<C>> Range<C> singletonRange(C singleton);
Set<Integer> toSet(Range<Integer> range);
DataInputStream addHeader(DataInputStream input, PacketType type);
}
@@ -1,28 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
import com.comphenix.protocol.injector.netty.Injector;
/**
* @author dmulloy2
*/
public interface ChannelInjector extends Injector {
WrappedChannel getChannel();
}
@@ -1,103 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
/**
* @author dmulloy2
*/
public class LegacyProtocolRegistry extends ProtocolRegistry {
public LegacyProtocolRegistry() {
super();
}
@Override
protected void initialize() {
final Object[] protocols = enumProtocol.getEnumConstants();
List<Map<Integer, Class<?>>> serverMaps = Lists.newArrayList();
List<Map<Integer, Class<?>>> clientMaps = Lists.newArrayList();
StructureModifier<Object> modifier = null;
// Result
Register result = new Register();
for (Object protocol : protocols) {
if (modifier == null)
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
StructureModifier<Map<Integer, Class<?>>> maps = modifier.withTarget(protocol).withType(Map.class);
serverMaps.add(maps.read(0));
clientMaps.add(maps.read(1));
}
// Maps we have to occationally check have changed
for (Map<Integer, Class<?>> map : Iterables.concat(serverMaps, clientMaps)) {
result.containers.add(new MapContainer(map));
}
// Heuristic - there are more server packets than client packets
if (sum(clientMaps) > sum(serverMaps)) {
// Swap if this is violated
List<Map<Integer, Class<?>>> temp = serverMaps;
serverMaps = clientMaps;
clientMaps = temp;
}
for (int i = 0; i < protocols.length; i++) {
Enum<?> enumProtocol = (Enum<?>) protocols[i];
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
// Associate known types
associatePackets(result, serverMaps.get(i), equivalent, Sender.SERVER);
associatePackets(result, clientMaps.get(i), equivalent, Sender.CLIENT);
}
// Exchange (thread safe, as we have only one writer)
this.register = result;
}
@Override
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
PacketType type = PacketType.fromID(protocol, sender, entry.getKey(), entry.getValue());
try {
register.typeToClass.put(type, entry.getValue());
if (sender == Sender.SERVER)
register.serverPackets.add(type);
if (sender == Sender.CLIENT)
register.clientPackets.add(type);
} catch (IllegalArgumentException ex) {
// Sometimes this happens with fake packets, just ignore it
}
}
}
}
@@ -1,99 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.util.logging.Level;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.compat.netty.independent.IndependentNetty;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.PacketFilterManager;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
/**
* @author dmulloy2
*/
public class Netty {
private static NettyCompat compat;
static {
try {
Class.forName("io.netty.buffer.ByteBuf");
compat = new IndependentNetty();
} catch (ClassNotFoundException ex) {
try {
Class<?> clazz = Class.forName("com.comphenix.protocol.compat.netty.shaded.ShadedNetty");
compat = (NettyCompat) clazz.newInstance();
} catch (Exception ex1) {
ProtocolLibrary.log(Level.SEVERE, "Failed to create legacy netty compat:", ex1);
}
}
}
private static NettyCompat getCompat() {
return compat;
}
public static boolean isIndependent() {
return compat instanceof IndependentNetty;
}
public static WrappedByteBuf createPacketBuffer() {
return getCompat().createPacketBuffer();
}
public static Class<?> getGenericFutureListenerArray() {
return getCompat().getGenericFutureListenerArray();
}
public static Class<?> getChannelHandlerContext() {
return getCompat().getChannelHandlerContext();
}
public static String toEncodedText(CompressedImage image) {
return getCompat().toEncodedText(image);
}
public static WrappedByteBuf decode(byte[] encoded) {
return getCompat().decode(encoded);
}
public static ProtocolInjector getProtocolInjector(Plugin library, PacketFilterManager packetFilterManager, ErrorReporter reporter) {
return getCompat().getProtocolInjector(library, packetFilterManager, reporter);
}
public static WrappedByteBuf packetReader(DataInputStream input) {
return getCompat().packetReader(input);
}
public static WrappedByteBuf packetWriter(DataOutputStream output) {
return getCompat().packetWriter(output);
}
public static WrappedByteBuf copiedBuffer(byte[] array) {
return getCompat().copiedBuffer(array);
}
public static WrappedByteBuf buffer() {
return getCompat().buffer();
}
}
@@ -1,55 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
/**
* @author dmulloy2
*/
// TODO: Sort out packet readers/writers
public interface NettyCompat {
WrappedByteBuf createPacketBuffer();
WrappedByteBuf copiedBuffer(byte[] array);
WrappedByteBuf buffer();
Class<?> getGenericFutureListenerArray();
Class<?> getChannelHandlerContext();
String toEncodedText(CompressedImage image);
WrappedByteBuf decode(byte[] encoded);
ProtocolInjector getProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter);
WrappedByteBuf packetReader(DataInputStream input);
WrappedByteBuf packetWriter(DataOutputStream output);
}
@@ -1,38 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
/**
* @author dmulloy2
*/
public interface ProtocolInjector extends ChannelListener {
PlayerInjectionHandler getPlayerInjector();
PacketInjector getPacketInjector();
void setDebug(boolean debug);
void inject();
void close();
}
@@ -1,46 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author dmulloy2
*/
public interface WrappedByteBuf {
void writeBytes(ObjectInputStream input, int id) throws IOException;
Object getHandle();
int readableBytes();
void readBytes(ObjectOutputStream output, int readableBytes) throws IOException;
void readBytes(byte[] data);
void writeByte(byte b);
void writeByte(int i);
void writeBytes(byte[] bytes);
byte[] array();
}
@@ -1,26 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty;
/**
* @author dmulloy2
*/
public interface WrappedChannel {
void writeAndFlush(Object packet);
}
@@ -1,105 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.base64.Base64;
import io.netty.util.concurrent.GenericFutureListener;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.compat.netty.NettyCompat;
import com.comphenix.protocol.compat.netty.ProtocolInjector;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedServerPing.CompressedImage;
import com.google.common.base.Charsets;
/**
* @author dmulloy2
*/
public class IndependentNetty implements NettyCompat {
@Override
public WrappedByteBuf createPacketBuffer() {
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
Class<?> packetSerializer = MinecraftReflection.getPacketDataSerializerClass();
try {
return new NettyByteBuf((ByteBuf) packetSerializer.getConstructor(ByteBuf.class).newInstance(buffer));
} catch (Exception e) {
throw new RuntimeException("Cannot construct packet serializer.", e);
}
}
@Override
public Class<?> getGenericFutureListenerArray() {
return GenericFutureListener[].class;
}
@Override
public Class<?> getChannelHandlerContext() {
return ChannelHandlerContext.class;
}
@Override
public String toEncodedText(CompressedImage image) {
final ByteBuf buffer = Unpooled.wrappedBuffer(image.getDataCopy());
String computed = "data:" + image.getMime() + ";base64," +
Base64.encode(buffer).toString(Charsets.UTF_8);
return computed;
}
@Override
public WrappedByteBuf decode(byte[] encoded) {
return new NettyByteBuf(Base64.decode(Unpooled.wrappedBuffer(encoded)));
}
@Override
public ProtocolInjector getProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter) {
return new NettyProtocolInjector(plugin, invoker, reporter);
}
@Override
public WrappedByteBuf packetReader(DataInputStream input) {
return new NettyByteBuf(NettyByteBufAdapter.packetReader(input));
}
@Override
public WrappedByteBuf packetWriter(DataOutputStream output) {
return new NettyByteBuf(NettyByteBufAdapter.packetWriter(output));
}
@Override
public WrappedByteBuf copiedBuffer(byte[] array) {
return new NettyByteBuf(Unpooled.copiedBuffer(array));
}
@Override
public WrappedByteBuf buffer() {
return new NettyByteBuf(Unpooled.buffer());
}
}
@@ -1,234 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.Callable;
import com.google.common.collect.Lists;
public class NettyBootstrapList implements List<Object> {
private List<Object> delegate;
private ChannelHandler handler;
/**
* Construct a new bootstrap list.
* @param delegate - the delegate.
* @param handler - the channel handler to add.
*/
public NettyBootstrapList(List<Object> delegate, ChannelHandler handler) {
this.delegate = delegate;
this.handler = handler;
// Process all existing bootstraps
for (Object item : this) {
processElement(item);
}
}
@Override
public synchronized boolean add(Object element) {
processElement(element);
return delegate.add(element);
}
@Override
public synchronized boolean addAll(Collection<? extends Object> collection) {
List<Object> copy = Lists.newArrayList(collection);
// Process the collection before we pass it on
for (Object element : copy) {
processElement(element);
}
return delegate.addAll(copy);
}
@Override
public synchronized Object set(int index, Object element) {
Object old = delegate.set(index, element);
// Handle the old future, and the newly inserted future
if (old != element) {
unprocessElement(old);
processElement(element);
}
return old;
}
/**
* Process a single element.
* @param element - the element.
*/
protected void processElement(Object element) {
if (element instanceof ChannelFuture) {
processBootstrap((ChannelFuture) element);
}
}
/**
* Unprocess a single element.
* @param element - the element to unprocess.
*/
protected void unprocessElement(Object element) {
if (element instanceof ChannelFuture) {
unprocessBootstrap((ChannelFuture) element);
}
}
/**
* Process a single channel future.
* @param future - the future.
*/
protected void processBootstrap(ChannelFuture future) {
// Important: Must be addFirst()
future.channel().pipeline().addFirst(handler);
}
/**
* Revert any changes we made to the channel future.
* @param future - the future.
*/
protected void unprocessBootstrap(ChannelFuture future) {
final Channel channel = future.channel();
// For thread safety - see ChannelInjector.close()
channel.eventLoop().submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
channel.pipeline().remove(handler);
return null;
}
});
}
/**
* Close and revert all changes.
*/
public synchronized void close() {
for (Object element : this)
unprocessElement(element);
}
// Boiler plate
@Override
public synchronized int size() {
return delegate.size();
}
@Override
public synchronized boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
return delegate.contains(o);
}
@Override
public synchronized Iterator<Object> iterator() {
return delegate.iterator();
}
@Override
public synchronized Object[] toArray() {
return delegate.toArray();
}
@Override
public synchronized <T> T[] toArray(T[] a) {
return delegate.toArray(a);
}
@Override
public synchronized boolean remove(Object o) {
return delegate.remove(o);
}
@Override
public synchronized boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
@Override
public synchronized boolean addAll(int index, Collection<? extends Object> c) {
return delegate.addAll(index, c);
}
@Override
public synchronized boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
@Override
public synchronized boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
@Override
public synchronized void clear() {
delegate.clear();
}
@Override
public synchronized Object get(int index) {
return delegate.get(index);
}
@Override
public synchronized void add(int index, Object element) {
delegate.add(index, element);
}
@Override
public synchronized Object remove(int index) {
return delegate.remove(index);
}
@Override
public synchronized int indexOf(Object o) {
return delegate.indexOf(o);
}
@Override
public synchronized int lastIndexOf(Object o) {
return delegate.lastIndexOf(o);
}
@Override
public synchronized ListIterator<Object> listIterator() {
return delegate.listIterator();
}
@Override
public synchronized ListIterator<Object> listIterator(int index) {
return delegate.listIterator(index);
}
@Override
public synchronized List<Object> subList(int fromIndex, int toIndex) {
return delegate.subList(fromIndex, toIndex);
}
// End boiler plate
}
@@ -1,83 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.buffer.ByteBuf;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.ref.WeakReference;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
/**
* @author dmulloy2
*/
public class NettyByteBuf implements WrappedByteBuf {
private WeakReference<ByteBuf> handle;
public NettyByteBuf(ByteBuf handle) {
this.handle = new WeakReference<ByteBuf>(handle);
}
@Override
public void writeBytes(ObjectInputStream input, int id) throws IOException {
handle.get().writeBytes(input, id);
}
@Override
public Object getHandle() {
return handle.get();
}
@Override
public int readableBytes() {
return handle.get().readableBytes();
}
@Override
public void readBytes(ObjectOutputStream output, int readableBytes) throws IOException {
handle.get().readBytes(output, readableBytes);
}
@Override
public void readBytes(byte[] data) {
handle.get().readBytes(data);
}
@Override
public void writeByte(byte b) {
handle.get().writeByte(b);
}
@Override
public void writeByte(int i) {
handle.get().writeByte(i);
}
@Override
public void writeBytes(byte[] bytes) {
handle.get().writeBytes(bytes);
}
@Override
public byte[] array() {
return handle.get().array();
}
}
@@ -1,392 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.buffer.AbstractByteBuf;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.Channels;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.ScatteringByteChannel;
import java.nio.channels.WritableByteChannel;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.io.ByteStreams;
/**
* Construct a ByteBuf around an input stream and an output stream.
* <p>
* Note that as streams usually don't support seeking, this implementation will ignore
* all indexing in the byte buffer.
* @author Kristian
*/
public class NettyByteBufAdapter extends AbstractByteBuf {
private DataInputStream input;
private DataOutputStream output;
// For modifying the reader or writer index
private static FieldAccessor READER_INDEX;
private static FieldAccessor WRITER_INDEX;
private static final int CAPACITY = Short.MAX_VALUE;
private NettyByteBufAdapter(DataInputStream input, DataOutputStream output) {
// Just pick a figure
super(CAPACITY);
this.input = input;
this.output = output;
// Prepare accessors
try {
if (READER_INDEX == null) {
READER_INDEX = Accessors.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("readerIndex"));
}
if (WRITER_INDEX == null) {
WRITER_INDEX = Accessors.getFieldAccessor(AbstractByteBuf.class.getDeclaredField("writerIndex"));
}
} catch (Exception e) {
throw new RuntimeException("Cannot initialize ByteBufAdapter.", e);
}
// "Infinite" reading/writing
if (input == null)
READER_INDEX.set(this, Integer.MAX_VALUE);
if (output == null)
WRITER_INDEX.set(this, Integer.MAX_VALUE);
}
/**
* Construct a new Minecraft packet serializer using the current byte buf adapter.
* @param input - the input stream.
* @return A packet serializer with a wrapped byte buf adapter.
*/
public static ByteBuf packetReader(DataInputStream input) {
return (ByteBuf) MinecraftReflection.getPacketDataSerializer(new NettyByteBufAdapter(input, null));
}
/**
* Construct a new Minecraft packet deserializer using the current byte buf adapter.
* @param output - the output stream.
* @return A packet serializer with a wrapped byte buf adapter.
*/
public static ByteBuf packetWriter(DataOutputStream output) {
return (ByteBuf) MinecraftReflection.getPacketDataSerializer(new NettyByteBufAdapter(null, output));
}
@Override
public int refCnt() {
return 1;
}
@Override
public boolean release() {
return false;
}
@Override
public boolean release(int paramInt) {
return false;
}
@Override
protected byte _getByte(int paramInt) {
try {
return input.readByte();
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
}
@Override
protected short _getShort(int paramInt) {
try {
return input.readShort();
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
}
@Override
protected int _getUnsignedMedium(int paramInt) {
try {
return input.readUnsignedShort();
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
}
@Override
protected int _getInt(int paramInt) {
try {
return input.readInt();
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
}
@Override
protected long _getLong(int paramInt) {
try {
return input.readLong();
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
}
@Override
protected void _setByte(int index, int value) {
try {
output.writeByte(value);
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
protected void _setShort(int index, int value) {
try {
output.writeShort(value);
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
protected void _setMedium(int index, int value) {
try {
output.writeShort(value);
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
protected void _setInt(int index, int value) {
try {
output.writeInt(value);
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
protected void _setLong(int index, long value) {
try {
output.writeLong(value);
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
public int capacity() {
return CAPACITY;
}
@Override
public ByteBuf capacity(int paramInt) {
return this;
}
@Override
public ByteBufAllocator alloc() {
return null;
}
@Override
public ByteOrder order() {
return ByteOrder.LITTLE_ENDIAN;
}
@Override
public ByteBuf unwrap() {
return null;
}
@Override
public boolean isDirect() {
return false;
}
@Override
public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
try {
for (int i = 0; i < length; i++) {
dst.setByte(dstIndex + i, input.read());
}
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
return this;
}
@Override
public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
try {
input.read(dst, dstIndex, length);
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
return this;
}
@Override
public ByteBuf getBytes(int index, ByteBuffer dst) {
try {
dst.put(ByteStreams.toByteArray(input));
} catch (IOException e) {
throw new RuntimeException("Cannot read input.", e);
}
return this;
}
@Override
public ByteBuf getBytes(int index, OutputStream dst, int length) throws IOException {
ByteStreams.copy(ByteStreams.limit(input, length), dst);
return this;
}
@Override
public int getBytes(int index, GatheringByteChannel out, int length) throws IOException {
byte[] data = ByteStreams.toByteArray(ByteStreams.limit(input, length));
out.write(ByteBuffer.wrap(data));
return data.length;
}
@Override
public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) {
byte[] buffer = new byte[length];
src.getBytes(srcIndex, buffer);
try {
output.write(buffer);
return this;
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
try {
output.write(src, srcIndex, length);
return this;
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
public ByteBuf setBytes(int index, ByteBuffer src) {
try {
WritableByteChannel channel = Channels.newChannel(output);
channel.write(src);
return this;
} catch (IOException e) {
throw new RuntimeException("Cannot write output.", e);
}
}
@Override
public int setBytes(int index, InputStream in, int length) throws IOException {
InputStream limit = ByteStreams.limit(in, length);
ByteStreams.copy(limit, output);
return length - limit.available();
}
@Override
public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(length);
WritableByteChannel channel = Channels.newChannel(output);
int count = in.read(buffer);
channel.write(buffer);
return count;
}
@Override
public ByteBuf copy(int index, int length) {
throw new UnsupportedOperationException("Cannot seek in input stream.");
}
@Override
public int nioBufferCount() {
return 0;
}
@Override
public ByteBuffer nioBuffer(int paramInt1, int paramInt2) {
throw new UnsupportedOperationException();
}
@Override
public ByteBuffer internalNioBuffer(int paramInt1, int paramInt2) {
return null;
}
@Override
public ByteBuffer[] nioBuffers(int paramInt1, int paramInt2) {
return null;
}
@Override
public boolean hasArray() {
return false;
}
@Override
public byte[] array() {
return null;
}
@Override
public int arrayOffset() {
return 0;
}
@Override
public boolean hasMemoryAddress() {
return false;
}
@Override
public long memoryAddress() {
return 0;
}
@Override
public ByteBuf retain(int paramInt) {
return this;
}
@Override
public ByteBuf retain() {
return this;
}
}
@@ -1,38 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import com.comphenix.protocol.compat.netty.WrappedChannel;
/**
* @author dmulloy2
*/
public class NettyChannel implements WrappedChannel {
private final Channel channel;
public NettyChannel(Channel channel) {
this.channel = channel;
}
@Override
public void writeAndFlush(Object packet) {
channel.writeAndFlush(packet);
}
}
@@ -1,932 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.internal.TypeParameterMatcher;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.ListIterator;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import net.sf.cglib.proxy.Factory;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.compat.netty.ChannelInjector;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
import com.comphenix.protocol.compat.netty.WrappedChannel;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.NetworkProcessor;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.netty.NettyNetworkMarker;
import com.comphenix.protocol.injector.netty.WirePacket;
import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
import com.comphenix.protocol.utility.MinecraftFields;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.google.common.base.Preconditions;
import com.google.common.collect.MapMaker;
/**
* Represents a channel injector.
* @author Kristian
*/
public class NettyChannelInjector extends ByteToMessageDecoder implements ChannelInjector {
public static final ReportType REPORT_CANNOT_INTERCEPT_SERVER_PACKET = new ReportType("Unable to intercept a written server packet.");
public static final ReportType REPORT_CANNOT_INTERCEPT_CLIENT_PACKET = new ReportType("Unable to intercept a read client packet.");
public static final ReportType REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD = new ReportType("Cannot execute code in channel thread.");
public static final ReportType REPORT_CANNOT_FIND_GET_VERSION = new ReportType("Cannot find getVersion() in NetworkMananger");
public static final ReportType REPORT_CANNOT_SEND_PACKET = new ReportType("Unable to send packet %s to %s");
/**
* Indicates that a packet has bypassed packet listeners.
*/
private static final PacketEvent BYPASSED_PACKET = new PacketEvent(NettyChannelInjector.class);
// The login packet
private static Class<?> PACKET_LOGIN_CLIENT = null;
private static FieldAccessor LOGIN_GAME_PROFILE = null;
// Saved accessors
private static MethodAccessor DECODE_BUFFER;
private static MethodAccessor ENCODE_BUFFER;
private static FieldAccessor ENCODER_TYPE_MATCHER;
// For retrieving the protocol
private static FieldAccessor PROTOCOL_ACCESSOR;
// For retrieving the protocol version
private static MethodAccessor PROTOCOL_VERSION;
// The factory that created this injector
private NettyInjectionFactory factory;
// The player, or temporary player
private Player player;
private Player updated;
private String playerName;
// The player connection
private Object playerConnection;
// The current network manager and channel
private final Object networkManager;
private final Channel originalChannel;
private VolatileField channelField;
// Known network markers
private ConcurrentMap<Object, NetworkMarker> packetMarker = new MapMaker().weakKeys().makeMap();
/**
* Indicate that this packet has been processed by event listeners.
* <p>
* This must never be set outside the channel pipeline's thread.
*/
private PacketEvent currentEvent;
/**
* A packet event that should be processed by the write method.
*/
private PacketEvent finalEvent;
/**
* A flag set by the main thread to indiciate that a packet should not be processed.
*/
private final ThreadLocal<Boolean> scheduleProcessPackets = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return true;
};
};
// Other handlers
private ByteToMessageDecoder vanillaDecoder;
private MessageToByteEncoder<Object> vanillaEncoder;
private Deque<PacketEvent> finishQueue = new ArrayDeque<PacketEvent>();
// The channel listener
private ChannelListener channelListener;
// Processing network markers
private NetworkProcessor processor;
// Closed
private boolean injected;
private boolean closed;
/**
* Construct a new channel injector.
* @param player - the current player, or temporary player.
* @param networkManager - its network manager.
* @param channel - its channel.
* @param channelListener - a listener.
* @param factory - the factory that created this injector
*/
public NettyChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener, NettyInjectionFactory factory) {
this.player = Preconditions.checkNotNull(player, "player cannot be NULL");
this.networkManager = Preconditions.checkNotNull(networkManager, "networkMananger cannot be NULL");
this.originalChannel = Preconditions.checkNotNull(channel, "channel cannot be NULL");
this.channelListener = Preconditions.checkNotNull(channelListener, "channelListener cannot be NULL");
this.factory = Preconditions.checkNotNull(factory, "factory cannot be NULL");
this.processor = new NetworkProcessor(ProtocolLibrary.getErrorReporter());
// Get the channel field
this.channelField = new VolatileField(FuzzyReflection.fromObject(networkManager, true).getFieldByType("channel", Channel.class),
networkManager, true);
}
/**
* Get the version of the current protocol.
* @return The version.
*/
@Override
public int getProtocolVersion() {
MethodAccessor accessor = PROTOCOL_VERSION;
if (accessor == null) {
try {
accessor = Accessors.getMethodAccessor(networkManager.getClass(), "getVersion");
} catch (Throwable ex) {
}
}
if (accessor != null) {
return (Integer) accessor.invoke(networkManager);
} else {
return MinecraftProtocolVersion.getCurrentVersion();
}
}
@Override
@SuppressWarnings("unchecked")
public boolean inject() {
synchronized (networkManager) {
if (closed)
return false;
if (originalChannel instanceof Factory)
return false;
if (!originalChannel.isActive())
return false;
// Main thread? We should synchronize with the channel thread, otherwise we might see a
// pipeline with only some of the handlers removed
if (Bukkit.isPrimaryThread()) {
// Just like in the close() method, we'll avoid blocking the main thread
executeInChannelThread(new Runnable() {
@Override
public void run() {
inject();
}
});
return false; // We don't know
}
// Don't inject the same channel twice
if (findChannelHandler(originalChannel, NettyChannelInjector.class) != null) {
return false;
}
// Get the vanilla decoder, so we don't have to replicate the work
vanillaDecoder = (ByteToMessageDecoder) originalChannel.pipeline().get("decoder");
vanillaEncoder = (MessageToByteEncoder<Object>) originalChannel.pipeline().get("encoder");
if (vanillaDecoder == null)
throw new IllegalArgumentException("Unable to find vanilla decoder in " + originalChannel.pipeline() );
if (vanillaEncoder == null)
throw new IllegalArgumentException("Unable to find vanilla encoder in " + originalChannel.pipeline() );
patchEncoder(vanillaEncoder);
if (DECODE_BUFFER == null)
DECODE_BUFFER = Accessors.getMethodAccessor(vanillaDecoder.getClass(),
"decode", ChannelHandlerContext.class, ByteBuf.class, List.class);
if (ENCODE_BUFFER == null)
ENCODE_BUFFER = Accessors.getMethodAccessor(vanillaEncoder.getClass(),
"encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
// Intercept sent packets
MessageToByteEncoder<Object> protocolEncoder = new MessageToByteEncoder<Object>() {
@Override
protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception {
if (packet instanceof WirePacket) {
// Special case for wire format
NettyChannelInjector.this.encodeWirePacket((WirePacket) packet, new NettyByteBuf(output));
} else {
NettyChannelInjector.this.encode(ctx, packet, output);
}
}
@Override
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
super.write(ctx, packet, promise);
NettyChannelInjector.this.finalWrite(ctx, packet, promise);
}
};
// Intercept recieved packets
ChannelInboundHandlerAdapter finishHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Execute context first
ctx.fireChannelRead(msg);
NettyChannelInjector.this.finishRead(ctx, msg);
}
};
// Insert our handlers - note that we effectively replace the vanilla encoder/decoder
originalChannel.pipeline().addBefore("decoder", "protocol_lib_decoder", this);
originalChannel.pipeline().addBefore("protocol_lib_decoder", "protocol_lib_finish", finishHandler);
originalChannel.pipeline().addAfter("encoder", "protocol_lib_encoder", protocolEncoder);
// Intercept all write methods
channelField.setValue(new NettyChannelProxy(originalChannel, MinecraftReflection.getPacketClass()) {
// Compatibility with Spigot 1.8
private final NettyPipelineProxy pipelineProxy = new NettyPipelineProxy(originalChannel.pipeline(), this) {
@Override
public ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) {
// Correct the position of the decoder
if ("decoder".equals(baseName)) {
if (super.get("protocol_lib_decoder") != null && guessCompression(handler)) {
super.addBefore("protocol_lib_decoder", name, handler);
return this;
}
}
return super.addBefore(baseName, name, handler);
}
};
@Override
public ChannelPipeline pipeline() {
return pipelineProxy;
}
@Override
protected <T> Callable<T> onMessageScheduled(final Callable<T> callable, FieldAccessor packetAccessor) {
final PacketEvent event = handleScheduled(callable, packetAccessor);
// Handle cancelled events
if (event != null && event.isCancelled())
return null;
return new Callable<T>() {
@Override
public T call() throws Exception {
T result = null;
// This field must only be updated in the pipeline thread
currentEvent = event;
result = callable.call();
currentEvent = null;
return result;
}
};
}
@Override
protected Runnable onMessageScheduled(final Runnable runnable, FieldAccessor packetAccessor) {
final PacketEvent event = handleScheduled(runnable, packetAccessor);
// Handle cancelled events
if (event != null && event.isCancelled())
return null;
return new Runnable() {
@Override
public void run() {
currentEvent = event;
runnable.run();
currentEvent = null;
}
};
}
protected PacketEvent handleScheduled(Object instance, FieldAccessor accessor) {
// Let the filters handle this packet
Object original = accessor.get(instance);
// See if we've been instructed not to process packets
if (!scheduleProcessPackets.get()) {
NetworkMarker marker = getMarker(original);
if (marker != null) {
PacketEvent result = new PacketEvent(NettyChannelInjector.class);
result.setNetworkMarker(marker);
return result;
} else {
return BYPASSED_PACKET;
}
}
PacketEvent event = processSending(original);
if (event != null && !event.isCancelled()) {
Object changed = event.getPacket().getHandle();
// Change packet to be scheduled
if (original != changed)
accessor.set(instance, changed);
};
return event != null ? event : BYPASSED_PACKET;
}
});
injected = true;
return true;
}
}
/**
* Determine if the given object is a compressor or decompressor.
* @param handler - object to test.
* @return TRUE if it is, FALSE if not or unknown.
*/
private boolean guessCompression(ChannelHandler handler) {
String className = handler != null ? handler.getClass().getCanonicalName() : "";
return className.contains("Compressor") || className.contains("Decompressor");
}
/**
* Process a given message on the packet listeners.
* @param message - the message/packet.
* @return The resulting message/packet.
*/
private PacketEvent processSending(Object message) {
return channelListener.onPacketSending(NettyChannelInjector.this, message, getMarker(message));
}
/**
* This method patches the encoder so that it skips already created packets.
* @param encoder - the encoder to patch.
*/
private void patchEncoder(MessageToByteEncoder<Object> encoder) {
if (ENCODER_TYPE_MATCHER == null) {
ENCODER_TYPE_MATCHER = Accessors.getFieldAccessor(encoder.getClass(), "matcher", true);
}
ENCODER_TYPE_MATCHER.set(encoder, TypeParameterMatcher.get(MinecraftReflection.getPacketClass()));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (channelListener.isDebug())
cause.printStackTrace();
super.exceptionCaught(ctx, cause);
}
protected void encodeWirePacket(WirePacket packet, WrappedByteBuf output) throws Exception {
packet.writeId(output);
packet.writeBytes(output);
}
/**
* Encode a packet to a byte buffer, taking over for the standard Minecraft encoder.
* @param ctx - the current context.
* @param packet - the packet to encode to a byte array.
* @param output - the output byte array.
* @throws Exception If anything went wrong.
*/
protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception {
NetworkMarker marker = null;
PacketEvent event = currentEvent;
try {
// Skip every kind of non-filtered packet
if (!scheduleProcessPackets.get()) {
return;
}
// This packet has not been seen by the main thread
if (event == null) {
Class<?> clazz = packet.getClass();
// Schedule the transmission on the main thread instead
if (channelListener.hasMainThreadListener(clazz)) {
// Delay the packet
scheduleMainThread(packet);
packet = null;
} else {
event = processSending(packet);
// Handle the output
if (event != null) {
packet = !event.isCancelled() ? event.getPacket().getHandle() : null;
}
}
}
if (event != null) {
// Retrieve marker without accidentally constructing it
marker = NetworkMarker.getNetworkMarker(event);
}
// Process output handler
if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) {
ByteBuf packetBuffer = ctx.alloc().buffer();
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, packetBuffer);
// Let each handler prepare the actual output
byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer));
// Write the result
output.writeBytes(data);
packet = null;
// Sent listeners?
finalEvent = event;
return;
}
} catch (Exception e) {
channelListener.getReporter().reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_INTERCEPT_SERVER_PACKET).callerParam(packet).error(e).build());
} finally {
// Attempt to handle the packet nevertheless
if (packet != null) {
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, output);
finalEvent = event;
}
}
}
/**
* Invoked when a packet has been written to the channel.
* @param ctx - current context.
* @param packet - the packet that has been written.
* @param promise - a promise.
*/
protected void finalWrite(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) {
PacketEvent event = finalEvent;
if (event != null) {
// Necessary to prevent infinite loops
finalEvent = null;
currentEvent = null;
processor.invokePostEvent(event, NetworkMarker.getNetworkMarker(event));
}
}
private void scheduleMainThread(final Object packetCopy) {
// Don't use BukkitExecutors for this - it has a bit of overhead
Bukkit.getScheduler().scheduleSyncDelayedTask(factory.getPlugin(), new Runnable() {
@Override
public void run() {
invokeSendPacket(packetCopy);
}
});
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuffer, List<Object> packets) throws Exception {
byteBuffer.markReaderIndex();
DECODE_BUFFER.invoke(vanillaDecoder, ctx, byteBuffer, packets);
try {
// Reset queue
finishQueue.clear();
for (ListIterator<Object> it = packets.listIterator(); it.hasNext(); ) {
Object input = it.next();
Class<?> packetClass = input.getClass();
NetworkMarker marker = null;
// Special case!
handleLogin(packetClass, input);
if (channelListener.includeBuffer(packetClass)) {
byteBuffer.resetReaderIndex();
marker = new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, getBytes(byteBuffer));
}
PacketEvent output = channelListener.onPacketReceiving(this, input, marker);
// Handle packet changes
if (output != null) {
if (output.isCancelled()) {
it.remove();
continue;
} else if (output.getPacket().getHandle() != input) {
it.set(output.getPacket().getHandle());
}
finishQueue.addLast(output);
}
}
} catch (Exception e) {
channelListener.getReporter().reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_INTERCEPT_CLIENT_PACKET).callerParam(byteBuffer).error(e).build());
}
}
/**
* Invoked after our decoder.
* @param ctx - current context.
* @param msg - the current packet.
*/
protected void finishRead(ChannelHandlerContext ctx, Object msg) {
// Assume same order
PacketEvent event = finishQueue.pollFirst();
if (event != null) {
NetworkMarker marker = NetworkMarker.getNetworkMarker(event);
if (marker != null) {
processor.invokePostEvent(event, marker);
}
}
}
/**
* Invoked when we may need to handle the login packet.
* @param packetClass - the packet class.
* @param packet - the packet.
*/
protected void handleLogin(Class<?> packetClass, Object packet) {
Class<?> loginClass = PACKET_LOGIN_CLIENT;
FieldAccessor loginClient = LOGIN_GAME_PROFILE;
// Initialize packet class and login
if (loginClass == null) {
loginClass = PacketType.Login.Client.START.getPacketClass();
PACKET_LOGIN_CLIENT = loginClass;
}
if (loginClient == null) {
loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true);
LOGIN_GAME_PROFILE = loginClient;
}
// See if we are dealing with the login packet
if (loginClass.equals(packetClass)) {
// GameProfile profile = (GameProfile) loginClient.get(packet);
WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet));
// Save the channel injector
factory.cacheInjector(profile.getName(), this);
}
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
// See NetworkManager.channelActive(ChannelHandlerContext) for why
if (channelField != null) {
channelField.refreshValue();
}
}
/**
* Retrieve every byte in the given byte buffer.
* @param buffer - the buffer.
* @return The bytes.
*/
private byte[] getBytes(ByteBuf buffer) {
byte[] data = new byte[buffer.readableBytes()];
buffer.readBytes(data);
return data;
}
/**
* Disconnect the current player.
* @param message - the disconnect message, if possible.
*/
private void disconnect(String message) {
// If we're logging in, we can only close the channel
if (playerConnection == null || player instanceof Factory) {
originalChannel.disconnect();
} else {
// Call the disconnect method
try {
MinecraftMethods.getDisconnectMethod(playerConnection.getClass()).
invoke(playerConnection, message);
} catch (Exception e) {
throw new IllegalArgumentException("Unable to invoke disconnect method.", e);
}
}
}
@Override
public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) {
saveMarker(packet, marker);
try {
scheduleProcessPackets.set(filtered);
invokeSendPacket(packet);
} finally {
scheduleProcessPackets.set(true);
}
}
/**
* Invoke the sendPacket method in Minecraft.
* @param packet - the packet to send.
*/
private void invokeSendPacket(Object packet) {
// Attempt to send the packet with NetworkMarker.handle(), or the PlayerConnection if its active
try {
if (player instanceof Factory) {
MinecraftMethods.getNetworkManagerHandleMethod().invoke(networkManager, packet, new GenericFutureListener[0]);
} else {
MinecraftMethods.getSendPacketMethod().invoke(getPlayerConnection(), packet);
}
} catch (Throwable ex) {
ProtocolLibrary.getErrorReporter().reportWarning(factory.getPlugin(),
Report.newBuilder(REPORT_CANNOT_SEND_PACKET).messageParam(packet, playerName).error(ex).build());
}
}
@Override
public void recieveClientPacket(final Object packet) {
// TODO: Ensure the packet listeners are executed in the channel thread.
// Execute this in the channel thread
Runnable action = new Runnable() {
@Override
public void run() {
try {
MinecraftMethods.getNetworkManagerReadPacketMethod().invoke(networkManager, null, packet);
} catch (Exception e) {
// Inform the user
ProtocolLibrary.getErrorReporter().reportMinimal(factory.getPlugin(), "recieveClientPacket", e);
}
}
};
// Execute in the worker thread
if (originalChannel.eventLoop().inEventLoop()) {
action.run();
} else {
originalChannel.eventLoop().execute(action);
}
}
@Override
public Protocol getCurrentProtocol() {
if (PROTOCOL_ACCESSOR == null) {
PROTOCOL_ACCESSOR = Accessors.getFieldAccessor(
networkManager.getClass(), MinecraftReflection.getEnumProtocolClass(), true);
}
return Protocol.fromVanilla((Enum<?>) PROTOCOL_ACCESSOR.get(networkManager));
}
/**
* Retrieve the player connection of the current player.
* @return The player connection.
*/
private Object getPlayerConnection() {
if (playerConnection == null) {
playerConnection = MinecraftFields.getPlayerConnection(player);
}
return playerConnection;
}
@Override
public NetworkMarker getMarker(Object packet) {
return packetMarker.get(packet);
}
@Override
public void saveMarker(Object packet, NetworkMarker marker) {
if (marker != null) {
packetMarker.put(packet, marker);
}
}
@Override
public Player getPlayer() {
if (player == null && playerName != null) {
return Bukkit.getPlayer(playerName);
}
return player;
}
/**
* Set the player instance.
* @param player - current instance.
*/
@Override
public void setPlayer(Player player) {
this.player = player;
this.playerName = player.getName();
}
/**
* Set the updated player instance.
* @param updated - updated instance.
*/
@Override
public void setUpdatedPlayer(Player updated) {
this.updated = updated;
this.playerName = updated.getName();
}
@Override
public boolean isInjected() {
return injected;
}
/**
* Determine if this channel has been closed and cleaned up.
* @return TRUE if it has, FALSE otherwise.
*/
@Override
public boolean isClosed() {
return closed;
}
@Override
public void close() {
if (!closed) {
closed = true;
if (injected) {
channelField.revertValue();
// Calling remove() in the main thread will block the main thread, which may lead
// to a deadlock:
// http://pastebin.com/L3SBVKzp
//
// ProtocolLib executes this close() method through a PlayerQuitEvent in the main thread,
// which has implicitly aquired a lock on SimplePluginManager (see SimplePluginManager.callEvent(Event)).
// Unfortunately, the remove() method will schedule the removal on one of the Netty worker threads if
// it's called from a different thread, blocking until the removal has been confirmed.
//
// This is bad enough (Rule #1: Don't block the main thread), but the real trouble starts if the same
// worker thread happens to be handling a server ping connection when this removal task is scheduled.
// In that case, it may attempt to invoke an asynchronous ServerPingEvent (see PacketStatusListener)
// using SimplePluginManager.callEvent(). But, since this has already been locked by the main thread,
// we end up with a deadlock. The main thread is waiting for the worker thread to process the task, and
// the worker thread is waiting for the main thread to finish executing PlayerQuitEvent.
//
// TL;DR: Concurrency is hard.
executeInChannelThread(new Runnable() {
@Override
public void run() {
String[] handlers = new String[] {
"protocol_lib_decoder", "protocol_lib_finish", "protocol_lib_encoder"
};
for (String handler : handlers) {
try {
originalChannel.pipeline().remove(handler);
} catch (NoSuchElementException e) {
// Ignore
}
}
}
});
// Clear cache
factory.invalidate(player);
// Clear player instances
// Should help fix memory leaks
this.player = null;
this.updated = null;
}
}
}
/**
* Execute a specific command in the channel thread.
* <p>
* Exceptions are printed through the standard error reporter mechanism.
* @param command - the command to execute.
*/
private void executeInChannelThread(final Runnable command) {
originalChannel.eventLoop().execute(new Runnable() {
@Override
public void run() {
try {
command.run();
} catch (Exception e) {
ProtocolLibrary.getErrorReporter().reportDetailed(NettyChannelInjector.this,
Report.newBuilder(REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD).error(e).build());
}
}
});
}
/**
* Find the first channel handler that is assignable to a given type.
* @param channel - the channel.
* @param clazz - the type.
* @return The first handler, or NULL.
*/
public static ChannelHandler findChannelHandler(Channel channel, Class<?> clazz) {
for (Entry<String, ChannelHandler> entry : channel.pipeline()) {
if (clazz.isAssignableFrom(entry.getValue().getClass())) {
return entry.getValue();
}
}
return null;
}
/**
* Represents a socket injector that foreards to the current channel injector.
* @author Kristian
*/
public static class ChannelSocketInjector implements SocketInjector {
private final NettyChannelInjector injector;
public ChannelSocketInjector(NettyChannelInjector injector) {
this.injector = Preconditions.checkNotNull(injector, "injector cannot be NULL");
}
@Override
public Socket getSocket() throws IllegalAccessException {
return NettySocketAdapter.adapt((SocketChannel) injector.originalChannel);
}
@Override
public SocketAddress getAddress() throws IllegalAccessException {
return injector.originalChannel.remoteAddress();
}
@Override
public void disconnect(String message) throws InvocationTargetException {
injector.disconnect(message);
}
@Override
public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) throws InvocationTargetException {
injector.sendServerPacket(packet, marker, filtered);
}
@Override
public Player getPlayer() {
return injector.getPlayer();
}
@Override
public Player getUpdatedPlayer() {
return injector.updated;
}
@Override
public void transferState(SocketInjector delegate) {
// Do nothing
}
@Override
public void setUpdatedPlayer(Player updatedPlayer) {
injector.setPlayer(updatedPlayer);
}
public NettyChannelInjector getChannelInjector() {
return injector;
}
}
@Override
public WrappedChannel getChannel() {
return new NettyChannel(originalChannel);
}
}
@@ -1,334 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.buffer.ByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelProgressivePromise;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import java.lang.reflect.Field;
import java.net.SocketAddress;
import java.util.Map;
import java.util.concurrent.Callable;
import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.google.common.collect.Maps;
public abstract class NettyChannelProxy implements Channel {
// Mark that a certain object does not contain a message field
private static final FieldAccessor MARK_NO_MESSAGE = new FieldAccessor() {
@Override
public void set(Object instance, Object value) { }
@Override
public Object get(Object instance) { return null; }
@Override
public Field getField() { return null; };
};
// Looking up packets in inner classes
private static Map<Class<?>, FieldAccessor> MESSAGE_LOOKUP = Maps.newConcurrentMap();
// The underlying channel
protected Channel delegate;
protected Class<?> messageClass;
// Event loop proxy
private transient NettyEventLoopProxy loopProxy;
public NettyChannelProxy(Channel delegate, Class<?> messageClass) {
this.delegate = delegate;
this.messageClass = messageClass;
}
/**
* Invoked when a packet is scheduled for transmission in the event loop.
* @param <T> Type
* @param callable - callable to schedule for execution.
* @param packetAccessor - accessor for modifying the packet in the callable.
* @return The callable that will be scheduled, or NULL to cancel.
*/
protected abstract <T> Callable<T> onMessageScheduled(Callable<T> callable, FieldAccessor packetAccessor);
/**
* Invoked when a packet is scheduled for transmission in the event loop.
* @param runnable - the runnable that contains a packet to be scheduled.
* @param packetAccessor - accessor for modifying the packet in the runnable.
* @return The runnable that will be scheduled, or NULL to cancel.
*/
protected abstract Runnable onMessageScheduled(Runnable runnable, FieldAccessor packetAccessor);
@Override
public <T> Attribute<T> attr(AttributeKey<T> paramAttributeKey) {
return delegate.attr(paramAttributeKey);
}
@Override
public ChannelFuture bind(SocketAddress paramSocketAddress) {
return delegate.bind(paramSocketAddress);
}
@Override
public ChannelPipeline pipeline() {
return delegate.pipeline();
}
@Override
public ChannelFuture connect(SocketAddress paramSocketAddress) {
return delegate.connect(paramSocketAddress);
}
@Override
public ByteBufAllocator alloc() {
return delegate.alloc();
}
@Override
public ChannelPromise newPromise() {
return delegate.newPromise();
}
@Override
public EventLoop eventLoop() {
if (loopProxy == null) {
loopProxy = new NettyEventLoopProxy() {
@Override
protected EventLoop getDelegate() {
return delegate.eventLoop();
}
@Override
protected Runnable schedulingRunnable(final Runnable runnable) {
final FieldAccessor accessor = getMessageAccessor(runnable);
if (accessor != null) {
Runnable result = onMessageScheduled(runnable, accessor);;
return result != null ? result : getEmptyRunnable();
}
return runnable;
}
@Override
protected <T> Callable<T> schedulingCallable(Callable<T> callable) {
FieldAccessor accessor = getMessageAccessor(callable);
if (accessor != null) {
Callable<T> result = onMessageScheduled(callable, accessor);;
return result != null ? result : NettyEventLoopProxy.<T>getEmptyCallable();
}
return callable;
}
};
}
return loopProxy;
}
/**
* Retrieve a way to access the packet field of an object.
* @param value - the object.
* @return The packet field accessor, or NULL if not found.
*/
private FieldAccessor getMessageAccessor(Object value) {
Class<?> clazz = value.getClass();
FieldAccessor accessor = MESSAGE_LOOKUP.get(clazz);
if (accessor == null) {
try {
accessor = Accessors.getFieldAccessor(clazz, messageClass, true);
} catch (IllegalArgumentException e) {
accessor = MARK_NO_MESSAGE;
}
// Save the result
MESSAGE_LOOKUP.put(clazz, accessor);
}
return accessor != MARK_NO_MESSAGE ? accessor : null;
}
@Override
public ChannelFuture connect(SocketAddress paramSocketAddress1,
SocketAddress paramSocketAddress2) {
return delegate.connect(paramSocketAddress1, paramSocketAddress2);
}
@Override
public ChannelProgressivePromise newProgressivePromise() {
return delegate.newProgressivePromise();
}
@Override
public Channel parent() {
return delegate.parent();
}
@Override
public ChannelConfig config() {
return delegate.config();
}
@Override
public ChannelFuture newSucceededFuture() {
return delegate.newSucceededFuture();
}
@Override
public boolean isOpen() {
return delegate.isOpen();
}
@Override
public ChannelFuture disconnect() {
return delegate.disconnect();
}
@Override
public boolean isRegistered() {
return delegate.isRegistered();
}
@Override
public ChannelFuture newFailedFuture(Throwable paramThrowable) {
return delegate.newFailedFuture(paramThrowable);
}
@Override
public ChannelFuture close() {
return delegate.close();
}
@Override
public boolean isActive() {
return delegate.isActive();
}
@Override
@Deprecated
public ChannelFuture deregister() {
return delegate.deregister();
}
@Override
public ChannelPromise voidPromise() {
return delegate.voidPromise();
}
@Override
public ChannelMetadata metadata() {
return delegate.metadata();
}
@Override
public ChannelFuture bind(SocketAddress paramSocketAddress,
ChannelPromise paramChannelPromise) {
return delegate.bind(paramSocketAddress, paramChannelPromise);
}
@Override
public SocketAddress localAddress() {
return delegate.localAddress();
}
@Override
public SocketAddress remoteAddress() {
return delegate.remoteAddress();
}
@Override
public ChannelFuture connect(SocketAddress paramSocketAddress,
ChannelPromise paramChannelPromise) {
return delegate.connect(paramSocketAddress, paramChannelPromise);
}
@Override
public ChannelFuture closeFuture() {
return delegate.closeFuture();
}
@Override
public boolean isWritable() {
return delegate.isWritable();
}
@Override
public Channel flush() {
return delegate.flush();
}
@Override
public ChannelFuture connect(SocketAddress paramSocketAddress1,
SocketAddress paramSocketAddress2, ChannelPromise paramChannelPromise) {
return delegate.connect(paramSocketAddress1, paramSocketAddress2, paramChannelPromise);
}
@Override
public Channel read() {
return delegate.read();
}
@Override
public Unsafe unsafe() {
return delegate.unsafe();
}
@Override
public ChannelFuture disconnect(ChannelPromise paramChannelPromise) {
return delegate.disconnect(paramChannelPromise);
}
@Override
public ChannelFuture close(ChannelPromise paramChannelPromise) {
return delegate.close(paramChannelPromise);
}
@Override
@Deprecated
public ChannelFuture deregister(ChannelPromise paramChannelPromise) {
return delegate.deregister(paramChannelPromise);
}
@Override
public ChannelFuture write(Object paramObject) {
return delegate.write(paramObject);
}
@Override
public ChannelFuture write(Object paramObject, ChannelPromise paramChannelPromise) {
return delegate.write(paramObject, paramChannelPromise);
}
@Override
public ChannelFuture writeAndFlush(Object paramObject, ChannelPromise paramChannelPromise) {
return delegate.writeAndFlush(paramObject, paramChannelPromise);
}
@Override
public ChannelFuture writeAndFlush(Object paramObject) {
return delegate.writeAndFlush(paramObject);
}
@Override
public int compareTo(Channel o) {
return delegate.compareTo(o);
}
}
@@ -1,259 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise;
import io.netty.channel.EventLoop;
import io.netty.channel.EventLoopGroup;
import io.netty.util.concurrent.EventExecutor;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.ProgressivePromise;
import io.netty.util.concurrent.Promise;
import io.netty.util.concurrent.ScheduledFuture;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* An event loop proxy.
* @author Kristian.
*/
abstract class NettyEventLoopProxy implements EventLoop {
private static final Runnable EMPTY_RUNNABLE = new Runnable() {
@Override
public void run() {
// Do nothing
}
};
private static final Callable<?> EMPTY_CALLABLE = new Callable<Object>() {
@Override
public Object call() throws Exception {
return null;
};
};
/**
* Retrieve the underlying event loop.
* @return The event loop.
*/
protected abstract EventLoop getDelegate();
/**
* Retrieve a callable that does nothing but return NULL.
* @return The empty callable.
*/
@SuppressWarnings("unchecked")
public static <T> Callable<T> getEmptyCallable() {
return (Callable<T>) EMPTY_CALLABLE;
}
/**
* Retrieve a runnable that does nothing.
* @return A NO-OP runnable.
*/
public static Runnable getEmptyRunnable() {
return EMPTY_RUNNABLE;
}
/**
* Invoked when a runnable is being scheduled.
* @param runnable - the runnable that is scheduling.
* @return The runnable to schedule instead. Cannot be NULL.
*/
protected abstract Runnable schedulingRunnable(Runnable runnable);
/**
* Invoked when a callable is being scheduled.
* @param runnable - the callable that is scheduling.
* @return The callable to schedule instead. Cannot be NULL.
*/
protected abstract <T> Callable<T> schedulingCallable(Callable<T> callable);
@Override
public void execute(Runnable command) {
getDelegate().execute(schedulingRunnable(command));
}
@Override
public <T> Future<T> submit(Callable<T> action) {
return getDelegate().submit(schedulingCallable(action));
}
@Override
public <T> Future<T> submit(Runnable action, T arg1) {
return getDelegate().submit(schedulingRunnable(action), arg1);
}
@Override
public Future<?> submit(Runnable action) {
return getDelegate().submit(schedulingRunnable(action));
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> action, long arg1, TimeUnit arg2) {
return getDelegate().schedule(schedulingCallable(action), arg1, arg2);
}
@Override
public ScheduledFuture<?> schedule(Runnable action, long arg1, TimeUnit arg2) {
return getDelegate().schedule(schedulingRunnable(action), arg1, arg2);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable action, long arg1, long arg2, TimeUnit arg3) {
return getDelegate().scheduleAtFixedRate(schedulingRunnable(action), arg1, arg2, arg3);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable action, long arg1, long arg2, TimeUnit arg3) {
return getDelegate().scheduleWithFixedDelay(schedulingRunnable(action), arg1, arg2, arg3);
}
// Boiler plate:
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return getDelegate().awaitTermination(timeout, unit);
}
@Override
public boolean inEventLoop() {
return getDelegate().inEventLoop();
}
@Override
public boolean inEventLoop(Thread arg0) {
return getDelegate().inEventLoop(arg0);
}
@Override
public boolean isShutdown() {
return getDelegate().isShutdown();
}
@Override
public boolean isTerminated() {
return getDelegate().isTerminated();
}
@Override
public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return getDelegate().invokeAll(tasks);
}
@Override
public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException {
return getDelegate().invokeAll(tasks, timeout, unit);
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException,
ExecutionException {
return getDelegate().invokeAny(tasks);
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return getDelegate().invokeAny(tasks, timeout, unit);
}
@Override
public boolean isShuttingDown() {
return getDelegate().isShuttingDown();
}
@Override
public Iterator<EventExecutor> iterator() {
return getDelegate().iterator();
}
@Override
public <V> Future<V> newFailedFuture(Throwable arg0) {
return getDelegate().newFailedFuture(arg0);
}
@Override
public EventLoop next() {
return ((EventLoopGroup) getDelegate()).next();
}
@Override
public <V> ProgressivePromise<V> newProgressivePromise() {
return getDelegate().newProgressivePromise();
}
@Override
public <V> Promise<V> newPromise() {
return getDelegate().newPromise();
}
@Override
public <V> Future<V> newSucceededFuture(V arg0) {
return getDelegate().newSucceededFuture(arg0);
}
@Override
public EventLoopGroup parent() {
return getDelegate().parent();
}
@Override
public ChannelFuture register(Channel arg0, ChannelPromise arg1) {
return getDelegate().register(arg0, arg1);
}
@Override
public ChannelFuture register(Channel arg0) {
return getDelegate().register(arg0);
}
@Override
public Future<?> shutdownGracefully() {
return getDelegate().shutdownGracefully();
}
@Override
public Future<?> shutdownGracefully(long arg0, long arg1, TimeUnit arg2) {
return getDelegate().shutdownGracefully(arg0, arg1, arg2);
}
@Override
public Future<?> terminationFuture() {
return getDelegate().terminationFuture();
}
@Override
@Deprecated
public void shutdown() {
getDelegate().shutdown();
}
@Override
@Deprecated
public List<Runnable> shutdownNow() {
return getDelegate().shutdownNow();
}
}
@@ -1,239 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnull;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.compat.netty.independent.NettyChannelInjector.ChannelSocketInjector;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.netty.ClosedInjector;
import com.comphenix.protocol.injector.netty.Injector;
import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.MinecraftFields;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.MapMaker;
/**
* Represents an injector factory.
* <p>
* Note that the factory will return {@link ClosedInjector} when the factory is closed.
* @author Kristian
*/
public class NettyInjectionFactory {
// This should work as long as the injectors are, uh, injected
private final ConcurrentMap<Player, Injector> playerLookup = new MapMaker().weakKeys().weakValues().makeMap();
private final ConcurrentMap<String, Injector> nameLookup = new MapMaker().weakValues().makeMap();
// Whether or not the factory is closed
private volatile boolean closed;
// The current plugin
private final Plugin plugin;
public NettyInjectionFactory(Plugin plugin) {
this.plugin = plugin;
}
/**
* Retrieve the main plugin associated with this injection factory.
* @return The main plugin.
*/
public Plugin getPlugin() {
return plugin;
}
/**
* Construct or retrieve a channel injector from an existing Bukkit player.
* @param player - the existing Bukkit player.
* @param listener - the listener.
* @return A new injector, an existing injector associated with this player, or a closed injector.
*/
@Nonnull
public Injector fromPlayer(Player player, ChannelListener listener) {
if (closed)
return new ClosedInjector(player);
Injector injector = playerLookup.get(player);
// Find a temporary injector as well
if (injector == null)
injector = getTemporaryInjector(player);
if (injector != null && !injector.isClosed())
return injector;
Object networkManager = MinecraftFields.getNetworkManager(player);
// Must be a temporary Bukkit player
if (networkManager == null) {
return fromName(player.getName(), player);
}
Channel channel = FuzzyReflection.getFieldValue(networkManager, Channel.class, true);
// See if a channel has already been created
injector = (NettyChannelInjector) NettyChannelInjector.findChannelHandler(channel, NettyChannelInjector.class);
if (injector != null) {
// Update the player instance
playerLookup.remove(injector.getPlayer());
injector.setPlayer(player);
} else {
injector = new NettyChannelInjector(player, networkManager, channel, listener, this);
}
// Cache injector and return
cacheInjector(player, injector);
return injector;
}
/**
* Retrieve a cached injector from a name.
* <p>
* The injector may be NULL if the plugin has been reloaded during a player login.
* @param name - the name.
* @param player - the player.
* @return The cached injector, or a closed injector if it could not be found.
*/
public Injector fromName(String name, Player player) {
if (!closed) {
Injector injector = nameLookup.get(name);
// We can only retrieve cached injectors
if (injector != null) {
// Update instance
injector.setUpdatedPlayer(player);
return injector;
}
}
return new ClosedInjector(player);
}
/**
* Construct a new channel injector for the given channel.
* @param channel - the channel.
* @param listener - the listener.
* @param playerFactory - a temporary player creator.
* @return The channel injector, or a closed injector.
*/
@Nonnull
public Injector fromChannel(Channel channel, ChannelListener listener, TemporaryPlayerFactory playerFactory) {
if (closed)
return new ClosedInjector(null);
Object networkManager = findNetworkManager(channel);
Player temporaryPlayer = playerFactory.createTemporaryPlayer(Bukkit.getServer());
NettyChannelInjector injector = new NettyChannelInjector(temporaryPlayer, networkManager, channel, listener, this);
// Initialize temporary player
TemporaryPlayerFactory.setInjectorInPlayer(temporaryPlayer, new ChannelSocketInjector(injector));
return injector;
}
/**
* Invalidate a cached injector.
* @param player - the associated player.
* @return The cached injector, or NULL if nothing was cached.
*/
public Injector invalidate(Player player) {
Injector injector = playerLookup.remove(player);
nameLookup.remove(player.getName());
return injector;
}
/**
* Cache an injector by player.
* @param player - the player.
* @param injector - the injector to cache.
* @return The previously cached injector.
*/
public Injector cacheInjector(Player player, Injector injector) {
nameLookup.put(player.getName(), injector);
return playerLookup.put(player, injector);
}
/**
* Cache an injector by name alone.
* @param name - the name to lookup.
* @param injector - the injector.
* @return The cached injector.
*/
public Injector cacheInjector(String name, Injector injector) {
return nameLookup.put(name, injector);
}
/**
* Retrieve the associated channel injector.
* @param player - the temporary player, or normal Bukkit player.
* @return The associated injector, or NULL if this is a Bukkit player.
*/
private NettyChannelInjector getTemporaryInjector(Player player) {
SocketInjector injector = TemporaryPlayerFactory.getInjectorFromPlayer(player);
if (injector != null) {
return ((ChannelSocketInjector) injector).getChannelInjector();
}
return null;
}
/**
* Find the network manager in a channel's pipeline.
* @param channel - the channel.
* @return The network manager.
*/
private Object findNetworkManager(Channel channel) {
// Find the network manager
Object networkManager = NettyChannelInjector.findChannelHandler(channel, MinecraftReflection.getNetworkManagerClass());
if (networkManager != null)
return networkManager;
throw new IllegalArgumentException("Unable to find NetworkManager in " + channel);
}
/**
* Determine if the factory is closed.
* <p>
* If it is, all new injectors will be closed by default.
* @return TRUE if it is closed, FALSE otherwise.
*/
public boolean isClosed() {
return closed;
}
/**
* Close all injectors created by this factory, and cease the creation of new injections.
*/
public synchronized void close() {
if (!closed) {
closed = true;
// Close everything
for (Injector injector : playerLookup.values())
injector.close();
for (Injector injector : nameLookup.values())
injector.close();
}
}
}
@@ -1,371 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.util.concurrent.EventExecutorGroup;
import java.net.SocketAddress;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
/**
* A pipeline proxy.
* @author Kristian
*/
public class NettyPipelineProxy implements ChannelPipeline {
protected final ChannelPipeline pipeline;
protected final Channel channel;
public NettyPipelineProxy(ChannelPipeline pipeline, Channel channel) {
this.pipeline = pipeline;
this.channel = channel;
}
@Override
public ChannelPipeline addAfter(EventExecutorGroup arg0, String arg1, String arg2, ChannelHandler arg3) {
pipeline.addAfter(arg0, arg1, arg2, arg3);
return this;
}
@Override
public ChannelPipeline addAfter(String arg0, String arg1, ChannelHandler arg2) {
pipeline.addAfter(arg0, arg1, arg2);
return this;
}
@Override
public ChannelPipeline addBefore(EventExecutorGroup arg0, String arg1, String arg2, ChannelHandler arg3) {
pipeline.addBefore(arg0, arg1, arg2, arg3);
return this;
}
@Override
public ChannelPipeline addBefore(String arg0, String arg1, ChannelHandler arg2) {
pipeline.addBefore(arg0, arg1, arg2);
return this;
}
@Override
public ChannelPipeline addFirst(ChannelHandler... arg0) {
pipeline.addFirst(arg0);
return this;
}
@Override
public ChannelPipeline addFirst(EventExecutorGroup arg0, ChannelHandler... arg1) {
pipeline.addFirst(arg0, arg1);
return this;
}
@Override
public ChannelPipeline addFirst(EventExecutorGroup arg0, String arg1, ChannelHandler arg2) {
pipeline.addFirst(arg0, arg1, arg2);
return this;
}
@Override
public ChannelPipeline addFirst(String arg0, ChannelHandler arg1) {
pipeline.addFirst(arg0, arg1);
return this;
}
@Override
public ChannelPipeline addLast(ChannelHandler... arg0) {
pipeline.addLast(arg0);
return this;
}
@Override
public ChannelPipeline addLast(EventExecutorGroup arg0, ChannelHandler... arg1) {
pipeline.addLast(arg0, arg1);
return this;
}
@Override
public ChannelPipeline addLast(EventExecutorGroup arg0, String arg1, ChannelHandler arg2) {
pipeline.addLast(arg0, arg1, arg2);
return this;
}
@Override
public ChannelPipeline addLast(String arg0, ChannelHandler arg1) {
pipeline.addLast(arg0, arg1);
return this;
}
@Override
public ChannelFuture bind(SocketAddress arg0, ChannelPromise arg1) {
return pipeline.bind(arg0, arg1);
}
@Override
public ChannelFuture bind(SocketAddress arg0) {
return pipeline.bind(arg0);
}
@Override
public Channel channel() {
return channel;
}
@Override
public ChannelFuture close() {
return pipeline.close();
}
@Override
public ChannelFuture close(ChannelPromise arg0) {
return pipeline.close(arg0);
}
@Override
public ChannelFuture connect(SocketAddress arg0, ChannelPromise arg1) {
return pipeline.connect(arg0, arg1);
}
@Override
public ChannelFuture connect(SocketAddress arg0, SocketAddress arg1, ChannelPromise arg2) {
return pipeline.connect(arg0, arg1, arg2);
}
@Override
public ChannelFuture connect(SocketAddress arg0, SocketAddress arg1) {
return pipeline.connect(arg0, arg1);
}
@Override
public ChannelFuture connect(SocketAddress arg0) {
return pipeline.connect(arg0);
}
@Override
public ChannelHandlerContext context(ChannelHandler arg0) {
return pipeline.context(arg0);
}
@Override
public ChannelHandlerContext context(Class<? extends ChannelHandler> arg0) {
return pipeline.context(arg0);
}
@Override
public ChannelHandlerContext context(String arg0) {
return pipeline.context(arg0);
}
// We have to call the depreciated methods to properly implement the proxy
@Override
public ChannelFuture deregister() {
return pipeline.deregister();
}
@Override
public ChannelFuture deregister(ChannelPromise arg0) {
return pipeline.deregister(arg0);
}
@Override
public ChannelPipeline fireChannelUnregistered() {
pipeline.fireChannelUnregistered();
return this;
}
@Override
public ChannelFuture disconnect() {
return pipeline.disconnect();
}
@Override
public ChannelFuture disconnect(ChannelPromise arg0) {
return pipeline.disconnect(arg0);
}
@Override
public ChannelPipeline fireChannelActive() {
pipeline.fireChannelActive();
return this;
}
@Override
public ChannelPipeline fireChannelInactive() {
pipeline.fireChannelInactive();
return this;
}
@Override
public ChannelPipeline fireChannelRead(Object arg0) {
pipeline.fireChannelRead(arg0);
return this;
}
@Override
public ChannelPipeline fireChannelReadComplete() {
pipeline.fireChannelReadComplete();
return this;
}
@Override
public ChannelPipeline fireChannelRegistered() {
pipeline.fireChannelRegistered();
return this;
}
@Override
public ChannelPipeline fireChannelWritabilityChanged() {
pipeline.fireChannelWritabilityChanged();
return this;
}
@Override
public ChannelPipeline fireExceptionCaught(Throwable arg0) {
pipeline.fireExceptionCaught(arg0);
return this;
}
@Override
public ChannelPipeline fireUserEventTriggered(Object arg0) {
pipeline.fireUserEventTriggered(arg0);
return this;
}
@Override
public ChannelHandler first() {
return pipeline.first();
}
@Override
public ChannelHandlerContext firstContext() {
return pipeline.firstContext();
}
@Override
public ChannelPipeline flush() {
pipeline.flush();
return this;
}
@Override
public <T extends ChannelHandler> T get(Class<T> arg0) {
return pipeline.get(arg0);
}
@Override
public ChannelHandler get(String arg0) {
return pipeline.get(arg0);
}
@Override
public Iterator<Entry<String, ChannelHandler>> iterator() {
return pipeline.iterator();
}
@Override
public ChannelHandler last() {
return pipeline.last();
}
@Override
public ChannelHandlerContext lastContext() {
return pipeline.lastContext();
}
@Override
public List<String> names() {
return pipeline.names();
}
@Override
public ChannelPipeline read() {
pipeline.read();
return this;
}
@Override
public ChannelPipeline remove(ChannelHandler arg0) {
pipeline.remove(arg0);
return this;
}
@Override
public <T extends ChannelHandler> T remove(Class<T> arg0) {
return pipeline.remove(arg0);
}
@Override
public ChannelHandler remove(String arg0) {
return pipeline.remove(arg0);
}
@Override
public ChannelHandler removeFirst() {
return pipeline.removeFirst();
}
@Override
public ChannelHandler removeLast() {
return pipeline.removeLast();
}
@Override
public ChannelPipeline replace(ChannelHandler arg0, String arg1, ChannelHandler arg2) {
pipeline.replace(arg0, arg1, arg2);
return this;
}
@Override
public <T extends ChannelHandler> T replace(Class<T> arg0, String arg1, ChannelHandler arg2) {
return pipeline.replace(arg0, arg1, arg2);
}
@Override
public ChannelHandler replace(String arg0, String arg1, ChannelHandler arg2) {
return pipeline.replace(arg0, arg1, arg2);
}
@Override
public Map<String, ChannelHandler> toMap() {
return pipeline.toMap();
}
@Override
public ChannelFuture write(Object arg0, ChannelPromise arg1) {
return pipeline.write(arg0, arg1);
}
@Override
public ChannelFuture write(Object arg0) {
return pipeline.write(arg0);
}
@Override
public ChannelFuture writeAndFlush(Object arg0, ChannelPromise arg1) {
return pipeline.writeAndFlush(arg0, arg1);
}
@Override
public ChannelFuture writeAndFlush(Object arg0) {
return pipeline.writeAndFlush(arg0);
}
}
@@ -1,441 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.util.List;
import java.util.Set;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.compat.netty.ChannelInjector;
import com.comphenix.protocol.compat.netty.ProtocolInjector;
import com.comphenix.protocol.compat.netty.WrappedChannel;
import com.comphenix.protocol.concurrency.PacketTypeSet;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.ListenerOptions;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.netty.Injector;
import com.comphenix.protocol.injector.netty.NettyNetworkMarker;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
import com.comphenix.protocol.injector.spigot.AbstractPacketInjector;
import com.comphenix.protocol.injector.spigot.AbstractPlayerHandler;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Lists;
public class NettyProtocolInjector implements ProtocolInjector {
public static final ReportType REPORT_CANNOT_INJECT_INCOMING_CHANNEL = new ReportType("Unable to inject incoming channel %s.");
private volatile boolean injected;
private volatile boolean closed;
// The temporary player factory
private TemporaryPlayerFactory playerFactory = new TemporaryPlayerFactory();
private List<VolatileField> bootstrapFields = Lists.newArrayList();
// The channel injector factory
private NettyInjectionFactory injectionFactory;
// List of network managers
private volatile List<Object> networkManagers;
// Different sending filters
private PacketTypeSet sendingFilters = new PacketTypeSet();
private PacketTypeSet reveivedFilters = new PacketTypeSet();
// Packets that must be executed on the main thread
private PacketTypeSet mainThreadFilters = new PacketTypeSet();
// Which packets are buffered
private PacketTypeSet bufferedPackets = new PacketTypeSet();
private ListenerInvoker invoker;
// Handle errors
private ErrorReporter reporter;
private boolean debug;
public NettyProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter) {
this.injectionFactory = new NettyInjectionFactory(plugin);
this.invoker = invoker;
this.reporter = reporter;
}
@Override
public boolean isDebug() {
return debug;
}
/**
* Set whether or not the debug mode is enabled.
* @param debug - TRUE if it is, FALSE otherwise.
*/
@Override
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* Inject into the spigot connection class.
*/
@Override
@SuppressWarnings("unchecked")
public synchronized void inject() {
if (injected)
throw new IllegalStateException("Cannot inject twice.");
try {
FuzzyReflection fuzzyServer = FuzzyReflection.fromClass(MinecraftReflection.getMinecraftServerClass());
List<Method> serverConnectionMethods = fuzzyServer.getMethodListByParameters(MinecraftReflection.getServerConnectionClass(), new Class[] {});
// Get the server connection
Object server = fuzzyServer.getSingleton();
Object serverConnection = null;
for (Method method : serverConnectionMethods) {
try {
serverConnection = method.invoke(server);
// Continue until we get a server connection
if (serverConnection != null) {
break;
}
} catch (Exception e) {
// Try the next though
e.printStackTrace();
}
}
// Handle connected channels
final ChannelInboundHandler 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) {
injectionFactory.fromChannel(channel, NettyProtocolInjector.this, playerFactory).inject();
}
} catch (Exception e) {
reporter.reportDetailed(NettyProtocolInjector.this, Report.newBuilder(REPORT_CANNOT_INJECT_INCOMING_CHANNEL).messageParam(channel).error(e));
}
}
};
// This is executed before Minecraft's channel handler
final ChannelInboundHandler beginInitProtocol = new ChannelInitializer<Channel>() {
@Override
protected void initChannel(Channel channel) throws Exception {
// Our only job is to add init protocol
channel.pipeline().addLast(endInitProtocol);
}
};
// Add our handler to newly created channels
final ChannelHandler connectionHandler = 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);
}
};
// Get the current NetworkMananger list
networkManagers = (List<Object>) FuzzyReflection.fromObject(serverConnection, true).invokeMethod(null, "getNetworkManagers", List.class, serverConnection);
// Insert ProtocolLib's connection interceptor
bootstrapFields = getBootstrapFields(serverConnection);
for (VolatileField field : bootstrapFields) {
final List<Object> list = (List<Object>) field.getValue();
// We don't have to override this list
if (list == networkManagers) {
continue;
}
// Synchronize with each list before we attempt to replace them.
field.setValue(new NettyBootstrapList(list, connectionHandler));
}
injected = true;
} catch (Exception e) {
throw new RuntimeException("Unable to inject channel futures.", e);
}
}
@Override
public boolean hasListener(Class<?> packetClass) {
return reveivedFilters.contains(packetClass) || sendingFilters.contains(packetClass);
}
@Override
public boolean hasMainThreadListener(Class<?> packetClass) {
return mainThreadFilters.contains(packetClass);
}
@Override
public ErrorReporter getReporter() {
return reporter;
}
/**
* Inject our packet handling into a specific player.
* @param player Player to inject into
*/
public void injectPlayer(Player player) {
injectionFactory.fromPlayer(player, this).inject();
}
private List<VolatileField> getBootstrapFields(Object serverConnection) {
List<VolatileField> result = Lists.newArrayList();
// Find and (possibly) proxy every list
for (Field field : FuzzyReflection.fromObject(serverConnection, true).getFieldListByType(List.class)) {
VolatileField volatileField = new VolatileField(field, serverConnection, true).toSynchronized();
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>) volatileField.getValue();
if (list.size() == 0 || list.get(0) instanceof ChannelFuture) {
result.add(volatileField);
}
}
return result;
}
/**
* Clean up any remaning injections.
*/
@Override
public synchronized void close() {
if (!closed) {
closed = true;
for (VolatileField field : bootstrapFields) {
Object value = field.getValue();
// Undo the processed channels, if any
if (value instanceof NettyBootstrapList) {
((NettyBootstrapList) value).close();
}
field.revertValue();
}
// Uninject all the players
injectionFactory.close();
}
}
@Override
public PacketEvent onPacketSending(Injector injector, Object packet, NetworkMarker marker) {
Class<?> clazz = packet.getClass();
if (sendingFilters.contains(clazz) || marker != null) {
try {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetQueued(container, injector.getPlayer(), marker);
} catch (LinkageError e) {
// So far this has been seen when the jar is shared
System.err.println("[ProtocolLib] Encountered a LinkageError. Make sure you\'re not using this jar for multiple server instances!");
System.err.println("[ProtocolLib] If you\'re getting this error for other reasons, please report it!");
e.printStackTrace();
}
}
// Don't change anything
return null;
}
@Override
public PacketEvent onPacketReceiving(Injector injector, Object packet, NetworkMarker marker) {
Class<?> clazz = packet.getClass();
if (reveivedFilters.contains(clazz) || marker != null) {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetReceived(container, injector.getPlayer(), marker);
}
// Don't change anything
return null;
}
@Override
public boolean includeBuffer(Class<?> packetClass) {
return bufferedPackets.contains(packetClass);
}
/**
* Called to inform the event listeners of a queued packet.
* @param packet - the packet that is to be sent.
* @param receiver - the receiver of this packet.
* @return The packet event that was used.
*/
private PacketEvent packetQueued(PacketContainer packet, Player receiver, NetworkMarker marker) {
PacketEvent event = PacketEvent.fromServer(this, packet, marker, receiver);
invoker.invokePacketSending(event);
return event;
}
/**
* Called to inform the event listeners of a received packet.
* @param packet - the packet that has been receieved.
* @param sender - the client packet.
* @param marker - the network marker.
* @return The packet event that was used.
*/
private PacketEvent packetReceived(PacketContainer packet, Player sender, NetworkMarker marker) {
PacketEvent event = PacketEvent.fromClient(this, packet, marker, sender);
invoker.invokePacketRecieving(event);
return event;
}
// Server side
@Override
public PlayerInjectionHandler getPlayerInjector() {
return new AbstractPlayerHandler(sendingFilters) {
private ChannelListener listener = NettyProtocolInjector.this;
@Override
public int getProtocolVersion(Player player) {
return injectionFactory.fromPlayer(player, listener).getProtocolVersion();
}
@Override
public void updatePlayer(Player player) {
injectionFactory.fromPlayer(player, listener).inject();
}
@Override
public void injectPlayer(Player player, ConflictStrategy strategy) {
injectionFactory.fromPlayer(player, listener).inject();
}
@Override
public boolean uninjectPlayer(InetSocketAddress address) {
// Ignore this too
return true;
}
@Override
public void addPacketHandler(PacketType type, Set<ListenerOptions> options) {
if (options != null && !type.forceAsync() && !options.contains(ListenerOptions.ASYNC))
mainThreadFilters.addType(type);
super.addPacketHandler(type, options);
}
@Override
public void removePacketHandler(PacketType type) {
mainThreadFilters.removeType(type);
super.removePacketHandler(type);
}
@Override
public boolean uninjectPlayer(Player player) {
// Just let Netty clean this up
return true;
}
@Override
public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
injectionFactory.fromPlayer(receiver, listener).sendServerPacket(packet.getHandle(), marker, filters);
}
@Override
public boolean hasMainThreadListener(PacketType type) {
return mainThreadFilters.contains(type);
}
@Override
public void recieveClientPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
injectionFactory.fromPlayer(player, listener).recieveClientPacket(mcPacket);
}
@Override
public PacketEvent handlePacketRecieved(PacketContainer packet, InputStream input, byte[] buffered) {
// Ignore this
return null;
}
@Override
public void handleDisconnect(Player player) {
injectionFactory.fromPlayer(player, listener).close();
}
@Override
public WrappedChannel getChannel(Player player) {
Injector injector = injectionFactory.fromPlayer(player, listener);
if (injector instanceof ChannelInjector) {
return ((ChannelInjector) injector).getChannel();
}
return null;
}
};
}
/**
* Retrieve a view of this protocol injector as a packet injector.
* @return The packet injector.
*/
// Client side
@Override
public PacketInjector getPacketInjector() {
return new AbstractPacketInjector(reveivedFilters) {
@Override
public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) {
NetworkMarker marker = buffered != null ? new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, buffered) : null;
injectionFactory.fromPlayer(client, NettyProtocolInjector.this).saveMarker(packet.getHandle(), marker);
return packetReceived(packet, client, marker);
}
@Override
public void inputBuffersChanged(Set<PacketType> set) {
bufferedPackets = new PacketTypeSet(set);
}
};
}
}
@@ -1,104 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import java.util.Map;
import java.util.Map.Entry;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.google.common.collect.Maps;
/**
* @author dmulloy2
*/
public class NettyProtocolRegistry extends ProtocolRegistry {
@Override
protected synchronized void initialize() {
Object[] protocols = enumProtocol.getEnumConstants();
// ID to Packet class maps
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
Register result = new Register();
StructureModifier<Object> modifier = null;
// Iterate through the protocols
for (Object protocol : protocols) {
if (modifier == null)
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
for (Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
String direction = entry.getKey().toString();
if (direction.contains("CLIENTBOUND")) { // Sent by Server
serverMaps.put(protocol, entry.getValue());
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
clientMaps.put(protocol, entry.getValue());
}
}
}
// Maps we have to occationally check have changed
for (Map<Integer, Class<?>> map : serverMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (Map<Integer, Class<?>> map : clientMaps.values()) {
result.containers.add(new MapContainer(map));
}
for (int i = 0; i < protocols.length; i++) {
Object protocol = protocols[i];
Enum<?> enumProtocol = (Enum<?>) protocol;
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
// Associate known types
if (serverMaps.containsKey(protocol))
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
if (clientMaps.containsKey(protocol))
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
}
// Exchange (thread safe, as we have only one writer)
this.register = result;
}
@Override
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
try {
register.typeToClass.put(type, entry.getValue());
if (sender == Sender.SERVER)
register.serverPackets.add(type);
if (sender == Sender.CLIENT)
register.clientPackets.add(type);
} catch (IllegalArgumentException ex) {
// Sometimes this happens with fake packets, just ignore it
}
}
}
}
@@ -1,265 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.independent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.socket.SocketChannel;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
/**
* This class wraps a Netty {@link Channel} in a {@link Socket}. It overrides
* all methods in {@link Socket} to ensure that calls are not mistakingly made
* to the unsupported super socket. All operations that can be sanely applied to
* a {@link Channel} are implemented here. Those which cannot will throw an
* {@link UnsupportedOperationException}.
*/
// Thanks MD5. :)
public class NettySocketAdapter extends Socket {
private final SocketChannel ch;
private NettySocketAdapter(SocketChannel ch) {
this.ch = ch;
}
public static NettySocketAdapter adapt(SocketChannel ch) {
return new NettySocketAdapter(ch);
}
@Override
public void bind(SocketAddress bindpoint) throws IOException {
ch.bind(bindpoint).syncUninterruptibly();
}
@Override
public synchronized void close() throws IOException {
ch.close().syncUninterruptibly();
}
@Override
public void connect(SocketAddress endpoint) throws IOException {
ch.connect(endpoint).syncUninterruptibly();
}
@Override
public void connect(SocketAddress endpoint, int timeout) throws IOException {
ch.config().setConnectTimeoutMillis(timeout);
ch.connect(endpoint).syncUninterruptibly();
}
@Override
public boolean equals(Object obj) {
return obj instanceof NettySocketAdapter && ch.equals(((NettySocketAdapter) obj).ch);
}
@Override
public java.nio.channels.SocketChannel getChannel() {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public InetAddress getInetAddress() {
return ch.remoteAddress().getAddress();
}
@Override
public InputStream getInputStream() throws IOException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public boolean getKeepAlive() throws SocketException {
return ch.config().getOption(ChannelOption.SO_KEEPALIVE);
}
@Override
public InetAddress getLocalAddress() {
return ch.localAddress().getAddress();
}
@Override
public int getLocalPort() {
return ch.localAddress().getPort();
}
@Override
public SocketAddress getLocalSocketAddress() {
return ch.localAddress();
}
@Override
public boolean getOOBInline() throws SocketException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public int getPort() {
return ch.remoteAddress().getPort();
}
@Override
public synchronized int getReceiveBufferSize() throws SocketException {
return ch.config().getOption(ChannelOption.SO_RCVBUF);
}
@Override
public SocketAddress getRemoteSocketAddress() {
return ch.remoteAddress();
}
@Override
public boolean getReuseAddress() throws SocketException {
return ch.config().getOption(ChannelOption.SO_REUSEADDR);
}
@Override
public synchronized int getSendBufferSize() throws SocketException {
return ch.config().getOption(ChannelOption.SO_SNDBUF);
}
@Override
public int getSoLinger() throws SocketException {
return ch.config().getOption(ChannelOption.SO_LINGER);
}
@Override
public synchronized int getSoTimeout() throws SocketException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public boolean getTcpNoDelay() throws SocketException {
return ch.config().getOption(ChannelOption.TCP_NODELAY);
}
@Override
public int getTrafficClass() throws SocketException {
return ch.config().getOption(ChannelOption.IP_TOS);
}
@Override
public int hashCode() {
return ch.hashCode();
}
@Override
public boolean isBound() {
return ch.localAddress() != null;
}
@Override
public boolean isClosed() {
return !ch.isOpen();
}
@Override
public boolean isConnected() {
return ch.isActive();
}
@Override
public boolean isInputShutdown() {
return ch.isInputShutdown();
}
@Override
public boolean isOutputShutdown() {
return ch.isOutputShutdown();
}
@Override
public void sendUrgentData(int data) throws IOException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public void setKeepAlive(boolean on) throws SocketException {
ch.config().setOption(ChannelOption.SO_KEEPALIVE, on);
}
@Override
public void setOOBInline(boolean on) throws SocketException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public synchronized void setReceiveBufferSize(int size) throws SocketException {
ch.config().setOption(ChannelOption.SO_RCVBUF, size);
}
@Override
public void setReuseAddress(boolean on) throws SocketException {
ch.config().setOption(ChannelOption.SO_REUSEADDR, on);
}
@Override
public synchronized void setSendBufferSize(int size) throws SocketException {
ch.config().setOption(ChannelOption.SO_SNDBUF, size);
}
@Override
public void setSoLinger(boolean on, int linger) throws SocketException {
ch.config().setOption(ChannelOption.SO_LINGER, linger);
}
@Override
public synchronized void setSoTimeout(int timeout) throws SocketException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public void setTcpNoDelay(boolean on) throws SocketException {
ch.config().setOption(ChannelOption.TCP_NODELAY, on);
}
@Override
public void setTrafficClass(int tc) throws SocketException {
ch.config().setOption(ChannelOption.IP_TOS, tc);
}
@Override
public void shutdownInput() throws IOException {
throw new UnsupportedOperationException("Operation not supported on Channel wrapper.");
}
@Override
public void shutdownOutput() throws IOException {
ch.shutdownOutput().syncUninterruptibly();
}
@Override
public String toString() {
return ch.toString();
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -23,9 +23,9 @@ import java.util.NavigableMap;
import java.util.Set;
import java.util.TreeMap;
import com.comphenix.protocol.compat.guava.Guava;
import com.google.common.base.Objects;
import com.google.common.collect.Range;
import com.google.common.collect.Ranges;
/**
* Represents a generic store of intervals and associated values. No two intervals
@@ -68,7 +68,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
@Override
public Range<TKey> getKey() {
return Guava.closedRange(left.key, right.key);
return Ranges.closed(left.key, right.key);
}
@Override
@@ -130,7 +130,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
this.state = state;
this.key = key;
this.value = value;
}
}
}
// To quickly look up ranges we'll index them by endpoints
@@ -140,7 +140,6 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
* Removes every interval that intersects with the given range.
* @param lowerBound - lowest value to remove.
* @param upperBound - highest value to remove.
* @return Intervals that were removed
*/
public Set<Entry> remove(TKey lowerBound, TKey upperBound) {
return remove(lowerBound, upperBound, false);
@@ -151,13 +150,12 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
* @param lowerBound - lowest value to remove.
* @param upperBound - highest value to remove.
* @param preserveDifference - whether or not to preserve the intervals that are partially outside.
* @return Intervals that were removed
*/
public Set<Entry> remove(TKey lowerBound, TKey upperBound, boolean preserveDifference) {
checkBounds(lowerBound, upperBound);
NavigableMap<TKey, EndPoint> range = bounds.subMap(lowerBound, true, upperBound, true);
EndPoint first = getNextEndPoint(lowerBound, true);
EndPoint first = getNextEndPoint(lowerBound, true);
EndPoint last = getPreviousEndPoint(upperBound, true);
// Used while resizing intervals
@@ -183,7 +181,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
if (next != null) {
removed.add(getEntry(last, next));
}
}
}
// Now remove both ranges
@@ -255,7 +253,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
/**
* Associates a given interval of keys with a certain value. Any previous
* association will be overwritten in the given interval.
* association will be overwritten in the given interval.
* <p>
* Overlapping intervals are not permitted. A key can only be associated with a single value.
*
@@ -264,7 +262,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
* @param value - the value, or NULL to reset this range.
*/
public void put(TKey lowerBound, TKey upperBound, TValue value) {
// While we don't permit overlapping intervals, we'll still allow overwriting existing intervals.
// While we don't permit overlapping intervals, we'll still allow overwriting existing intervals.
remove(lowerBound, upperBound, true);
invokeEntryAdded(putUnsafe(lowerBound, upperBound, value));
}
@@ -425,7 +423,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
if (point != null) {
Map.Entry<TKey, EndPoint> previous = bounds.floorEntry(inclusive ? point : decrementKey(point));
if (previous != null)
if (previous != null)
return previous.getValue();
}
return null;
@@ -441,7 +439,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
if (point != null) {
Map.Entry<TKey, EndPoint> next = bounds.ceilingEntry(inclusive ? point : incrementKey(point));
if (next != null)
if (next != null)
return next.getValue();
}
return null;
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -48,8 +48,6 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Retrieve a cache loader that will always throw an exception.
* @param <TKey> Type of the key
* @param <TValue> Type of the value
* @return An invalid cache loader.
*/
public static <TKey, TValue> CacheLoader<TKey, TValue> newInvalidCacheLoader() {
@@ -85,8 +83,6 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Initialize a new map.
* @param <TKey> Type of the key
* @param <TValue> Type of the value
* @return The created map.
*/
public static <TKey, TValue> BlockingHashMap<TKey, TValue> create() {
@@ -95,7 +91,7 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Waits until a value has been associated with the given key, and then retrieves that value.
* @param key - the key whose associated value is to be returned
* @param key - the key whose associated value is to be returned
* @return The value to which the specified key is mapped.
* @throws InterruptedException If the current thread got interrupted while waiting.
*/
@@ -122,7 +118,7 @@ public class BlockingHashMap<TKey, TValue> {
/**
* Waits until a value has been associated with the given key, and then retrieves that value.
* @param key - the key whose associated value is to be returned
* @param key - the key whose associated value is to be returned
* @param timeout - the amount of time to wait until an association has been made.
* @param unit - unit of timeout.
* @return The value to which the specified key is mapped, or NULL if the timeout elapsed.
@@ -137,7 +133,7 @@ public class BlockingHashMap<TKey, TValue> {
* <p>
* If timeout is zero, this method will return immediately if it can't find an socket injector.
*
* @param key - the key whose associated value is to be returned
* @param key - the key whose associated value is to be returned
* @param timeout - the amount of time to wait until an association has been made.
* @param unit - unit of timeout.
* @param ignoreInterrupted - TRUE if we should ignore the thread being interrupted, FALSE otherwise.
@@ -6,11 +6,12 @@ import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.comphenix.protocol.utility.SafeCacheBuilder;
import com.comphenix.protocol.utility.Util;
import com.google.common.base.Function;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.RemovalListener;
@@ -69,7 +70,6 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
/**
* Construct a new concurrent player map that uses each player's address as key.
* @param <T> Parameter type
* @return Concurrent player map.
*/
public static <T> ConcurrentPlayerMap<T> usingAddress() {
@@ -78,7 +78,6 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
/**
* Construct a new concurrent player map that uses each player's name as key.
* @param <T> Parameter type
* @return Concurrent player map.
*/
public static <T> ConcurrentPlayerMap<T> usingName() {
@@ -166,7 +165,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
* @return The player with the given key, or NULL if not found.
*/
protected Player findOnlinePlayer(Object key) {
for (Player player : Util.getOnlinePlayers()) {
for (Player player : Bukkit.getOnlinePlayers()) {
if (key.equals(keyMethod.apply(player))) {
return player;
}
@@ -178,6 +177,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
* Lookup a player by key in the cache, optionally searching every online player.
* @param key - the key of the player we are locating.
* @return The player, or NULL if not found.
* @throws ExecutionException
*/
protected Player lookupPlayer(Object key) {
try {
@@ -293,7 +293,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
private Iterator<Entry<Player, TValue>> entryIterator() {
// Skip entries with stale data
final Iterator<Entry<Object, TValue>> source = valueLookup.entrySet().iterator();
final AbstractIterator<Entry<Player,TValue>> filtered =
final AbstractIterator<Entry<Player,TValue>> filtered =
new AbstractIterator<Entry<Player,TValue>>() {
@Override
protected Entry<Player, TValue> computeNext() {
@@ -315,15 +315,12 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
// We can't return AbstractIterator directly, as it doesn't permitt the remove() method
return new Iterator<Entry<Player, TValue>>() {
@Override
public boolean hasNext() {
return filtered.hasNext();
}
@Override
public Entry<Player, TValue> next() {
return filtered.next();
}
@Override
public void remove() {
source.remove();
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -25,7 +25,7 @@ import java.util.Set;
/**
* Represents a very quick integer set that uses a lookup table to store membership.
* <p>
* This class is intentionally missing a size method.
* This class is intentionally missing a size method.
* @author Kristian
*/
public class IntegerSet {
@@ -67,7 +67,7 @@ public class IntegerSet {
/**
* Add the given element to the set, or do nothing if it already exists.
* @param element - element to add.
* @throws ArrayIndexOutOfBoundsException If the given element is not in the range [0, count).
* @throws OutOfBoundsException If the given element is not in the range [0, count).
*/
public void add(int element) {
array[element] = true;
@@ -65,7 +65,7 @@ public class PacketTypeSet {
/**
* Remove the given types from the set.
* @param types Types to remove
* @param type - the types to remove.
*/
public synchronized void removeAll(Iterable<? extends PacketType> types) {
for (PacketType type : types) {
@@ -101,7 +101,7 @@ public class PacketTypeSet {
}
/**
* Determine if the type of a packet is in the current set.
* Determine if the type of a packet is in the current set.
* @param packet - the packet.
* @return TRUE if it is, FALSE otherwise.
*/
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -35,7 +35,6 @@ import org.apache.commons.lang.builder.ToStringStyle;
import org.bukkit.Bukkit;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.collections.ExpireHashMap;
import com.comphenix.protocol.error.Report.ReportBuilder;
import com.comphenix.protocol.events.PacketAdapter;
@@ -50,13 +49,13 @@ import com.google.common.primitives.Primitives;
*/
public class DetailedErrorReporter implements ErrorReporter {
/**
* Report format for printing the current exception count.
* Report format for printing the current exception count.
*/
public static final ReportType REPORT_EXCEPTION_COUNT = new ReportType("Internal exception count: %s!");
public static final String SECOND_LEVEL_PREFIX = " ";
public static final String DEFAULT_PREFIX = " ";
public static final String DEFAULT_SUPPORT_URL = "https://github.com/dmulloy2/ProtocolLib/issues";
public static final String DEFAULT_SUPPORT_URL = "http://dev.bukkit.org/server-mods/protocollib/";
// Users that are informed about errors in the chat
public static final String ERROR_PERMISSION = "protocol.info";
@@ -79,7 +78,7 @@ public class DetailedErrorReporter implements ErrorReporter {
protected String pluginName;
// Whether or not Apache Commons is not present
protected static boolean apacheCommonsMissing;
protected boolean apacheCommonsMissing;
// Whether or not detailed errror reporting is enabled
protected boolean detailedReporting;
@@ -93,7 +92,6 @@ public class DetailedErrorReporter implements ErrorReporter {
/**
* Create a default error reporting system.
* @param plugin - the plugin owner.
*/
public DetailedErrorReporter(Plugin plugin) {
this(plugin, DEFAULT_PREFIX, DEFAULT_SUPPORT_URL);
@@ -122,21 +120,13 @@ public class DetailedErrorReporter implements ErrorReporter {
throw new IllegalArgumentException("Plugin cannot be NULL.");
this.pluginReference = new WeakReference<Plugin>(plugin);
this.pluginName = getNameSafely(plugin);
this.pluginName = plugin.getName();
this.prefix = prefix;
this.supportURL = supportURL;
this.maxErrorCount = maxErrorCount;
this.logger = logger;
}
private String getNameSafely(Plugin plugin) {
try {
return plugin.getName();
} catch (LinkageError e) {
return "ProtocolLib";
}
}
// Attempt to get the logger.
private static Logger getBukkitLogger() {
try {
@@ -282,7 +272,7 @@ public class DetailedErrorReporter implements ErrorReporter {
// Print the main warning
if (report.getException() != null) {
logger.log(level, message, report.getException());
} else {
} else {
logger.log(level, message);
// Remember the call stack
@@ -346,7 +336,7 @@ public class DetailedErrorReporter implements ErrorReporter {
writer.println("at " + supportURL + " with the following data:");
// Now, let us print important exception information
writer.println("Stack Trace:");
writer.println(" ===== STACK TRACE =====");
if (report.getException() != null) {
report.getException().printStackTrace(writer);
@@ -356,7 +346,7 @@ public class DetailedErrorReporter implements ErrorReporter {
}
// Data dump!
writer.println("Dump:");
writer.println(" ===== DUMP =====");
// Relevant parameters
if (report.hasCallerParameters()) {
@@ -366,7 +356,7 @@ public class DetailedErrorReporter implements ErrorReporter {
// Global parameters
for (String param : globalParameters()) {
writer.println(SECOND_LEVEL_PREFIX + param + ":");
writer.println(addPrefix(getStringDescription(getGlobalParameter(param)),
writer.println(addPrefix(getStringDescription(getGlobalParameter(param)),
SECOND_LEVEL_PREFIX + SECOND_LEVEL_PREFIX));
}
@@ -379,18 +369,14 @@ public class DetailedErrorReporter implements ErrorReporter {
writer.println("Version:");
writer.println(addPrefix(plugin.toString(), SECOND_LEVEL_PREFIX));
}
// And java version
writer.println("Java Version:");
writer.println(addPrefix(System.getProperty("java.version"), SECOND_LEVEL_PREFIX));
// Add the server version too
if (Bukkit.getServer() != null) {
writer.println("Server:");
writer.println(addPrefix(Bukkit.getServer().getVersion(), SECOND_LEVEL_PREFIX));
// Inform of this occurrence
if (ERROR_PERMISSION != null) {
if (ERROR_PERMISSION != null) {
Bukkit.getServer().broadcast(
String.format("Error %s (%s) occured in %s.", report.getReportMessage(), report.getException(), sender),
ERROR_PERMISSION
@@ -455,7 +441,7 @@ public class DetailedErrorReporter implements ErrorReporter {
* @param value - object to convert.
* @return String representation.
*/
public static String getStringDescription(Object value) {
protected String getStringDescription(Object value) {
// We can't only rely on toString.
if (value == null) {
return "[NULL]";
@@ -470,7 +456,7 @@ public class DetailedErrorReporter implements ErrorReporter {
apacheCommonsMissing = true;
} catch (Exception e) {
// Don't use the error logger to log errors in error logging (that could lead to infinite loops)
ProtocolLibrary.log(Level.WARNING, "Cannot convert to a String with Apache: " + e.getMessage());
System.err.print("[ProtocolLib] Warning: Cannot convert to a String with Apache: " + e.getMessage());
}
// Use our custom object printer instead
@@ -487,7 +473,7 @@ public class DetailedErrorReporter implements ErrorReporter {
* @param test - the object to test.
* @return TRUE if this object is simple enough to simply be printed, FALSE othewise.
*/
protected static boolean isSimpleType(Object test) {
protected boolean isSimpleType(Object test) {
return test instanceof String || Primitives.isWrapperType(test.getClass());
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -56,20 +56,20 @@ public interface ErrorReporter {
/**
* Prints a debug message from the current sender.
* @param sender - the sender.
* @param builder - the report builder.
* @param report - the report builder.
*/
public abstract void reportDebug(Object sender, ReportBuilder builder);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param sender - the object containing the caller method.
* @param report - an error report to include.
*/
public abstract void reportWarning(Object sender, Report report);
/**
* Prints a warning message from the current plugin.
* @param sender - the object containing the caller method.
* @param sender - the object containing the caller method.
* @param reportBuilder - an error report builder that will be used to get the report.
*/
public abstract void reportWarning(Object sender, ReportBuilder reportBuilder);
@@ -1,6 +1,7 @@
package com.comphenix.protocol.error;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.CodeSource;
@@ -28,11 +29,11 @@ public final class PluginContext {
for (int i = 1; i < elements.length; i++) {
String caller = getPluginName(elements[i]);
if (caller != null && !caller.equals(current)) {
return caller;
}
}
return null;
}
@@ -40,28 +41,30 @@ public final class PluginContext {
* Lookup the plugin that this method invocation belongs to, and return its file name.
* @param element - the method invocation.
* @return Plugin name, or NULL if not found.
*
*/
public static String getPluginName(StackTraceElement element) {
try {
if (Bukkit.getServer() == null) {
if (Bukkit.getServer() == null)
return null;
}
CodeSource codeSource = Class.forName(element.getClassName()).getProtectionDomain().getCodeSource();
if (codeSource != null) {
String encoding = codeSource.getLocation().getPath();
File path = new File(URLDecoder.decode(encoding, "UTF-8"));
File plugins = getPluginFolder();
if (plugins != null && folderContains(plugins, path)) {
return path.getName().replaceAll(".jar", "");
return path.getName();
}
}
} catch (Throwable ex) {
// throw new RuntimeException("Cannot lookup plugin name.", ex);
return null; // Cannot find it
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Cannot lookup plugin name.", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Cannot lookup plugin name.", e);
}
return null; // Cannot find it
}
/**
@@ -83,7 +86,6 @@ public final class PluginContext {
return true;
file = file.getParentFile();
}
return false;
}
@@ -94,7 +96,7 @@ public final class PluginContext {
private static File getPluginFolder() {
File folder = pluginFolder;
if (folder == null && Bukkit.getServer() != null) {
if (folder == null && Bukkit.getServer() != null) {
Plugin[] plugins = Bukkit.getPluginManager().getPlugins();
if (plugins.length > 0) {
@@ -102,7 +104,6 @@ public final class PluginContext {
pluginFolder = folder;
}
}
return folder;
}
}
@@ -10,7 +10,7 @@ import javax.annotation.Nullable;
*
* @author Kristian
*/
public class Report {
public class Report {
private final ReportType type;
private final Throwable exception;
private final Object[] messageParameters;
@@ -76,7 +76,7 @@ public class Report {
}
/**
* Set the minimum number of nanoseconds to wait until a report of equal type and parameters
* Set the minimum number of nanoseconds to wait until a report of equal type and parameters
* is allowed to be printed again.
* @param rateLimit - number of nanoseconds, or 0 to disable. Cannot be negative.
* @return This builder, for chaining.
@@ -122,8 +122,8 @@ public class Report {
* @param type - the report type that will be used to construct the message.
* @param messageParameters - parameters used to construct the report message.
* @param callerParameters - parameters from the caller method.
*/
protected Report(ReportType type, @Nullable Throwable exception,
*/
protected Report(ReportType type, @Nullable Throwable exception,
@Nullable Object[] messageParameters, @Nullable Object[] callerParameters) {
this(type, exception, messageParameters, callerParameters, 0);
}
@@ -135,8 +135,8 @@ public class Report {
* @param messageParameters - parameters used to construct the report message.
* @param callerParameters - parameters from the caller method.
* @param rateLimit - minimum number of nanoseconds to wait until a report of equal type and parameters is allowed to be printed again.
*/
protected Report(ReportType type, @Nullable Throwable exception,
*/
protected Report(ReportType type, @Nullable Throwable exception,
@Nullable Object[] messageParameters, @Nullable Object[] callerParameters, long rateLimit) {
if (type == null)
throw new IllegalArgumentException("type cannot be NULL.");
@@ -157,7 +157,7 @@ public class Report {
/**
* Retrieve the message parameters that will be used to construc the report message.
* <p>
* <p<
* This should not be confused with the method parameters of the caller method.
* @return Message parameters.
*/
@@ -231,8 +231,8 @@ public class Report {
return true;
if (obj instanceof Report) {
Report other = (Report) obj;
return type == other.type &&
Arrays.equals(callerParameters, other.callerParameters) &&
return type == other.type &&
Arrays.equals(callerParameters, other.callerParameters) &&
Arrays.equals(messageParameters, other.messageParameters);
}
return false;
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -47,7 +47,7 @@ public enum ListenerPriority {
HIGHEST(4),
/**
* Event is listened to purely for monitoring the outcome of an event.
* <p>
* <p/>
* No modifications to the event should be made under this priority.
*/
MONITOR(5);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -32,7 +32,7 @@ import com.google.common.collect.Sets;
/**
* Determines which packets will be observed by a listener, and with what priority.
* @author Kristian
* @author Kristian
*/
public class ListeningWhitelist {
/**
@@ -60,7 +60,7 @@ public class ListeningWhitelist {
* <p>
* Deprecated: Use {@link #newBuilder()} instead.
* @param priority - the listener priority.
* @param whitelist - set of IDs to observe/enable.
* @param whitelist - set of IDs to observe/enable.
*/
@Deprecated
public ListeningWhitelist(ListenerPriority priority, Set<Integer> whitelist) {
@@ -192,7 +192,7 @@ public class ListeningWhitelist {
/**
* Determine if any of the given IDs can be found in the whitelist.
* @param whitelist - whitelist to test.
* @param idList - list of packet IDs to find.
* @param idList - list of packet IDs to find.
* @return TRUE if any of the packets in the list can be found in the whitelist, FALSE otherwise.
*/
public static boolean containsAny(ListeningWhitelist whitelist, int... idList) {
@@ -442,7 +442,7 @@ public class ListeningWhitelist {
/**
* Set the options to copy when constructing new whitelists.
* @param serverOptions - the options array.
* @param options - the options array.
* @return This builder, for chaining.
*/
public Builder options(ListenerOptions[] serverOptions) {
@@ -452,7 +452,7 @@ public class ListeningWhitelist {
/**
* Options to merge into the current set of options.
* @param serverOptions - the options array.
* @param options - the options array.
* @return This builder, for chaining.
*/
public Builder mergeOptions(ListenerOptions... serverOptions) {
@@ -461,7 +461,7 @@ public class ListeningWhitelist {
/**
* Options to merge into the current set of options.
* @param serverOptions - the options array.
* @param options - the options array.
* @return This builder, for chaining.
*/
public Builder mergeOptions(Collection<ListenerOptions> serverOptions) {
@@ -24,12 +24,12 @@ import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
/**
* Marker containing the serialized packet data seen from the network,
* Marker containing the serialized packet data seen from the network,
* or output handlers that will serialize the current packet.
*
* @author Kristian
*/
public abstract class NetworkMarker {
public abstract class NetworkMarker {
public static class EmptyBufferMarker extends NetworkMarker {
public EmptyBufferMarker(@Nonnull ConnectionSide side) {
super(side, (byte[]) null, null);
@@ -48,7 +48,7 @@ public abstract class NetworkMarker {
@Override
protected DataInputStream addHeader(DataInputStream input, PacketType type) {
throw new IllegalStateException("Buffer is empty.");
}
}
}
// Custom network handler
@@ -68,9 +68,8 @@ public abstract class NetworkMarker {
/**
* Construct a new network marker.
* @param side - which side this marker belongs to.
* @param side - whether or not this marker belongs to a client or server packet.
* @param inputBuffer - the read serialized packet data.
* @param type - packet type
*/
public NetworkMarker(@Nonnull ConnectionSide side, ByteBuffer inputBuffer, PacketType type) {
this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
@@ -82,9 +81,9 @@ public abstract class NetworkMarker {
* Construct a new network marker.
* <p>
* The input buffer is only non-null for client-side packets.
* @param side - which side this marker belongs to.
* @param side - whether or not this marker belongs to a client or server packet.
* @param inputBuffer - the read serialized packet data.
* @param type - packet type
* @param handler - handle skipping headers.
*/
public NetworkMarker(@Nonnull ConnectionSide side, byte[] inputBuffer, PacketType type) {
this.side = Preconditions.checkNotNull(side, "side cannot be NULL.");
@@ -116,7 +115,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data (excluding the header by default) from the network input stream.
* <p>
* The returned buffer is read-only. If the parent event is a server side packet this
* The returned buffer is read-only. If the parent event is a server side packet this
* method throws {@link IllegalStateException}.
* <p>
* It returns NULL if the packet was transmitted by a plugin locally.
@@ -129,7 +128,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data from the network input stream.
* <p>
* The returned buffer is read-only. If the parent event is a server side packet this
* The returned buffer is read-only. If the parent event is a server side packet this
* method throws {@link IllegalStateException}.
* <p>
* It returns NULL if the packet was transmitted by a plugin locally.
@@ -144,7 +143,7 @@ public abstract class NetworkMarker {
ByteBuffer result = inputBuffer.asReadOnlyBuffer();
try {
if (excludeHeader)
if (excludeHeader)
result = skipHeader(result);
else
result = addHeader(result, type);
@@ -159,7 +158,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data (excluding the header by default) as an input stream.
* <p>
* The data is exactly the same as in {@link #getInputBuffer()}.
* The data is exactly the same as in {@link #getInputBuffer()}.
* @see #getInputBuffer()
* @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
*/
@@ -170,7 +169,7 @@ public abstract class NetworkMarker {
/**
* Retrieve the serialized packet data as an input stream.
* <p>
* The data is exactly the same as in {@link #getInputBuffer()}.
* The data is exactly the same as in {@link #getInputBuffer()}.
* @see #getInputBuffer()
* @param excludeHeader - whether or not to exclude the packet ID header.
* @return The incoming serialized packet data as a stream, or NULL if the packet was transmitted locally.
@@ -187,7 +186,7 @@ public abstract class NetworkMarker {
);
try {
if (excludeHeader)
if (excludeHeader)
input = skipHeader(input);
else
input = addHeader(input, type);
@@ -208,7 +207,7 @@ public abstract class NetworkMarker {
/**
* Enqueue the given output handler for managing how the current packet will be written to the network stream.
* <p>
* Note that output handlers are not serialized, as most consumers will probably implement them using anonymous classes.
* Note that output handlers are not serialized, as most consumers will probably implement them using anonymous classes.
* It is not safe to serialize anonymous classes, as their name depend on the order in which they are declared in the parent class.
* <p>
* This can only be invoked on server side packet events.
@@ -262,10 +261,10 @@ public abstract class NetworkMarker {
}
/**
* Add a listener that is invoked after a packet has been successfully sent to the client, or received
* by the server.
* Add a listener that is invoked after a packet has been successfully sent to the client, or received
* by the server.
* <p>
* Received packets are not guarenteed to have been fully processed, but packets passed
* Received packets are not guarenteed to have been fully processed, but packets passed
* to {@link ProtocolManager#recieveClientPacket(Player, PacketContainer)} will be processed after the
* current packet event.
* <p>
@@ -325,9 +324,7 @@ public abstract class NetworkMarker {
* Return a byte buffer without the header in the current packet.
* <p>
* It's safe to modify the position of the buffer.
* @param buffer - a read-only byte source.
* @return A byte buffer without the header in the current packet.
* @throws IOException If integer reading fails
* @param buffer - a read-only byte source.
*/
protected ByteBuffer skipHeader(ByteBuffer buffer) throws IOException {
skipHeader(new DataInputStream(new ByteBufferInputStream(buffer)));
@@ -338,16 +335,13 @@ public abstract class NetworkMarker {
* Return an input stream without the header in the current packet.
* <p>
* It's safe to modify the input stream.
* @param input - input stream
* @return An input stream without the header
* @throws IOException If integer reading fails
*/
protected abstract DataInputStream skipHeader(DataInputStream input) throws IOException;
/**
* Return the byte buffer prepended with the packet header.
* @param buffer - the read-only byte buffer.
* @param type - the current packet.
* @param buffer - the read-only byte buffer.
* @param type - the current packet.
* @return The byte buffer.
*/
protected abstract ByteBuffer addHeader(ByteBuffer buffer, PacketType type);
@@ -355,7 +349,7 @@ public abstract class NetworkMarker {
/**
* Return the input stream prepended with the packet header.
* @param input - the input stream.
* @param type - the current packet.
* @param type - the current packet.
* @return The byte buffer.
*/
protected abstract DataInputStream addHeader(DataInputStream input, PacketType type);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -50,7 +50,7 @@ public abstract class PacketAdapter implements PacketListener {
*/
public PacketAdapter(@Nonnull AdapterParameteters params) {
this(
checkValidity(params).plugin, params.connectionSide, params.listenerPriority,
checkValidity(params).plugin, params.connectionSide, params.listenerPriority,
params.gamePhase, params.options, params.packets
);
}
@@ -58,6 +58,7 @@ public abstract class PacketAdapter implements PacketListener {
/**
* Initialize a packet listener with the given parameters.
* @param plugin - the plugin.
* @param listenerPriority - the priority.
* @param types - the packet types.
*/
public PacketAdapter(Plugin plugin, PacketType... types) {
@@ -240,7 +241,7 @@ public abstract class PacketAdapter implements PacketListener {
*/
@Deprecated
public PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, Integer... packets) {
this(plugin, connectionSide, listenerPriority, gamePhase, options,
@@ -250,7 +251,7 @@ public abstract class PacketAdapter implements PacketListener {
// For internal use only
private PacketAdapter(
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
GamePhase gamePhase, ListenerOptions[] options, PacketType... packets) {
if (plugin == null)
@@ -271,7 +272,7 @@ public abstract class PacketAdapter implements PacketListener {
// Special case that allows us to specify optionIntercept().
if (connectionSide == ConnectionSide.BOTH) {
serverOptions = except(serverOptions, new ListenerOptions[0],
serverOptions = except(serverOptions, new ListenerOptions[0],
ListenerOptions.INTERCEPT_INPUT_BUFFER);
}
@@ -346,21 +347,23 @@ public abstract class PacketAdapter implements PacketListener {
* @return Name of the given plugin.
*/
public static String getPluginName(Plugin plugin) {
if (plugin == null)
return "UNKNOWN";
// Try to get the plugin name
try {
return plugin.getName();
if (plugin == null)
return "UNKNOWN";
else
return plugin.getName();
} catch (NoSuchMethodError e) {
return plugin.toString();
}
}
@Override
public String toString() {
// This is used by the error reporter
return String.format("PacketAdapter[plugin=%s, sending=%s, receiving=%s]",
getPluginName(this),
public String toString() {
// This is used by the error reporter
return String.format("PacketAdapter[plugin=%s, sending=%s, receiving=%s]",
getPluginName(this),
sendingWhitelist,
receivingWhitelist);
}
@@ -438,7 +441,7 @@ public abstract class PacketAdapter implements PacketListener {
}
/**
* Set this adapter to also look for client-side packets.
* Set this adapter to also look for client-side packets.
* @return This builder, for chaining.
*/
public AdapterParameteters clientSide() {
@@ -446,7 +449,7 @@ public abstract class PacketAdapter implements PacketListener {
}
/**
* Set this adapter to also look for server-side packets.
* Set this adapter to also look for server-side packets.
* @return This builder, for chaining.
*/
public AdapterParameteters serverSide() {
@@ -454,7 +457,7 @@ public abstract class PacketAdapter implements PacketListener {
}
/**
* Set the the event priority, where the execution is in ascending order from lowest to highest.
* Set the the event priority, where the execution is in ascending order from lowest to highest.
* <p>
* Default is {@link ListenerPriority#NORMAL}.
* @param listenerPriority - the new event priority.
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -29,7 +29,6 @@ import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -38,17 +37,18 @@ import java.util.concurrent.ConcurrentMap;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.buffer.UnpooledByteBufAllocator;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.compat.netty.Netty;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
import com.comphenix.protocol.injector.StructureCache;
import com.comphenix.protocol.reflect.EquivalentConverter;
import com.comphenix.protocol.reflect.FuzzyReflection;
@@ -67,29 +67,16 @@ import com.comphenix.protocol.reflect.instances.DefaultInstances;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.StreamSerializer;
import com.comphenix.protocol.wrappers.BlockPosition;
import com.comphenix.protocol.wrappers.BukkitConverters;
import com.comphenix.protocol.wrappers.ChunkCoordIntPair;
import com.comphenix.protocol.wrappers.ChunkPosition;
import com.comphenix.protocol.wrappers.EnumWrappers;
import com.comphenix.protocol.wrappers.EnumWrappers.ChatVisibility;
import com.comphenix.protocol.wrappers.EnumWrappers.ClientCommand;
import com.comphenix.protocol.wrappers.EnumWrappers.CombatEventType;
import com.comphenix.protocol.wrappers.EnumWrappers.Difficulty;
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
import com.comphenix.protocol.wrappers.EnumWrappers.Particle;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerAction;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
import com.comphenix.protocol.wrappers.EnumWrappers.ResourcePackStatus;
import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction;
import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction;
import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction;
import com.comphenix.protocol.wrappers.MultiBlockChangeInfo;
import com.comphenix.protocol.wrappers.PlayerInfoData;
import com.comphenix.protocol.wrappers.WrappedAttribute;
import com.comphenix.protocol.wrappers.WrappedBlockData;
import com.comphenix.protocol.wrappers.WrappedChatComponent;
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
@@ -162,9 +149,10 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* <p>
* Deprecated: Use {@link #PacketContainer(PacketType, Object))} instead.
* @param id - ID of the given packet.
* @param handle - contained packet.
* @deprecated Use {@link #PacketContainer(PacketType, Object)} instead
*/
@Deprecated
public PacketContainer(int id, Object handle) {
@@ -173,10 +161,11 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* <p>
* Deprecated: Use {@link #PacketContainer(PacketType, Object, StructureModifier))} instead.
* @param id - ID of the given packet.
* @param handle - contained packet.
* @param structure - structure modifier.
* @deprecated Use {@link #PacketContainer(PacketType, Object, StructureModifier)} instead
*/
@Deprecated
public PacketContainer(int id, Object handle, StructureModifier<Object> structure) {
@@ -193,7 +182,7 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* @param type - Type of the given packet.
* @param id - ID of the given packet.
* @param handle - contained packet.
*/
public PacketContainer(PacketType type, Object handle) {
@@ -202,7 +191,7 @@ public class PacketContainer implements Serializable {
/**
* Creates a packet container for an existing packet.
* @param type - Type of the given packet.
* @param id - ID of the given packet.
* @param handle - contained packet.
* @param structure - structure modifier.
*/
@@ -234,7 +223,7 @@ public class PacketContainer implements Serializable {
}
/**
* Retrieves the underlying Minecraft packet.
* Retrieves the underlying Minecraft packet.
* @return Underlying Minecraft packet.
*/
public Object getHandle() {
@@ -251,7 +240,6 @@ public class PacketContainer implements Serializable {
/**
* Retrieves a read/write structure for every field with the given type.
* @param <T> Type
* @param primitiveType - the type to find.
* @return A modifier for this specific type.
*/
@@ -374,10 +362,10 @@ public class PacketContainer implements Serializable {
* internal Minecraft ItemStack.
* @return A modifier for ItemStack array fields.
*/
public StructureModifier<ItemStack[]> getItemArrayModifier() {
public StructureModifier<ItemStack[]> getItemArrayModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<ItemStack[]>withType(
MinecraftReflection.getItemStackArrayClass(),
MinecraftReflection.getItemStackArrayClass(),
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
}
@@ -388,9 +376,9 @@ public class PacketContainer implements Serializable {
* @return A modifier for maps of statistics.
*/
public StructureModifier<Map<WrappedStatistic, Integer>> getStatisticMaps() {
return structureModifier.withType(Map.class,
return structureModifier.withType(Map.class,
BukkitConverters.<WrappedStatistic, Integer>getMapConverter(
MinecraftReflection.getStatisticClass(),
MinecraftReflection.getStatisticClass(),
BukkitConverters.getWrappedStatisticConverter()
)
);
@@ -406,7 +394,7 @@ public class PacketContainer implements Serializable {
public StructureModifier<WorldType> getWorldTypeModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WorldType>withType(
MinecraftReflection.getWorldTypeClass(),
MinecraftReflection.getWorldTypeClass(),
BukkitConverters.getWorldTypeConverter());
}
@@ -417,7 +405,7 @@ public class PacketContainer implements Serializable {
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedDataWatcher>withType(
MinecraftReflection.getDataWatcherClass(),
MinecraftReflection.getDataWatcherClass(),
BukkitConverters.getDataWatcherConverter());
}
@@ -426,7 +414,7 @@ public class PacketContainer implements Serializable {
* <p>
* Note that entities are transmitted by integer ID, and the type may not be enough
* to distinguish between entities and other values. Thus, this structure modifier
* MAY return null or invalid entities for certain fields. Using the correct index
* MAY return null or invalid entities for certain fields. Using the correct index
* is essential.
*
* @param world - the world each entity is currently occupying.
@@ -444,7 +432,7 @@ public class PacketContainer implements Serializable {
* <p>
* Note that entities are transmitted by integer ID, and the type may not be enough
* to distinguish between entities and other values. Thus, this structure modifier
* MAY return null or invalid entities for certain fields. Using the correct index
* MAY return null or invalid entities for certain fields. Using the correct index
* is essential.
*
* @param event - the original packet event.
@@ -465,18 +453,7 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getChunkPositionClass(),
ChunkPosition.getConverter());
}
/**
* Retrieves a read/write structure for block positions.
* @return A modifier for a BlockPosition.
*/
public StructureModifier<BlockPosition> getBlockPositionModifier() {
// Convert to and from the Bukkit wrapper
return structureModifier.withType(
MinecraftReflection.getBlockPositionClass(),
BlockPosition.getConverter());
}
/**
* Retrieves a read/write structure for wrapped ChunkCoordIntPairs.
* @return A modifier for ChunkCoordIntPair.
@@ -498,18 +475,7 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getNBTBaseClass(),
BukkitConverters.getNbtConverter());
}
/**
* Retrieves a read/write structure for Vectors.
* @return A modifier for Vectors.
*/
public StructureModifier<Vector> getVectors() {
// Automatically marshal between Vec3d and the Bukkit wrapper
return structureModifier.withType(
MinecraftReflection.getVec3DClass(),
BukkitConverters.getVectorConverter());
}
/**
* Retrieves a read/write structure for collections of attribute snapshots.
* <p>
@@ -522,7 +488,7 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getAttributeSnapshotClass(),
MinecraftReflection.getAttributeSnapshotClass(),
BukkitConverters.getWrappedAttributeConverter())
);
}
@@ -532,7 +498,6 @@ public class PacketContainer implements Serializable {
* <p>
* This modifier will automatically marshall between the visible ProtocolLib ChunkPosition and the
* internal Minecraft ChunkPosition.
*
* @return A modifier for ChunkPosition list fields.
*/
public StructureModifier<List<ChunkPosition>> getPositionCollectionModifier() {
@@ -540,29 +505,11 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getChunkPositionClass(),
MinecraftReflection.getChunkPositionClass(),
ChunkPosition.getConverter())
);
}
/**
* Retrieves a read/write structure for collections of chunk positions.
* <p>
* This modifier will automatically marshall between the visible ProtocolLib BlockPosition and the
* internal Minecraft BlockPosition.
*
* @return A modifier for ChunkPosition list fields.
*/
public StructureModifier<List<BlockPosition>> getBlockPositionCollectionModifier() {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getBlockPositionClass(),
BlockPosition.getConverter())
);
}
/**
* Retrieves a read/write structure for collections of watchable objects.
* <p>
@@ -575,7 +522,7 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getWatchableObjectClass(),
MinecraftReflection.getWatchableObjectClass(),
BukkitConverters.getWatchableObjectConverter())
);
}
@@ -604,42 +551,14 @@ public class PacketContainer implements Serializable {
public StructureModifier<WrappedGameProfile> getGameProfiles() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedGameProfile>withType(
MinecraftReflection.getGameProfileClass(), BukkitConverters.getWrappedGameProfileConverter());
}
/**
* Retrieves a read/write structure for BlockData in Minecraft 1.8.
* <p>
* This modifier will automatically marshall between WrappedBlockData and the
* internal Minecraft IBlockData.
* @return A modifier for BlockData fields.
*/
public StructureModifier<WrappedBlockData> getBlockData() {
// Convert to and from our wrapper
return structureModifier.<WrappedBlockData>withType(
MinecraftReflection.getIBlockDataClass(), BukkitConverters.getWrappedBlockDataConverter());
}
/**
* Retrieves a read/write structure for MultiBlockChangeInfo arrays in Minecraft 1.8.
* <p>
* This modifier will automatically marshall between MultiBlockChangeInfo and the
* internal Minecraft MultiBlockChangeInfo.
* @return A modifier for BlockData fields.
*/
public StructureModifier<MultiBlockChangeInfo[]> getMultiBlockChangeInfoArrays() {
ChunkCoordIntPair chunk = getChunkCoordIntPairs().read(0);
// Convert to and from our wrapper
return structureModifier.<MultiBlockChangeInfo[]>withType(
MinecraftReflection.getMultiBlockChangeInfoArrayClass(), MultiBlockChangeInfo.getArrayConverter(chunk));
GameProfile.class, BukkitConverters.getWrappedGameProfileConverter());
}
/**
* Retrieves a read/write structure for chat components in Minecraft 1.7.2.
* <p>
* This modifier will automatically marshall between WrappedChatComponent and the
* internal Minecraft IChatBaseComponent.
* internal Minecraft GameProfile.
* @return A modifier for ChatComponent fields.
*/
public StructureModifier<WrappedChatComponent> getChatComponents() {
@@ -647,20 +566,6 @@ public class PacketContainer implements Serializable {
return structureModifier.<WrappedChatComponent>withType(
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
}
/**
* Retrieves a read/write structure for arrays of chat components.
* <p>
* This modifier will automatically marshall between WrappedChatComponent and the
* internal Minecraft IChatBaseComponent.
* @return A modifier for ChatComponent array fields.
*/
public StructureModifier<WrappedChatComponent[]> getChatComponentArrays() {
// Convert to and from the Bukkit wrapper
return structureModifier.<WrappedChatComponent[]>withType(
MinecraftReflection.getIChatBaseComponentArrayClass(),
BukkitConverters.getIgnoreNull(new WrappedChatComponentArrayConverter()));
}
/**
* Retrieve a read/write structure for the ServerPing fields in the following packet: <br>
@@ -675,23 +580,6 @@ public class PacketContainer implements Serializable {
MinecraftReflection.getServerPingClass(), BukkitConverters.getWrappedServerPingConverter());
}
/**
* Retrieve a read/write structure for the PlayerInfoData list fields in the following packet: <br>
* <ul>
* <li>{@link PacketType.Play.Server#PLAYER_INFO}
* </ul>
* @return A modifier for PlayerInfoData list fields.
*/
public StructureModifier<List<PlayerInfoData>> getPlayerInfoDataLists() {
// Convert to and from the ProtocolLib wrapper
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
MinecraftReflection.getPlayerInfoDataClass(),
PlayerInfoData.getConverter())
);
}
/**
* Retrieve a read/write structure for the Protocol enum in 1.7.2.
* @return A modifier for Protocol enum fields.
@@ -741,7 +629,7 @@ public class PacketContainer implements Serializable {
return structureModifier.<EntityUseAction>withType(
EnumWrappers.getEntityUseActionClass(), EnumWrappers.getEntityUseActionConverter());
}
/**
* Retrieve a read/write structure for the NativeGameMode enum in 1.7.2.
* @return A modifier for NativeGameMode enum fields.
@@ -751,97 +639,7 @@ public class PacketContainer implements Serializable {
return structureModifier.<NativeGameMode>withType(
EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter());
}
/**
* Retrieve a read/write structure for the ResourcePackStatus enum in 1.8.
* @return A modifier for ResourcePackStatus enum fields.
*/
public StructureModifier<ResourcePackStatus> getResourcePackStatus() {
// Convert to and from the wrapper
return structureModifier.<ResourcePackStatus>withType(
EnumWrappers.getResourcePackStatusClass(), EnumWrappers.getResourcePackStatusConverter());
}
/**
* Retrieve a read/write structure for the PlayerInfo enum in 1.8.
* @return A modifier for PlayerInfoAction enum fields.
*/
public StructureModifier<PlayerInfoAction> getPlayerInfoAction() {
// Convert to and from the wrapper
return structureModifier.<PlayerInfoAction>withType(
EnumWrappers.getPlayerInfoActionClass(), EnumWrappers.getPlayerInfoActionConverter());
}
/**
* Retrieve a read/write structure for the TitleAction enum in 1.8.
* @return A modifier for TitleAction enum fields.
*/
public StructureModifier<TitleAction> getTitleActions() {
// Convert to and from the wrapper
return structureModifier.<TitleAction>withType(
EnumWrappers.getTitleActionClass(), EnumWrappers.getTitleActionConverter());
}
/**
* Retrieve a read/write structure for the WorldBorderAction enum in 1.8.
* @return A modifier for WorldBorderAction enum fields.
*/
public StructureModifier<WorldBorderAction> getWorldBorderActions() {
// Convert to and from the wrapper
return structureModifier.<WorldBorderAction>withType(
EnumWrappers.getWorldBorderActionClass(), EnumWrappers.getWorldBorderActionConverter());
}
/**
* Retrieve a read/write structure for the CombatEventType enum in 1.8.
* @return A modifier for CombatEventType enum fields.
*/
public StructureModifier<CombatEventType> getCombatEvents() {
// Convert to and from the wrapper
return structureModifier.<CombatEventType>withType(
EnumWrappers.getCombatEventTypeClass(), EnumWrappers.getCombatEventTypeConverter());
}
/**
* Retrieve a read/write structure for the PlayerDigType enum in 1.8.
* @return A modifier for PlayerDigType enum fields.
*/
public StructureModifier<PlayerDigType> getPlayerDigTypes() {
// Convert to and from the wrapper
return structureModifier.<PlayerDigType>withType(
EnumWrappers.getPlayerDigTypeClass(), EnumWrappers.getPlayerDiggingActionConverter());
}
/**
* Retrieve a read/write structure for the PlayerAction enum in 1.8.
* @return A modifier for PlayerAction enum fields.
*/
public StructureModifier<PlayerAction> getPlayerActions() {
// Convert to and from the wrapper
return structureModifier.<PlayerAction>withType(
EnumWrappers.getPlayerActionClass(), EnumWrappers.getEntityActionConverter());
}
/**
* Retrieve a read/write structure for the ScoreboardAction enum in 1.8.
* @return A modifier for ScoreboardAction enum fields.
*/
public StructureModifier<ScoreboardAction> getScoreboardActions() {
// Convert to and from the wrapper
return structureModifier.<ScoreboardAction>withType(
EnumWrappers.getScoreboardActionClass(), EnumWrappers.getUpdateScoreActionConverter());
}
/**
* Retrieve a read/write structure for the Particle enum in 1.8.
* @return A modifier for Particle enum fields.
*/
public StructureModifier<Particle> getParticles() {
// Convert to and from the wrapper
return structureModifier.<Particle>withType(
EnumWrappers.getParticleClass(), EnumWrappers.getParticleConverter());
}
/**
* Retrieves the ID of this packet.
* <p>
@@ -865,7 +663,7 @@ public class PacketContainer implements Serializable {
* Create a shallow copy of the current packet.
* <p>
* This merely writes the content of each field to the new class directly,
* without performing any expensive copies.
* without performing any expensive copies.
*
* @return A shallow copy of the current packet.
*/
@@ -885,7 +683,7 @@ public class PacketContainer implements Serializable {
* @return A deep copy of the current packet.
*/
public PacketContainer deepClone() {
Object clonedPacket = null;
Object clonedPacket = null;
// Fall back on the alternative (but slower) method of reading and writing back the packet
if (CLONING_UNSUPPORTED.contains(type)) {
@@ -898,14 +696,13 @@ public class PacketContainer implements Serializable {
// To save space, we'll skip copying the inflated buffers in packet 51 and 56
private static Function<BuilderParameters, Cloner> getSpecializedDeepClonerFactory() {
// Look at what you've made me do Java, look at it!!
// Look at what you've made me do Java, look at it!!
return new Function<BuilderParameters, Cloner>() {
@Override
public Cloner apply(@Nullable BuilderParameters param) {
return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
this.writer = new ObjectWriter() {
@Override
protected void transformField(StructureModifier<Object> modifierSource,
protected void transformField(StructureModifier<Object> modifierSource,
StructureModifier<Object> modifierDest, int fieldIndex) {
// No need to clone inflated buffers
if (modifierSource.getField(fieldIndex).getName().startsWith("inflatedBuffer"))
@@ -920,7 +717,7 @@ public class PacketContainer implements Serializable {
}
private void writeObject(ObjectOutputStream output) throws IOException {
// Default serialization
// Default serialization
output.defaultWriteObject();
// We'll take care of NULL packets as well
@@ -928,16 +725,17 @@ public class PacketContainer implements Serializable {
try {
if (MinecraftReflection.isUsingNetty()) {
WrappedByteBuf buffer = createPacketBuffer();
MinecraftMethods.getPacketWriteByteBufMethod().invoke(handle, buffer.getHandle());
ByteBuf buffer = createPacketBuffer();
MinecraftMethods.getPacketWriteByteBufMethod().invoke(handle, buffer);
output.writeInt(buffer.readableBytes());
buffer.readBytes(output, buffer.readableBytes());
} else {
// Call the write-method
output.writeInt(-1);
getMethodLazily(writeMethods, handle.getClass(), "write", DataOutput.class).
invoke(handle, new DataOutputStream(output));
invoke(handle, new DataOutputStream(output));
}
} catch (IllegalArgumentException e) {
@@ -965,10 +763,10 @@ public class PacketContainer implements Serializable {
// Call the read method
try {
if (MinecraftReflection.isUsingNetty()) {
WrappedByteBuf buffer = createPacketBuffer();
ByteBuf buffer = createPacketBuffer();
buffer.writeBytes(input, input.readInt());
MinecraftMethods.getPacketReadByteBufMethod().invoke(handle, buffer.getHandle());
MinecraftMethods.getPacketReadByteBufMethod().invoke(handle, buffer);
} else {
if (input.readInt() != -1)
throw new IllegalArgumentException("Cannot load a packet from 1.7.2 in 1.6.4.");
@@ -993,75 +791,10 @@ public class PacketContainer implements Serializable {
* Construct a new packet data serializer.
* @return The packet data serializer.
*/
private WrappedByteBuf createPacketBuffer() {
return Netty.createPacketBuffer();
private ByteBuf createPacketBuffer() {
return MinecraftReflection.getPacketDataSerializer(UnpooledByteBufAllocator.DEFAULT.buffer());
}
// ---- Metadata
// This map will only be initialized if it is actually used
private Map<String, Object> metadata;
/**
* Gets the metadata value for a given key.
*
* @param key Metadata key
* @return Metadata value, or null if nonexistent.
*/
public Object getMetadata(String key) {
if (metadata != null) {
return metadata.get(key);
}
return null;
}
/**
* Adds metadata to this packet.
* <p>
* Note: Since metadata is lazily initialized, this may result in the creation of the metadata map.
*
* @param key Metadata key
* @param value Metadata value
*/
public void addMetadata(String key, Object value) {
if (metadata == null) {
metadata = new HashMap<String, Object>();
}
metadata.put(key, value);
}
/**
* Removes metadata from this packet.
* <p>
* Note: If this operation leaves the metadata map empty, the map will be set to null.
*
* @param key Metadata key
* @return The previous value, or null if nonexistant.
*/
public Object removeMetadata(String key) {
if (metadata != null) {
Object value = metadata.remove(key);
if (metadata.isEmpty()) {
metadata = null;
}
return value;
}
return null;
}
/**
* Whether or not this packet has metadata for a given key.
*
* @param key Metadata key
* @return True if this packet has metadata for the key, false if not.
*/
public boolean hasMetadata(String key) {
return metadata != null && metadata.containsKey(key);
}
/**
* Retrieve the cached method concurrently.
* @param lookup - a lazy lookup cache.
@@ -1070,7 +803,7 @@ public class PacketContainer implements Serializable {
* @param parameterClass - the one parameter type in the method.
* @return Reflected method.
*/
private Method getMethodLazily(ConcurrentMap<Class<?>, Method> lookup,
private Method getMethodLazily(ConcurrentMap<Class<?>, Method> lookup,
Class<?> handleClass, String methodName, Class<?> parameterClass) {
Method method = lookup.get(handleClass);
@@ -1100,14 +833,13 @@ public class PacketContainer implements Serializable {
private static class ItemStackArrayConverter implements EquivalentConverter<ItemStack[]> {
final EquivalentConverter<ItemStack> stackConverter = BukkitConverters.getItemStackConverter();
@Override
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
Class<?> nmsStack = MinecraftReflection.getItemStackClass();
Object[] result = (Object[]) Array.newInstance(nmsStack, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
result[i] = stackConverter.getGeneric(nmsStack, specific[i]);
}
return result;
}
@@ -1129,46 +861,4 @@ public class PacketContainer implements Serializable {
return ItemStack[].class;
}
}
/**
* Represents an equivalent converter for ChatComponent arrays.
* @author dmulloy2
*/
private static class WrappedChatComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
@Override
public Object getGeneric(Class<?>genericType, WrappedChatComponent[] specific) {
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
// Unwrap every item
for (int i = 0; i < result.length; i++) {
result[i] = componentConverter.getGeneric(nmsComponent, specific[i]);
}
return result;
}
@Override
public WrappedChatComponent[] getSpecific(Object generic) {
Object[] input = (Object[]) generic;
WrappedChatComponent[] result = new WrappedChatComponent[input.length];
// Add the wrapper
for (int i = 0; i < result.length; i++) {
result[i] = componentConverter.getSpecific(input[i]);
}
return result;
}
@Override
public Class<WrappedChatComponent[]> getSpecificType() {
return WrappedChatComponent[].class;
}
}
@Override
public String toString() {
return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]";
}
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -39,7 +39,7 @@ import com.google.common.collect.Multimaps;
import com.google.common.collect.SetMultimap;
/**
* Represents a packet sending or receiving event. Changes to the packet will be
* Represents a packet sending or receiving event. Changes to the packet will be
* reflected in the final version to be sent or received. It is also possible to cancel an event.
* @author Kristian
*/
@@ -47,7 +47,7 @@ public class PacketEvent extends EventObject implements Cancellable {
public static final ReportType REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING = new ReportType(
"Plugin %s changed packet type from %s to %s in packet listener. This is confusing for other plugins! (Not an error, though!)");
private static final SetMultimap<PacketType, PacketType> CHANGE_WARNINGS =
private static final SetMultimap<PacketType, PacketType> CHANGE_WARNINGS =
Multimaps.synchronizedSetMultimap(HashMultimap.<PacketType, PacketType>create());
/**
@@ -229,7 +229,7 @@ public class PacketEvent extends EventObject implements Cancellable {
if (this.packet != null && !Objects.equal(oldType, newType)) {
// Only report this once
if (CHANGE_WARNINGS.put(oldType, newType)) {
ProtocolLibrary.getErrorReporter().reportWarning(this,
ProtocolLibrary.getErrorReporter().reportWarning(this,
Report.newBuilder(REPORT_CHANGING_PACKET_TYPE_IS_CONFUSING).
messageParam(oldType, newType).
build());
@@ -261,7 +261,6 @@ public class PacketEvent extends EventObject implements Cancellable {
* Retrieves whether or not the packet should be cancelled.
* @return TRUE if it should be cancelled, FALSE otherwise.
*/
@Override
public boolean isCancelled() {
return cancel;
}
@@ -308,7 +307,6 @@ public class PacketEvent extends EventObject implements Cancellable {
*
* @param cancel - TRUE if it should be cancelled, FALSE otherwise.
*/
@Override
public void setCancelled(boolean cancel) {
if (readOnly)
throw new IllegalStateException("The packet event is read-only.");
@@ -356,12 +354,12 @@ public class PacketEvent extends EventObject implements Cancellable {
return asyncMarker;
}
/**
* Set the asynchronous marker.
* Set the asynchronous marker.
* <p>
* If the marker is non-null at the end of an synchronous event processing, the packet will be scheduled
* to be processed asynchronously with the given settings.
* <p>
* Note that if there are no asynchronous events that can receive this packet, the marker should be NULL.
* Note that if there are no asynchronous events that can receive this packet, the marker should be NULL.
* @param asyncMarker - the new asynchronous marker, or NULL.
* @throws IllegalStateException If the current event is asynchronous.
*/
@@ -427,7 +425,7 @@ public class PacketEvent extends EventObject implements Cancellable {
}
private void writeObject(ObjectOutputStream output) throws IOException {
// Default serialization
// Default serialization
output.defaultWriteObject();
// Write the name of the player (or NULL if it's not set)
@@ -441,15 +439,10 @@ public class PacketEvent extends EventObject implements Cancellable {
final SerializedOfflinePlayer serialized = (SerializedOfflinePlayer) input.readObject();
// Better than nothing
if (serialized != null) {
if (serialized != null) {
// Store it, to prevent weak reference from cleaning up the reference
offlinePlayer = serialized.getPlayer();
playerReference = new WeakReference<Player>(offlinePlayer);
}
}
@Override
public String toString() {
return "PacketEvent[player=" + getPlayer() + ", packet=" + packet + "]";
}
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -34,7 +34,7 @@ public interface PacketListener {
* <p>
* This method is executed on the main thread in 1.6.4 and earlier, and thus the Bukkit API is safe to use.
* <p>
* In Minecraft 1.7.2 and later, this method MAY be executed asynchronously, but only if {@link ListenerOptions#ASYNC}
* In Minecraft 1.7.2 and later, this method MAY be executed asynchronously, but only if {@link ListenerOptions#ASYNC}
* have been specified in the listener. This is off by default.
* @param event - the packet that should be sent.
*/
@@ -43,9 +43,9 @@ public interface PacketListener {
/**
* Invoked right before a received packet from a client is being processed.
* <p>
* <b>WARNING</b>: <br>
* This method will be called <i>asynchronously</i>! You should synchronize with the main
* thread using {@link org.bukkit.scheduler.BukkitScheduler#scheduleSyncDelayedTask(Plugin, Runnable, long) scheduleSyncDelayedTask}
* <b>WARNING</b>: </br>
* This method will be called <i>asynchronously</i>! You should synchronize with the main
* thread using {@link org.bukkit.scheduler.BukkitScheduler#scheduleSyncDelayedTask(Plugin, Runnable, long) scheduleSyncDelayedTask}
* if you need to call the Bukkit API.
* @param event - the packet that has been received.
*/
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -38,8 +38,8 @@ import com.google.common.primitives.Primitives;
* <p>
* Typical conversions include:
* <ul>
* <li>org.bukkit.entity.Player to net.minecraft.server.EntityPlayer</li>
* <li>org.bukkit.World to net.minecraft.server.WorldServer</li>
* <li>org.bukkit.entity.Player -> net.minecraft.server.EntityPlayer</li>
* <li>org.bukkit.World -> net.minecraft.server.WorldServer</li>
* </ul>
*
* @author Kristian
@@ -91,7 +91,7 @@ public class BukkitUnwrapper implements Unwrapper {
@Override
public Object unwrapItem(Object wrappedObject) {
// Special case
if (wrappedObject == null)
if (wrappedObject == null)
return null;
Class<?> currentClass = PacketConstructor.getClass(wrappedObject);
@@ -149,7 +149,7 @@ public class BukkitUnwrapper implements Unwrapper {
try {
final Method find = type.getMethod("getHandle");
// It's thread safe, as getMethod should return the same handle
// It's thread safe, as getMethod should return the same handle
Unwrapper methodUnwrapper = new Unwrapper() {
@Override
public Object unwrapItem(Object wrappedObject) {
@@ -159,7 +159,7 @@ public class BukkitUnwrapper implements Unwrapper {
return find.invoke(wrappedObject);
} catch (IllegalArgumentException e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_ILLEGAL_ARGUMENT).error(e).callerParam(wrappedObject, find)
);
} catch (IllegalAccessException e) {
@@ -178,7 +178,7 @@ public class BukkitUnwrapper implements Unwrapper {
return methodUnwrapper;
} catch (SecurityException e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_SECURITY_LIMITATION).error(e).callerParam(type)
);
} catch (NoSuchMethodException e) {
@@ -188,7 +188,7 @@ public class BukkitUnwrapper implements Unwrapper {
if (fieldUnwrapper != null)
return fieldUnwrapper;
else
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
}
@@ -214,7 +214,7 @@ public class BukkitUnwrapper implements Unwrapper {
return checkClass((Class<?>) wrappedObject, type, find.getType());
return FieldUtils.readField(find, wrappedObject, true);
} catch (IllegalAccessException e) {
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_READ_FIELD_HANDLE).error(e).callerParam(wrappedObject, find)
);
return null;
@@ -227,7 +227,7 @@ public class BukkitUnwrapper implements Unwrapper {
} else {
// Inform about this too
reporter.reportDetailed(this,
reporter.reportDetailed(this,
Report.newBuilder(REPORT_CANNOT_READ_FIELD_HANDLE).callerParam(find)
);
return null;
@@ -26,7 +26,6 @@ import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
import com.comphenix.protocol.injector.netty.WirePacket;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftVersion;
@@ -45,7 +44,6 @@ import com.google.common.collect.Sets;
public class DelayedPacketManager implements InternalManager {
// Registering packet IDs that are not supported
public static final ReportType REPORT_CANNOT_SEND_QUEUED_PACKET = new ReportType("Cannot send queued packet %s.");
public static final ReportType REPORT_CANNOT_SEND_QUEUED_WIRE_PACKET = new ReportType("Cannot send queued wire packet %s.");
public static final ReportType REPORT_CANNOT_REGISTER_QUEUED_LISTENER = new ReportType("Cannot register queued listener %s.");
private volatile InternalManager delegate;
@@ -105,7 +103,7 @@ public class DelayedPacketManager implements InternalManager {
/**
* Update the delegate to the underlying manager.
* <p>
* This will prompt this packet manager to immediately transmit and
* This will prompt this packet manager to immediately transmit and
* register all queued packets an listeners.
* @param delegate - delegate to the new manager.
*/
@@ -131,7 +129,7 @@ public class DelayedPacketManager implements InternalManager {
delegate.addPacketListener(listener);
} catch (IllegalArgumentException e) {
// Inform about this plugin error
reporter.reportWarning(this,
reporter.reportWarning(this,
Report.newBuilder(REPORT_CANNOT_REGISTER_QUEUED_LISTENER).
callerParam(delegate).messageParam(listener).error(e));
}
@@ -151,7 +149,7 @@ public class DelayedPacketManager implements InternalManager {
}
}
private Runnable queuedAddPacket(final ConnectionSide side, final Player player, final PacketContainer packet,
private Runnable queuedAddPacket(final ConnectionSide side, final Player player, final PacketContainer packet,
final NetworkMarker marker, final boolean filtered) {
return new Runnable() {
@@ -171,10 +169,10 @@ public class DelayedPacketManager implements InternalManager {
}
} catch (Exception e) {
// Inform about this plugin error
reporter.reportWarning(this,
reporter.reportWarning(this,
Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_PACKET).
callerParam(delegate).messageParam(packet).error(e));
}
}
}
};
}
@@ -208,36 +206,6 @@ public class DelayedPacketManager implements InternalManager {
}
}
@Override
public void sendWirePacket(Player receiver, int id, byte[] bytes) throws InvocationTargetException {
WirePacket packet = new WirePacket(id, bytes);
sendWirePacket(receiver, packet);
}
@Override
public void sendWirePacket(final Player receiver, final WirePacket packet) throws InvocationTargetException {
if (delegate != null) {
delegate.sendWirePacket(receiver, packet);
} else {
queuedActions.add(new Runnable() {
@Override
public void run() {
try {
delegate.sendWirePacket(receiver, packet);
} catch (Throwable ex) {
// Inform about this plugin error
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_WIRE_PACKET)
.callerParam(delegate)
.messageParam(packet)
.error(ex));
}
}
});
}
}
@Override
public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException {
recieveClientPacket(sender, packet, null, true);
@@ -436,7 +404,7 @@ public class DelayedPacketManager implements InternalManager {
@Override
public void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
if (delegate != null)
if (delegate != null)
delegate.updateEntity(entity, observers);
else
EntityUtilities.updateEntity(entity, observers);
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.World;
@@ -52,8 +53,19 @@ class EntityUtilities {
private static Method scanPlayersMethod;
// Fix: PaperSpigot changed the trackedPlayers field
private static Collection<?> getCollection(Object value) {
if (value instanceof Collection<?>) {
return (Collection<?>) value;
} else if (value instanceof Map<?, ?>) {
return ((Map<?, ?>) value).keySet();
} else {
throw new IllegalArgumentException("Expected Collection or Map but got " + value.getClass());
}
}
/*
* While this function may look pretty bad, it's essentially just a reflection-warped
* While this function may look pretty bad, it's essentially just a reflection-warped
* version of the following:
*
* @SuppressWarnings("unchecked")
@@ -85,19 +97,21 @@ class EntityUtilities {
*/
public static void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
try {
//EntityTrackerEntry trackEntity = (EntityTrackerEntry) tracker.trackedEntities.get(entity.getEntityId());
// Fix: Throw a more informative error
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
if (trackerEntry == null) {
throw new IllegalArgumentException("Cannot find entity trackers for " + entity + (entity.isDead() ? " - entity is dead." : "."));
}
if (trackedPlayersField == null) {
// This one is fairly easy
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
}
// Phew, finally there.
Collection<?> trackedPlayers = (Collection<?>) FieldUtils.readField(trackedPlayersField, trackerEntry, false);
Collection<?> trackedPlayers = getCollection(FieldUtils.readField(trackedPlayersField, trackerEntry, false));
List<Object> nmsPlayers = unwrapBukkit(observers);
// trackEntity.trackedPlayers.clear();
trackedPlayers.removeAll(nmsPlayers);
// We have to rely on a NAME once again. Damn it.
@@ -105,7 +119,6 @@ class EntityUtilities {
scanPlayersMethod = trackerEntry.getClass().getMethod("scanPlayers", List.class);
}
//trackEntity.scanPlayers(server.players);
scanPlayersMethod.invoke(trackerEntry, nmsPlayers);
} catch (IllegalArgumentException e) {
@@ -130,17 +143,17 @@ class EntityUtilities {
public static List<Player> getEntityTrackers(Entity entity) {
try {
List<Player> result = new ArrayList<Player>();
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
if (trackerEntry == null) {
throw new IllegalArgumentException("Cannot find entity trackers for " + entity +
(entity.isDead() ? " - entity is dead." : "."));
throw new IllegalArgumentException("Cannot find entity trackers for " + entity + (entity.isDead() ? " - entity is dead." : "."));
}
if (trackedPlayersField == null) {
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
}
Collection<?> trackedPlayers = (Collection<?>) FieldUtils.readField(trackedPlayersField, trackerEntry, false);
Collection<?> trackedPlayers = getCollection(FieldUtils.readField(trackedPlayersField, trackerEntry, false));
// Wrap every player - we also ensure that the underlying tracker list is immutable
for (Object tracker : trackedPlayers) {
@@ -152,6 +165,8 @@ class EntityUtilities {
} catch (IllegalAccessException e) {
throw new FieldAccessException("Security limitation prevented access to the list of tracked players.", e);
} catch (InvocationTargetException e) {
throw new FieldAccessException("Exception occurred in Minecraft.", e);
}
}
@@ -160,9 +175,9 @@ class EntityUtilities {
* @param world - world server.
* @param entityID - entity ID.
* @return The entity tracker entry.
* @throws FieldAccessException
* @throws FieldAccessException
*/
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException {
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
Object worldServer = unwrapper.unwrapItem(world);
@@ -181,9 +196,9 @@ class EntityUtilities {
if (trackedEntitiesField == null) {
@SuppressWarnings("rawtypes")
Set<Class> ignoredTypes = new HashSet<Class>();
Set<Class> ignoredTypes = new HashSet<Class>();
// Well, this is more difficult. But we're looking for a Minecraft object that is not
// Well, this is more difficult. But we're looking for a Minecraft object that is not
// created by the constructor(s).
for (Constructor<?> constructor : tracker.getClass().getConstructors()) {
for (Class<?> type : constructor.getParameterTypes()) {
@@ -28,30 +28,29 @@ class LoginPackets {
serverSide.add(Packets.Server.KEY_RESPONSE);
clientSide.add(Packets.Client.CLIENT_COMMAND);
serverSide.add(Packets.Server.LOGIN);
// List ping
clientSide.add(Packets.Client.GET_INFO);
// In 1.6.2, Minecraft started sending CUSTOM_PAYLOAD in the server list protocol
// MCPC+/Cauldron contains Forge, which uses CUSTOM_PAYLOAD during login
if (version.isAtLeast(MinecraftVersion.HORSE_UPDATE) || isCauldronOrMCPC()) {
if (version.compareTo(MinecraftVersion.HORSE_UPDATE) >= 0 || triesForgeIntegration()) {
clientSide.add(Packets.Client.CUSTOM_PAYLOAD);
}
if (isCauldronOrMCPC()) {
serverSide.add(Packets.Server.CUSTOM_PAYLOAD);
}
serverSide.add(Packets.Server.KICK_DISCONNECT);
// Forge uses packet 250 during login
if (triesForgeIntegration()) {
serverSide.add(Packets.Client.CUSTOM_PAYLOAD);
}
}
/**
* Determine if we are running MCPC or Cauldron.
* Determine if we are runnign MCPC.
* @return TRUE if we are, FALSE otherwise.
*/
private static boolean isCauldronOrMCPC() {
String version = Bukkit.getServer().getVersion();
return version.contains("MCPC") || version.contains("Cauldron");
private static boolean triesForgeIntegration() {
String version = Bukkit.getVersion();
return version.contains("MCPC-Plus") || version.contains("Cauldron") || version.contains("Thermos");
}
/**
@@ -36,7 +36,7 @@ public class NetworkProcessor {
*/
public byte[] processOutput(PacketEvent event, NetworkMarker marker, final byte[] input) {
// Bit of a hack - but we need the performance
PriorityQueue<PacketOutputHandler> handlers = (PriorityQueue<PacketOutputHandler>)
PriorityQueue<PacketOutputHandler> handlers = (PriorityQueue<PacketOutputHandler>)
marker.getOutputHandlers();
byte[] output = input;
@@ -66,7 +66,6 @@ public class NetworkProcessor {
/**
* Invoke the post listeners and packet transmission, if any.
* @param event - PacketEvent
* @param marker - the network marker, or NULL.
*/
public void invokePostEvent(PacketEvent event, NetworkMarker marker) {
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -38,7 +38,7 @@ import com.google.common.primitives.Primitives;
*/
public class PacketConstructor {
/**
* A packet constructor that automatically converts Bukkit types to their NMS conterpart.
* A packet constructor that automatically converts Bukkit types to their NMS conterpart.
* <p>
* Remember to call withPacket().
*/
@@ -59,7 +59,7 @@ public class PacketConstructor {
private PacketConstructor(Constructor<?> constructorMethod) {
this.constructorMethod = constructorMethod;
this.unwrappers = Lists.newArrayList((Unwrapper) new BukkitUnwrapper(new RethrowErrorReporter() ));
this.unwrappers.addAll(BukkitConverters.getUnwrappers());
this.unwrappers.addAll(BukkitConverters.getUnwrappers());
}
private PacketConstructor(PacketType type, Constructor<?> constructorMethod, List<Unwrapper> unwrappers, Unwrapper[] paramUnwrapper) {
@@ -104,7 +104,7 @@ public class PacketConstructor {
/**
* Create a packet constructor that creates packets using the given ID.
* <p>
* Note that if you pass a Class as a value, it will use its type directly.
* Note that if you pass a Class<?> as a value, it will use its type directly.
* <p>
* Deprecated: Use {@link #withPacket(PacketType, Object[])} instead.
* @param id - legacy (1.6.4) packet ID.
@@ -120,7 +120,7 @@ public class PacketConstructor {
/**
* Create a packet constructor that creates packets using the given types.
* <p>
* Note that if you pass a Class as a value, it will use its type directly.
* Note that if you pass a Class<?> as a value, it will use its type directly.
* @param type - the type of the packet to create.
* @param values - the values that will match each parameter in the desired constructor.
* @return A packet constructor with these types.
@@ -129,7 +129,7 @@ public class PacketConstructor {
public PacketConstructor withPacket(PacketType type, Object[] values) {
Class<?>[] types = new Class<?>[values.length];
Throwable lastException = null;
Unwrapper[] paramUnwrapper = new Unwrapper[values.length];
Unwrapper[] paramUnwrapper = new Unwrapper[values.length];
for (int i = 0; i < types.length; i++) {
// Default type
@@ -258,7 +258,7 @@ public class PacketConstructor {
/**
* Convert the given wrapped object to the equivalent net.minecraft.server object.
* <p>
* Note that we may pass in a class instead of object - in that case, the unwrapper should
* Note that we may pass in a class instead of object - in that case, the unwrapper should
* return the equivalent NMS class.
* @param wrappedObject - wrapped object or class.
* @return The equivalent net.minecraft.server object or class.
@@ -53,9 +53,6 @@ import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.async.AsyncFilterManager;
import com.comphenix.protocol.async.AsyncMarker;
import com.comphenix.protocol.compat.netty.Netty;
import com.comphenix.protocol.compat.netty.ProtocolInjector;
import com.comphenix.protocol.compat.netty.WrappedChannel;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
@@ -68,7 +65,7 @@ import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.injector.netty.WirePacket;
import com.comphenix.protocol.injector.netty.NettyProtocolInjector;
import com.comphenix.protocol.injector.packet.InterceptWritePacket;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
@@ -80,10 +77,10 @@ import com.comphenix.protocol.injector.player.PlayerInjectorBuilder;
import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.utility.BukkitUtil;
import com.comphenix.protocol.utility.EnhancerFactory;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.utility.Util;
import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
@@ -204,7 +201,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
private SpigotPacketInjector spigotInjector;
// Netty injector (for 1.7.2)
private ProtocolInjector nettyInjector;
private NettyProtocolInjector nettyInjector;
// Plugin verifier
private PluginVerifier pluginVerifier;
@@ -222,8 +219,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
private boolean debug;
/**
* Only create instances of this class if ProtocolLib is disabled.
* @param builder - PacketFilterBuilder
* Only create instances of this class if protocol lib is disabled.
*/
public PacketFilterManager(PacketFilterBuilder builder) {
// Used to determine if injection is needed
@@ -272,7 +268,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
// Use the correct injection type
if (MinecraftReflection.isUsingNetty()) {
this.nettyInjector = Netty.getProtocolInjector(builder.getLibrary(), this, reporter);
this.nettyInjector = new NettyProtocolInjector(builder.getLibrary(), this, reporter);
this.playerInjection = nettyInjector.getPlayerInjector();
this.packetInjector = nettyInjector.getPacketInjector();
@@ -441,7 +437,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
playerInjection.checkListener(listener);
}
if (hasSending)
incrementPhases(processPhase(sending));
incrementPhases(processPhase(sending, ConnectionSide.SERVER_SIDE));
// Handle receivers after senders
if (hasReceiving) {
@@ -450,7 +446,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
enablePacketFilters(listener, receiving.getTypes());
}
if (hasReceiving)
incrementPhases(processPhase(receiving));
incrementPhases(processPhase(receiving, ConnectionSide.CLIENT_SIDE));
// Inform our injected hooks
packetListeners.add(listener);
@@ -458,7 +454,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
}
}
private GamePhase processPhase(ListeningWhitelist whitelist) {
private GamePhase processPhase(ListeningWhitelist whitelist, ConnectionSide side) {
// Determine if this is a login packet, ensuring that gamephase detection is enabled
if (!whitelist.getGamePhase().hasLogin() &&
!whitelist.getOptions().contains(ListenerOptions.DISABLE_GAMEPHASE_DETECTION)) {
@@ -509,7 +505,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
unhookTask.cancel();
else
// Inject our hook into already existing players
initializePlayers(Util.getOnlinePlayers());
initializePlayers(BukkitUtil.getOnlinePlayers());
}
}
}
@@ -530,7 +526,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
@Override
public void run() {
// Inject our hook into already existing players
uninitializePlayers(Util.getOnlinePlayers());
uninitializePlayers(BukkitUtil.getOnlinePlayers());
}
});
}
@@ -571,11 +567,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
// Remove listeners and phases
if (sending != null && sending.isEnabled()) {
sendingRemoved = sendingListeners.removeListener(listener, sending);
decrementPhases(processPhase(sending));
decrementPhases(processPhase(sending, ConnectionSide.SERVER_SIDE));
}
if (receiving != null && receiving.isEnabled()) {
receivingRemoved = recievedListeners.removeListener(listener, receiving);
decrementPhases(processPhase(receiving));
decrementPhases(processPhase(receiving, ConnectionSide.CLIENT_SIDE));
}
// Remove hooks, if needed
@@ -710,7 +706,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
@Override
public void broadcastServerPacket(PacketContainer packet) {
Preconditions.checkNotNull(packet, "packet cannot be NULL.");
broadcastServerPacket(packet, Util.getOnlinePlayers());
broadcastServerPacket(packet, BukkitUtil.getOnlinePlayers());
}
@Override
@@ -736,7 +732,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
Location recycle = origin.clone();
// Only broadcast the packet to nearby players
for (Player player : Util.getOnlinePlayers()) {
for (Player player : server.getOnlinePlayers()) {
if (world.equals(player.getWorld()) &&
getDistanceSquared(origin, recycle, player) <= maxDistance) {
@@ -836,22 +832,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
playerInjection.sendServerPacket(receiver, packet, marker, filters);
}
@Override
public void sendWirePacket(Player receiver, int id, byte[] bytes) throws InvocationTargetException {
WirePacket packet = new WirePacket(id, bytes);
sendWirePacket(receiver, packet);
}
@Override
public void sendWirePacket(Player receiver, WirePacket packet) throws InvocationTargetException {
WrappedChannel channel = playerInjection.getChannel(receiver);
if (channel == null) {
throw new InvocationTargetException(new NullPointerException(), "Failed to obtain channel for " + receiver.getName());
}
channel.writeAndFlush(packet);
}
@Override
public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException {
recieveClientPacket(sender, packet, null, true);
@@ -1008,7 +988,6 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
/**
* Register this protocol manager on Bukkit.
*
* @param manager - Bukkit plugin manager that provides player join/leave events.
* @param plugin - the parent plugin.
*/
@@ -1021,31 +1000,26 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
try {
manager.registerEvents(new Listener() {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerLogin(PlayerLoginEvent event) {
public void onPlayerLogin(PlayerLoginEvent event) {
PacketFilterManager.this.onPlayerLogin(event);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPrePlayerJoin(PlayerJoinEvent event) {
public void onPrePlayerJoin(PlayerJoinEvent event) {
PacketFilterManager.this.onPrePlayerJoin(event);
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
public void onPlayerJoin(PlayerJoinEvent event) {
PacketFilterManager.this.onPlayerJoin(event);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
public void onPlayerQuit(PlayerQuitEvent event) {
PacketFilterManager.this.onPlayerQuit(event);
}
}
@EventHandler(priority = EventPriority.MONITOR)
public void onPluginDisabled(PluginDisableEvent event) {
public void onPluginDisabled(PluginDisableEvent event) {
PacketFilterManager.this.onPluginDisabled(event, plugin);
}
}
}, plugin);
@@ -1069,7 +1043,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
playerInjection.uninjectPlayer(event.getPlayer().getAddress());
playerInjection.injectPlayer(event.getPlayer(), ConflictStrategy.OVERRIDE);
} catch (ServerHandlerNull e) {
// Caused by logged out players, or fake login events in MCPC+/Cauldron. Ignore it.
// Caused by logged out players, or fake login events in MCPC++. Ignore it.
} catch (Exception e) {
reporter.reportDetailed(PacketFilterManager.this,
Report.newBuilder(REPORT_CANNOT_INJECT_PLAYER).callerParam(event).error(e)
@@ -4,7 +4,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginLoadOrder;
@@ -74,16 +73,10 @@ class PluginVerifier {
public PluginVerifier(Plugin dependency) {
if (dependency == null)
throw new IllegalArgumentException("dependency cannot be NULL.");
try {
// This would screw with the assumption in hasDependency(Plugin, Plugin)
if (safeConversion(dependency.getDescription().getLoadBefore()).size() > 0)
throw new IllegalArgumentException("dependency cannot have a load directives.");
} catch (LinkageError e) {
// They're probably using an ancient version of Bukkit
dependency.getLogger().log(Level.WARNING, "Failed to determine loadBefore: " + e);
}
// This would screw with the assumption in hasDependency(Plugin, Plugin)
if (safeConversion(dependency.getDescription().getLoadBefore()).size() > 0)
throw new IllegalArgumentException("dependency cannot have a load directives.");
this.dependency = dependency;
}
@@ -100,7 +93,7 @@ class PluginVerifier {
if (plugin != null)
return plugin;
else
throw new PluginNotFoundException("Cannot find plugin " + pluginName);
throw new PluginNotFoundException("Cannot find plugin " + pluginName);
}
/**
@@ -160,7 +153,7 @@ class PluginVerifier {
/**
* Determine if a given plugin is guarenteed to be loaded before the other.
* <p>
* Note that the before plugin is assumed to have no "load" directives - that is, plugins to be
* Note that the before plugin is assumed to have no "load" directives - that is, plugins to be
* loaded after itself. The after plugin may have "load" directives, but it is irrelevant for our purposes.
* @param beforePlugin - the plugin that is loaded first.
* @param afterPlugin - the plugin that is loaded last.
@@ -173,7 +166,7 @@ class PluginVerifier {
}
// No dependency - check the load order
if (beforePlugin.getDescription().getLoad() == PluginLoadOrder.STARTUP &&
if (beforePlugin.getDescription().getLoad() == PluginLoadOrder.STARTUP &&
afterPlugin.getDescription().getLoad() == PluginLoadOrder.POSTWORLD) {
return true;
}
@@ -184,14 +177,14 @@ class PluginVerifier {
* Determine if a plugin has a given dependency, either directly or indirectly.
* @param plugin - the plugin to check.
* @param dependency - the dependency to find.
* @return TRUE if the plugin has the given dependency, FALSE otherwise.
* @return TRUE if the plugin has the given dependency, FALSE otherwise.
*/
private boolean hasDependency(Plugin plugin, Plugin dependency) {
return hasDependency(plugin, dependency, Sets.<String>newHashSet());
}
/**
* Convert a list to a set.
* Convert a list to a set.
* <p>
* A null list will be converted to an empty set.
* @param list - the list to convert.
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.util.Collection;
import java.util.Iterator;
@@ -23,12 +7,13 @@ import java.util.ListIterator;
import java.util.concurrent.Callable;
import net.minecraft.util.io.netty.channel.Channel;
// Hopefully, CB won't version these as well
import net.minecraft.util.io.netty.channel.ChannelFuture;
import net.minecraft.util.io.netty.channel.ChannelHandler;
import com.google.common.collect.Lists;
public class ShadedBootstrapList implements List<Object> {
class BootstrapList implements List<Object> {
private List<Object> delegate;
private ChannelHandler handler;
@@ -37,7 +22,7 @@ public class ShadedBootstrapList implements List<Object> {
* @param delegate - the delegate.
* @param handler - the channel handler to add.
*/
public ShadedBootstrapList(List<Object> delegate, ChannelHandler handler) {
public BootstrapList(List<Object> delegate, ChannelHandler handler) {
this.delegate = delegate;
this.handler = handler;
@@ -131,102 +116,82 @@ public class ShadedBootstrapList implements List<Object> {
}
// Boiler plate
@Override
public synchronized int size() {
return delegate.size();
}
@Override
public synchronized boolean isEmpty() {
return delegate.isEmpty();
}
@Override
public boolean contains(Object o) {
return delegate.contains(o);
}
@Override
public synchronized Iterator<Object> iterator() {
return delegate.iterator();
}
@Override
public synchronized Object[] toArray() {
return delegate.toArray();
}
@Override
public synchronized <T> T[] toArray(T[] a) {
return delegate.toArray(a);
}
@Override
public synchronized boolean remove(Object o) {
return delegate.remove(o);
}
@Override
public synchronized boolean containsAll(Collection<?> c) {
return delegate.containsAll(c);
}
@Override
public synchronized boolean addAll(int index, Collection<? extends Object> c) {
return delegate.addAll(index, c);
}
@Override
public synchronized boolean removeAll(Collection<?> c) {
return delegate.removeAll(c);
}
@Override
public synchronized boolean retainAll(Collection<?> c) {
return delegate.retainAll(c);
}
@Override
public synchronized void clear() {
delegate.clear();
}
@Override
public synchronized Object get(int index) {
return delegate.get(index);
}
@Override
public synchronized void add(int index, Object element) {
delegate.add(index, element);
}
@Override
public synchronized Object remove(int index) {
return delegate.remove(index);
}
@Override
public synchronized int indexOf(Object o) {
return delegate.indexOf(o);
}
@Override
public synchronized int lastIndexOf(Object o) {
return delegate.lastIndexOf(o);
}
@Override
public synchronized ListIterator<Object> listIterator() {
return delegate.listIterator();
}
@Override
public synchronized ListIterator<Object> listIterator(int index) {
return delegate.listIterator(index);
}
@Override
public synchronized List<Object> subList(int fromIndex, int toIndex) {
return delegate.subList(fromIndex, toIndex);
}
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
@@ -28,10 +12,12 @@ import java.util.NoSuchElementException;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import net.minecraft.util.com.mojang.authlib.GameProfile;
import net.minecraft.util.io.netty.buffer.ByteBuf;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelHandler;
import net.minecraft.util.io.netty.channel.ChannelHandlerContext;
import net.minecraft.util.io.netty.channel.ChannelInboundHandler;
import net.minecraft.util.io.netty.channel.ChannelInboundHandlerAdapter;
import net.minecraft.util.io.netty.channel.ChannelPipeline;
import net.minecraft.util.io.netty.channel.ChannelPromise;
@@ -48,18 +34,13 @@ import org.bukkit.entity.Player;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.compat.netty.ChannelInjector;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
import com.comphenix.protocol.compat.netty.WrappedChannel;
import com.comphenix.protocol.annotations.Spigot;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.NetworkProcessor;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.netty.NettyNetworkMarker;
import com.comphenix.protocol.injector.netty.WirePacket;
import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.reflect.FuzzyReflection;
import com.comphenix.protocol.reflect.VolatileField;
@@ -70,7 +51,6 @@ import com.comphenix.protocol.utility.MinecraftFields;
import com.comphenix.protocol.utility.MinecraftMethods;
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.wrappers.WrappedGameProfile;
import com.google.common.base.Preconditions;
import com.google.common.collect.MapMaker;
@@ -78,17 +58,16 @@ import com.google.common.collect.MapMaker;
* Represents a channel injector.
* @author Kristian
*/
public class ShadedChannelInjector extends ByteToMessageDecoder implements ChannelInjector {
class ChannelInjector extends ByteToMessageDecoder implements Injector {
public static final ReportType REPORT_CANNOT_INTERCEPT_SERVER_PACKET = new ReportType("Unable to intercept a written server packet.");
public static final ReportType REPORT_CANNOT_INTERCEPT_CLIENT_PACKET = new ReportType("Unable to intercept a read client packet.");
public static final ReportType REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD = new ReportType("Cannot execute code in channel thread.");
public static final ReportType REPORT_CANNOT_FIND_GET_VERSION = new ReportType("Cannot find getVersion() in NetworkMananger");
public static final ReportType REPORT_CANNOT_SEND_PACKET = new ReportType("Unable to send packet %s to %s");
/**
* Indicates that a packet has bypassed packet listeners.
*/
private static final PacketEvent BYPASSED_PACKET = new PacketEvent(ShadedChannelInjector.class);
private static final PacketEvent BYPASSED_PACKET = new PacketEvent(ChannelInjector.class);
// The login packet
private static Class<?> PACKET_LOGIN_CLIENT = null;
@@ -102,16 +81,15 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
// For retrieving the protocol
private static FieldAccessor PROTOCOL_ACCESSOR;
// For retrieving the protocol version
private static MethodAccessor PROTOCOL_VERSION;
// Current version
private static volatile MethodAccessor PROTOCOL_VERSION;
// The factory that created this injector
private ShadedInjectionFactory factory;
private InjectionFactory factory;
// The player, or temporary player
private Player player;
private Player updated;
private String playerName;
// The player connection
private Object playerConnection;
@@ -150,6 +128,9 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
private ByteToMessageDecoder vanillaDecoder;
private MessageToByteEncoder<Object> vanillaEncoder;
// Our extra handlers
private MessageToByteEncoder<Object> protocolEncoder;
private ChannelInboundHandler finishHandler;
private Deque<PacketEvent> finishQueue = new ArrayDeque<PacketEvent>();
// The channel listener
@@ -170,7 +151,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
* @param channelListener - a listener.
* @param factory - the factory that created this injector
*/
public ShadedChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener, ShadedInjectionFactory factory) {
public ChannelInjector(Player player, Object networkManager, Channel channel, ChannelListener channelListener, InjectionFactory factory) {
this.player = Preconditions.checkNotNull(player, "player cannot be NULL");
this.networkManager = Preconditions.checkNotNull(networkManager, "networkMananger cannot be NULL");
this.originalChannel = Preconditions.checkNotNull(channel, "channel cannot be NULL");
@@ -179,29 +160,37 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
this.processor = new NetworkProcessor(ProtocolLibrary.getErrorReporter());
// Get the channel field
this.channelField = new VolatileField(FuzzyReflection.fromObject(networkManager, true).getFieldByType("channel", Channel.class),
networkManager, true);
this.channelField = new VolatileField(
FuzzyReflection.fromObject(networkManager, true).
getFieldByType("channel", Channel.class),
networkManager, true);
}
/**
* Get the version of the current protocol.
* @return The version.
*/
@Spigot(minimumBuild = 1628)
@Override
public int getProtocolVersion() {
MethodAccessor accessor = PROTOCOL_VERSION;
if (accessor == null) {
try {
accessor = Accessors.getMethodAccessor(networkManager.getClass(), "getVersion");
} catch (Throwable ex) {
}
}
if (accessor != null) {
return (Integer) accessor.invoke(networkManager);
} else {
return MinecraftProtocolVersion.getCurrentVersion();
} catch (RuntimeException e) {
// Notify user
ProtocolLibrary.getErrorReporter().reportWarning(
this, Report.newBuilder(REPORT_CANNOT_FIND_GET_VERSION).error(e));
// Fallback method
accessor = Accessors.getConstantAccessor(
MinecraftProtocolVersion.getCurrentVersion(), null);
}
PROTOCOL_VERSION = accessor;
}
return (Integer) accessor.invoke(networkManager);
}
@Override
@@ -229,7 +218,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
}
// Don't inject the same channel twice
if (findChannelHandler(originalChannel, ShadedChannelInjector.class) != null) {
if (findChannelHandler(originalChannel, ChannelInjector.class) != null) {
return false;
}
@@ -251,31 +240,26 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
"encode", ChannelHandlerContext.class, Object.class, ByteBuf.class);
// Intercept sent packets
MessageToByteEncoder<Object> protocolEncoder = new MessageToByteEncoder<Object>() {
protocolEncoder = new MessageToByteEncoder<Object>() {
@Override
protected void encode(ChannelHandlerContext ctx, Object packet, ByteBuf output) throws Exception {
if (packet instanceof WirePacket) {
// Special case for wire format
ShadedChannelInjector.this.encodeWirePacket((WirePacket) packet, new ShadedByteBuf(output));
} else {
ShadedChannelInjector.this.encode(ctx, packet, output);
}
ChannelInjector.this.encode(ctx, packet, output);
}
@Override
public void write(ChannelHandlerContext ctx, Object packet, ChannelPromise promise) throws Exception {
super.write(ctx, packet, promise);
ShadedChannelInjector.this.finalWrite(ctx, packet, promise);
ChannelInjector.this.finalWrite(ctx, packet, promise);
}
};
// Intercept recieved packets
ChannelInboundHandlerAdapter finishHandler = new ChannelInboundHandlerAdapter() {
finishHandler = new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// Execute context first
ctx.fireChannelRead(msg);
ShadedChannelInjector.this.finishRead(ctx, msg);
ChannelInjector.this.finishRead(ctx, msg);
}
};
@@ -285,19 +269,18 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
originalChannel.pipeline().addAfter("encoder", "protocol_lib_encoder", protocolEncoder);
// Intercept all write methods
channelField.setValue(new ShadedChannelProxy(originalChannel, MinecraftReflection.getPacketClass()) {
// Compatibility with Spigot 1.8
private final ShadedPipelineProxy pipelineProxy = new ShadedPipelineProxy(originalChannel.pipeline(), this) {
channelField.setValue(new ChannelProxy(originalChannel, MinecraftReflection.getPacketClass()) {
// Compatibility with Spigot 1.8 protocol hack
private final PipelineProxy pipelineProxy = new PipelineProxy(originalChannel.pipeline(), this) {
@Override
public ChannelPipeline addBefore(String baseName, String name, ChannelHandler handler) {
// Correct the position of the decoder
if ("decoder".equals(baseName)) {
if (super.get("protocol_lib_decoder") != null && guessCompression(handler)) {
if (super.get("protocol_lib_decoder") != null && guessSpigotHandler(handler)) {
super.addBefore("protocol_lib_decoder", name, handler);
return this;
}
}
return super.addBefore(baseName, name, handler);
}
};
@@ -356,7 +339,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
NetworkMarker marker = getMarker(original);
if (marker != null) {
PacketEvent result = new PacketEvent(ShadedChannelInjector.class);
PacketEvent result = new PacketEvent(ChannelInjector.class);
result.setNetworkMarker(marker);
return result;
} else {
@@ -382,13 +365,15 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
}
/**
* Determine if the given object is a compressor or decompressor.
* Determine if the given object is a Spigot channel handler.
* @param handler - object to test.
* @return TRUE if it is, FALSE if not or unknown.
*/
private boolean guessCompression(ChannelHandler handler) {
private boolean guessSpigotHandler(ChannelHandler handler) {
String className = handler != null ? handler.getClass().getCanonicalName() : null;
return className.contains("Compressor") || className.contains("Decompressor");
return "org.spigotmc.SpigotDecompressor".equals(className) ||
"org.spigotmc.SpigotCompressor".equals(className);
}
/**
@@ -397,7 +382,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
* @return The resulting message/packet.
*/
private PacketEvent processSending(Object message) {
return channelListener.onPacketSending(ShadedChannelInjector.this, message, getMarker(message));
return channelListener.onPacketSending(ChannelInjector.this, message, getMarker(message));
}
/**
@@ -418,11 +403,6 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
super.exceptionCaught(ctx, cause);
}
protected void encodeWirePacket(WirePacket packet, WrappedByteBuf output) throws Exception {
packet.writeId(output);
packet.writeBytes(output);
}
/**
* Encode a packet to a byte buffer, taking over for the standard Minecraft encoder.
* @param ctx - the current context.
@@ -541,7 +521,6 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
byteBuffer.resetReaderIndex();
marker = new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, getBytes(byteBuffer));
}
PacketEvent output = channelListener.onPacketReceiving(this, input, marker);
// Handle packet changes
@@ -595,14 +574,13 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
PACKET_LOGIN_CLIENT = loginClass;
}
if (loginClient == null) {
loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true);
loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, GameProfile.class, true);
LOGIN_GAME_PROFILE = loginClient;
}
// See if we are dealing with the login packet
if (loginClass.equals(packetClass)) {
// GameProfile profile = (GameProfile) loginClient.get(packet);
WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet));
GameProfile profile = (GameProfile) loginClient.get(packet);
// Save the channel injector
factory.cacheInjector(profile.getName(), this);
@@ -624,7 +602,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
* @param buffer - the buffer.
* @return The bytes.
*/
private byte[] getBytes(ByteBuf buffer) {
private byte[] getBytes(ByteBuf buffer){
byte[] data = new byte[buffer.readableBytes()];
buffer.readBytes(data);
@@ -674,9 +652,8 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
} else {
MinecraftMethods.getSendPacketMethod().invoke(getPlayerConnection(), packet);
}
} catch (Throwable ex) {
ProtocolLibrary.getErrorReporter().reportWarning(factory.getPlugin(),
Report.newBuilder(REPORT_CANNOT_SEND_PACKET).messageParam(packet, playerName).error(ex).build());
} catch (Exception e) {
throw new RuntimeException("Unable to send server packet " + packet, e);
}
}
@@ -739,10 +716,6 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
@Override
public Player getPlayer() {
if (player == null && playerName != null) {
return Bukkit.getPlayer(playerName);
}
return player;
}
@@ -753,7 +726,6 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
@Override
public void setPlayer(Player player) {
this.player = player;
this.playerName = player.getName();
}
/**
@@ -763,7 +735,6 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
@Override
public void setUpdatedPlayer(Player updated) {
this.updated = updated;
this.playerName = updated.getName();
}
@Override
@@ -804,15 +775,11 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
// we end up with a deadlock. The main thread is waiting for the worker thread to process the task, and
// the worker thread is waiting for the main thread to finish executing PlayerQuitEvent.
//
// TLDR: Concurrency is hard.
// TLDR: Concurrenty is hard.
executeInChannelThread(new Runnable() {
@Override
public void run() {
String[] handlers = new String[] {
"protocol_lib_decoder", "protocol_lib_finish", "protocol_lib_encoder"
};
for (String handler : handlers) {
for (ChannelHandler handler : new ChannelHandler[] { ChannelInjector.this, finishHandler, protocolEncoder }) {
try {
originalChannel.pipeline().remove(handler);
} catch (NoSuchElementException e) {
@@ -824,13 +791,13 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
// Clear cache
factory.invalidate(player);
// Clear player instances
// Should help fix memory leaks
this.player = null;
this.updated = null;
}
}
// dmulloy2 - clear player instances
// Should fix memory leaks
this.player = null;
this.updated = null;
}
/**
@@ -846,7 +813,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
try {
command.run();
} catch (Exception e) {
ProtocolLibrary.getErrorReporter().reportDetailed(ShadedChannelInjector.this,
ProtocolLibrary.getErrorReporter().reportDetailed(ChannelInjector.this,
Report.newBuilder(REPORT_CANNOT_EXECUTE_IN_CHANNEL_THREAD).error(e).build());
}
}
@@ -872,16 +839,16 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
* Represents a socket injector that foreards to the current channel injector.
* @author Kristian
*/
public static class ChannelSocketInjector implements SocketInjector {
private final ShadedChannelInjector injector;
static class ChannelSocketInjector implements SocketInjector {
private final ChannelInjector injector;
public ChannelSocketInjector(ShadedChannelInjector injector) {
public ChannelSocketInjector(ChannelInjector injector) {
this.injector = Preconditions.checkNotNull(injector, "injector cannot be NULL");
}
@Override
public Socket getSocket() throws IllegalAccessException {
return ShadedSocketAdapter.adapt((SocketChannel) injector.originalChannel);
return NettySocketAdaptor.adapt((SocketChannel) injector.originalChannel);
}
@Override
@@ -901,7 +868,7 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
@Override
public Player getPlayer() {
return injector.getPlayer();
return injector.player;
}
@Override
@@ -916,16 +883,11 @@ public class ShadedChannelInjector extends ByteToMessageDecoder implements Chann
@Override
public void setUpdatedPlayer(Player updatedPlayer) {
injector.setPlayer(updatedPlayer);
injector.player = updatedPlayer;
}
public ShadedChannelInjector getChannelInjector() {
public ChannelInjector getChannelInjector() {
return injector;
}
}
@Override
public WrappedChannel getChannel() {
return new ShadedChannel(originalChannel);
}
}
@@ -4,11 +4,12 @@ import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketEvent;
/**
* Represents a listener for received or sent packets.
* @author Kristian
*/
public interface ChannelListener {
interface ChannelListener {
/**
* Invoked when a packet is being sent to the client.
* <p>
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.lang.reflect.Field;
import java.net.SocketAddress;
@@ -37,7 +21,7 @@ import com.comphenix.protocol.reflect.accessors.Accessors;
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
import com.google.common.collect.Maps;
public abstract class ShadedChannelProxy implements Channel {
abstract class ChannelProxy implements Channel {
// Mark that a certain object does not contain a message field
private static final FieldAccessor MARK_NO_MESSAGE = new FieldAccessor() {
@Override
@@ -56,16 +40,15 @@ public abstract class ShadedChannelProxy implements Channel {
protected Class<?> messageClass;
// Event loop proxy
private transient ShadedEventLoopProxy loopProxy;
private transient EventLoopProxy loopProxy;
public ShadedChannelProxy(Channel delegate, Class<?> messageClass) {
public ChannelProxy(Channel delegate, Class<?> messageClass) {
this.delegate = delegate;
this.messageClass = messageClass;
}
/**
* Invoked when a packet is scheduled for transmission in the event loop.
* @param <T> Type
* @param callable - callable to schedule for execution.
* @param packetAccessor - accessor for modifying the packet in the callable.
* @return The callable that will be scheduled, or NULL to cancel.
@@ -113,7 +96,7 @@ public abstract class ShadedChannelProxy implements Channel {
@Override
public EventLoop eventLoop() {
if (loopProxy == null) {
loopProxy = new ShadedEventLoopProxy() {
loopProxy = new EventLoopProxy() {
@Override
protected EventLoop getDelegate() {
return delegate.eventLoop();
@@ -136,7 +119,7 @@ public abstract class ShadedChannelProxy implements Channel {
if (accessor != null) {
Callable<T> result = onMessageScheduled(callable, accessor);;
return result != null ? result : ShadedEventLoopProxy.<T>getEmptyCallable();
return result != null ? result : EventLoopProxy.<T>getEmptyCallable();
}
return callable;
}
@@ -9,7 +9,7 @@ import com.comphenix.protocol.events.NetworkMarker;
* Represents a closed injector.
* @author Kristian
*/
public class ClosedInjector implements Injector {
class ClosedInjector implements Injector {
private Player player;
/**
@@ -1,26 +1,11 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
@@ -30,7 +15,6 @@ import net.minecraft.util.io.netty.channel.ChannelPromise;
import net.minecraft.util.io.netty.channel.EventLoop;
import net.minecraft.util.io.netty.channel.EventLoopGroup;
import net.minecraft.util.io.netty.util.concurrent.EventExecutor;
import net.minecraft.util.io.netty.util.concurrent.Future;
import net.minecraft.util.io.netty.util.concurrent.ProgressivePromise;
import net.minecraft.util.io.netty.util.concurrent.Promise;
import net.minecraft.util.io.netty.util.concurrent.ScheduledFuture;
@@ -39,15 +23,13 @@ import net.minecraft.util.io.netty.util.concurrent.ScheduledFuture;
* An event loop proxy.
* @author Kristian.
*/
abstract class ShadedEventLoopProxy implements EventLoop {
abstract class EventLoopProxy implements EventLoop {
private static final Runnable EMPTY_RUNNABLE = new Runnable() {
@Override
public void run() {
// Do nothing
}
};
private static final Callable<?> EMPTY_CALLABLE = new Callable<Object>() {
@Override
public Object call() throws Exception {
return null;
};
@@ -90,168 +72,137 @@ abstract class ShadedEventLoopProxy implements EventLoop {
*/
protected abstract <T> Callable<T> schedulingCallable(Callable<T> callable);
@Override
public void execute(Runnable command) {
getDelegate().execute(schedulingRunnable(command));
}
@Override
public <T> Future<T> submit(Callable<T> action) {
public <T> net.minecraft.util.io.netty.util.concurrent.Future<T> submit(Callable<T> action) {
return getDelegate().submit(schedulingCallable(action));
}
@Override
public <T> Future<T> submit(Runnable action, T arg1) {
public <T> net.minecraft.util.io.netty.util.concurrent.Future<T> submit(Runnable action, T arg1) {
return getDelegate().submit(schedulingRunnable(action), arg1);
}
@Override
public Future<?> submit(Runnable action) {
public net.minecraft.util.io.netty.util.concurrent.Future<?> submit(Runnable action) {
return getDelegate().submit(schedulingRunnable(action));
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> action, long arg1, TimeUnit arg2) {
return getDelegate().schedule(schedulingCallable(action), arg1, arg2);
}
@Override
public ScheduledFuture<?> schedule(Runnable action, long arg1, TimeUnit arg2) {
return getDelegate().schedule(schedulingRunnable(action), arg1, arg2);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable action, long arg1, long arg2, TimeUnit arg3) {
return getDelegate().scheduleAtFixedRate(schedulingRunnable(action), arg1, arg2, arg3);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable action, long arg1, long arg2, TimeUnit arg3) {
return getDelegate().scheduleWithFixedDelay(schedulingRunnable(action), arg1, arg2, arg3);
}
// Boiler plate:
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return getDelegate().awaitTermination(timeout, unit);
}
@Override
public boolean inEventLoop() {
return getDelegate().inEventLoop();
}
@Override
public boolean inEventLoop(Thread arg0) {
return getDelegate().inEventLoop(arg0);
}
@Override
public boolean isShutdown() {
return getDelegate().isShutdown();
}
@Override
public boolean isTerminated() {
return getDelegate().isTerminated();
}
@Override
public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return getDelegate().invokeAll(tasks);
}
@Override
public <T> List<java.util.concurrent.Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException {
return getDelegate().invokeAll(tasks, timeout, unit);
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException,
ExecutionException {
return getDelegate().invokeAny(tasks);
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return getDelegate().invokeAny(tasks, timeout, unit);
}
@Override
public boolean isShuttingDown() {
return getDelegate().isShuttingDown();
}
@Override
public Iterator<EventExecutor> iterator() {
return getDelegate().iterator();
}
@Override
public <V> Future<V> newFailedFuture(Throwable arg0) {
public <V> net.minecraft.util.io.netty.util.concurrent.Future<V> newFailedFuture(Throwable arg0) {
return getDelegate().newFailedFuture(arg0);
}
@Override
public EventLoop next() {
return ((EventLoopGroup) getDelegate()).next();
return getDelegate().next();
}
@Override
public <V> ProgressivePromise<V> newProgressivePromise() {
return getDelegate().newProgressivePromise();
}
@Override
public <V> Promise<V> newPromise() {
return getDelegate().newPromise();
}
@Override
public <V> Future<V> newSucceededFuture(V arg0) {
public <V> net.minecraft.util.io.netty.util.concurrent.Future<V> newSucceededFuture(V arg0) {
return getDelegate().newSucceededFuture(arg0);
}
@Override
public EventLoopGroup parent() {
return getDelegate().parent();
}
@Override
public ChannelFuture register(Channel arg0, ChannelPromise arg1) {
return getDelegate().register(arg0, arg1);
}
@Override
public ChannelFuture register(Channel arg0) {
return getDelegate().register(arg0);
}
@Override
public Future<?> shutdownGracefully() {
public net.minecraft.util.io.netty.util.concurrent.Future<?> shutdownGracefully() {
return getDelegate().shutdownGracefully();
}
@Override
public Future<?> shutdownGracefully(long arg0, long arg1, TimeUnit arg2) {
public net.minecraft.util.io.netty.util.concurrent.Future<?> shutdownGracefully(long arg0, long arg1, TimeUnit arg2) {
return getDelegate().shutdownGracefully(arg0, arg1, arg2);
}
@Override
public Future<?> terminationFuture() {
public net.minecraft.util.io.netty.util.concurrent.Future<?> terminationFuture() {
return getDelegate().terminationFuture();
}
@Override
@Deprecated
public void shutdown() {
getDelegate().shutdown();
}
@Override
@Deprecated
public List<Runnable> shutdownNow() {
return getDelegate().shutdownNow();
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.util.concurrent.ConcurrentMap;
@@ -26,10 +10,7 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.compat.netty.shaded.ShadedChannelInjector.ChannelSocketInjector;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.netty.ClosedInjector;
import com.comphenix.protocol.injector.netty.Injector;
import com.comphenix.protocol.injector.netty.ChannelInjector.ChannelSocketInjector;
import com.comphenix.protocol.injector.server.SocketInjector;
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
import com.comphenix.protocol.reflect.FuzzyReflection;
@@ -43,7 +24,7 @@ import com.google.common.collect.MapMaker;
* Note that the factory will return {@link ClosedInjector} when the factory is closed.
* @author Kristian
*/
public class ShadedInjectionFactory {
class InjectionFactory {
// This should work as long as the injectors are, uh, injected
private final ConcurrentMap<Player, Injector> playerLookup = new MapMaker().weakKeys().weakValues().makeMap();
private final ConcurrentMap<String, Injector> nameLookup = new MapMaker().weakValues().makeMap();
@@ -54,7 +35,7 @@ public class ShadedInjectionFactory {
// The current plugin
private final Plugin plugin;
public ShadedInjectionFactory(Plugin plugin) {
public InjectionFactory(Plugin plugin) {
this.plugin = plugin;
}
@@ -69,7 +50,7 @@ public class ShadedInjectionFactory {
/**
* Construct or retrieve a channel injector from an existing Bukkit player.
* @param player - the existing Bukkit player.
* @param listener - the listener.
* @param channelListener - the listener.
* @return A new injector, an existing injector associated with this player, or a closed injector.
*/
@Nonnull
@@ -93,14 +74,14 @@ public class ShadedInjectionFactory {
Channel channel = FuzzyReflection.getFieldValue(networkManager, Channel.class, true);
// See if a channel has already been created
injector = (ShadedChannelInjector) ShadedChannelInjector.findChannelHandler(channel, ShadedChannelInjector.class);
injector = (ChannelInjector) ChannelInjector.findChannelHandler(channel, ChannelInjector.class);
if (injector != null) {
// Update the player instance
playerLookup.remove(injector.getPlayer());
injector.setPlayer(player);
} else {
injector = new ShadedChannelInjector(player, networkManager, channel, listener, this);
injector = new ChannelInjector(player, networkManager, channel, listener, this);
}
// Cache injector and return
@@ -112,8 +93,7 @@ public class ShadedInjectionFactory {
* Retrieve a cached injector from a name.
* <p>
* The injector may be NULL if the plugin has been reloaded during a player login.
* @param name - the name.
* @param player - the player.
* @param address - the name.
* @return The cached injector, or a closed injector if it could not be found.
*/
public Injector fromName(String name, Player player) {
@@ -133,18 +113,19 @@ public class ShadedInjectionFactory {
/**
* Construct a new channel injector for the given channel.
* @param channel - the channel.
* @param listener - the listener.
* @param playerFactory - a temporary player creator.
* @param channelListener - the listener.
* @param loader - the current (plugin) class loader.
* @return The channel injector, or a closed injector.
*/
@Nonnull
public Injector fromChannel(Channel channel, ChannelListener listener, TemporaryPlayerFactory playerFactory) {
public Injector fromChannel(Channel channel, ChannelListener listener, TemporaryPlayerFactory playerFactory) {
if (closed)
return new ClosedInjector(null);
Object networkManager = findNetworkManager(channel);
Object networkManager = findNetworkManager(channel);
Player temporaryPlayer = playerFactory.createTemporaryPlayer(Bukkit.getServer());
ShadedChannelInjector injector = new ShadedChannelInjector(temporaryPlayer, networkManager, channel, listener, this);
ChannelInjector injector = new ChannelInjector(temporaryPlayer, networkManager, channel, listener, this);
// Initialize temporary player
TemporaryPlayerFactory.setInjectorInPlayer(temporaryPlayer, new ChannelSocketInjector(injector));
@@ -189,7 +170,7 @@ public class ShadedInjectionFactory {
* @param player - the temporary player, or normal Bukkit player.
* @return The associated injector, or NULL if this is a Bukkit player.
*/
private ShadedChannelInjector getTemporaryInjector(Player player) {
private ChannelInjector getTemporaryInjector(Player player) {
SocketInjector injector = TemporaryPlayerFactory.getInjectorFromPlayer(player);
if (injector != null) {
@@ -205,7 +186,7 @@ public class ShadedInjectionFactory {
*/
private Object findNetworkManager(Channel channel) {
// Find the network manager
Object networkManager = ShadedChannelInjector.findChannelHandler(channel, MinecraftReflection.getNetworkManagerClass());
Object networkManager = ChannelInjector.findChannelHandler(channel, MinecraftReflection.getNetworkManagerClass());
if (networkManager != null)
return networkManager;
@@ -9,7 +9,7 @@ import com.comphenix.protocol.events.NetworkMarker;
* Represents an injected client connection.
* @author Kristian
*/
public interface Injector {
interface Injector {
/**
* Retrieve the current protocol version of the player.
* @return Protocol version.
@@ -10,7 +10,7 @@ import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.NetworkMarker;
public class NettyNetworkMarker extends NetworkMarker {
class NettyNetworkMarker extends NetworkMarker {
public NettyNetworkMarker(@Nonnull ConnectionSide side, byte[] inputBuffer) {
super(side, inputBuffer, null);
}
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.io.InputStream;
import java.lang.reflect.Field;
@@ -36,9 +20,6 @@ import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.compat.netty.ChannelInjector;
import com.comphenix.protocol.compat.netty.ProtocolInjector;
import com.comphenix.protocol.compat.netty.WrappedChannel;
import com.comphenix.protocol.concurrency.PacketTypeSet;
import com.comphenix.protocol.error.ErrorReporter;
import com.comphenix.protocol.error.Report;
@@ -49,9 +30,6 @@ import com.comphenix.protocol.events.NetworkMarker;
import com.comphenix.protocol.events.PacketContainer;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.injector.ListenerInvoker;
import com.comphenix.protocol.injector.netty.ChannelListener;
import com.comphenix.protocol.injector.netty.Injector;
import com.comphenix.protocol.injector.netty.NettyNetworkMarker;
import com.comphenix.protocol.injector.packet.PacketInjector;
import com.comphenix.protocol.injector.packet.PacketRegistry;
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
@@ -63,7 +41,8 @@ import com.comphenix.protocol.reflect.VolatileField;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.Lists;
public class ShadedProtocolInjector implements ProtocolInjector {
public class NettyProtocolInjector implements ChannelListener {
public static final ReportType REPORT_CANNOT_INJECT_INCOMING_CHANNEL = new ReportType("Unable to inject incoming channel %s.");
private volatile boolean injected;
@@ -74,7 +53,7 @@ public class ShadedProtocolInjector implements ProtocolInjector {
private List<VolatileField> bootstrapFields = Lists.newArrayList();
// The channel injector factory
private ShadedInjectionFactory injectionFactory;
private InjectionFactory injectionFactory;
// List of network managers
private volatile List<Object> networkManagers;
@@ -94,8 +73,8 @@ public class ShadedProtocolInjector implements ProtocolInjector {
private ErrorReporter reporter;
private boolean debug;
public ShadedProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter) {
this.injectionFactory = new ShadedInjectionFactory(plugin);
public NettyProtocolInjector(Plugin plugin, ListenerInvoker invoker, ErrorReporter reporter) {
this.injectionFactory = new InjectionFactory(plugin);
this.invoker = invoker;
this.reporter = reporter;
}
@@ -109,7 +88,6 @@ public class ShadedProtocolInjector implements ProtocolInjector {
* Set whether or not the debug mode is enabled.
* @param debug - TRUE if it is, FALSE otherwise.
*/
@Override
public void setDebug(boolean debug) {
this.debug = debug;
}
@@ -117,8 +95,7 @@ public class ShadedProtocolInjector implements ProtocolInjector {
/**
* Inject into the spigot connection class.
*/
@Override
@SuppressWarnings("unchecked")
@SuppressWarnings("unchecked")
public synchronized void inject() {
if (injected)
throw new IllegalStateException("Cannot inject twice.");
@@ -151,10 +128,10 @@ public class ShadedProtocolInjector implements ProtocolInjector {
try {
// This can take a while, so we need to stop the main thread from interfering
synchronized (networkManagers) {
injectionFactory.fromChannel(channel, ShadedProtocolInjector.this, playerFactory).inject();
injectionFactory.fromChannel(channel, NettyProtocolInjector.this, playerFactory).inject();
}
} catch (Exception e) {
reporter.reportDetailed(ShadedProtocolInjector.this, Report.newBuilder(REPORT_CANNOT_INJECT_INCOMING_CHANNEL).
reporter.reportDetailed(NettyProtocolInjector.this, Report.newBuilder(REPORT_CANNOT_INJECT_INCOMING_CHANNEL).
messageParam(channel).error(e));
}
}
@@ -197,7 +174,7 @@ public class ShadedProtocolInjector implements ProtocolInjector {
}
// Synchronize with each list before we attempt to replace them.
field.setValue(new ShadedBootstrapList(list, connectionHandler));
field.setValue(new BootstrapList(list, connectionHandler));
}
injected = true;
@@ -224,7 +201,7 @@ public class ShadedProtocolInjector implements ProtocolInjector {
/**
* Inject our packet handling into a specific player.
* @param player Player to inject into
* @param player
*/
public void injectPlayer(Player player) {
injectionFactory.fromPlayer(player, this).inject();
@@ -250,17 +227,16 @@ public class ShadedProtocolInjector implements ProtocolInjector {
/**
* Clean up any remaning injections.
*/
@Override
public synchronized void close() {
public synchronized void close() {
if (!closed) {
closed = true;
for (VolatileField field : bootstrapFields) {
Object value = field.getValue();
// Undo the processed channels, if any
if (value instanceof ShadedBootstrapList) {
((ShadedBootstrapList) value).close();
// Undo the processed channels, if any
if (value instanceof BootstrapList) {
((BootstrapList) value).close();
}
field.revertValue();
}
@@ -277,7 +253,6 @@ public class ShadedProtocolInjector implements ProtocolInjector {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetQueued(container, injector.getPlayer(), marker);
}
// Don't change anything
return null;
}
@@ -290,7 +265,6 @@ public class ShadedProtocolInjector implements ProtocolInjector {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetReceived(container, injector.getPlayer(), marker);
}
// Don't change anything
return null;
}
@@ -328,10 +302,9 @@ public class ShadedProtocolInjector implements ProtocolInjector {
}
// Server side
@Override
public PlayerInjectionHandler getPlayerInjector() {
return new AbstractPlayerHandler(sendingFilters) {
private ChannelListener listener = ShadedProtocolInjector.this;
private ChannelListener listener = NettyProtocolInjector.this;
@Override
public int getProtocolVersion(Player player) {
@@ -341,8 +314,8 @@ public class ShadedProtocolInjector implements ProtocolInjector {
@Override
public void updatePlayer(Player player) {
injectionFactory.fromPlayer(player, listener).inject();
}
@Override
public void injectPlayer(Player player, ConflictStrategy strategy) {
injectionFactory.fromPlayer(player, listener).inject();
@@ -356,7 +329,7 @@ public class ShadedProtocolInjector implements ProtocolInjector {
@Override
public void addPacketHandler(PacketType type, Set<ListenerOptions> options) {
if (options != null && !type.forceAsync() && !options.contains(ListenerOptions.ASYNC))
if (options != null && !options.contains(ListenerOptions.ASYNC))
mainThreadFilters.addType(type);
super.addPacketHandler(type, options);
}
@@ -400,16 +373,6 @@ public class ShadedProtocolInjector implements ProtocolInjector {
public void handleDisconnect(Player player) {
injectionFactory.fromPlayer(player, listener).close();
}
@Override
public WrappedChannel getChannel(Player player) {
Injector injector = injectionFactory.fromPlayer(player, listener);
if (injector instanceof ChannelInjector) {
return ((ChannelInjector) injector).getChannel();
}
return null;
}
};
}
@@ -418,13 +381,12 @@ public class ShadedProtocolInjector implements ProtocolInjector {
* @return The packet injector.
*/
// Client side
@Override
public PacketInjector getPacketInjector() {
return new AbstractPacketInjector(reveivedFilters) {
@Override
public PacketEvent packetRecieved(PacketContainer packet, Player client, byte[] buffered) {
NetworkMarker marker = buffered != null ? new NettyNetworkMarker(ConnectionSide.CLIENT_SIDE, buffered) : null;
injectionFactory.fromPlayer(client, ShadedProtocolInjector.this).
injectionFactory.fromPlayer(client, NettyProtocolInjector.this).
saveMarker(packet.getHandle(), marker);
return packetReceived(packet, client, marker);
}
@@ -3,15 +3,18 @@ package com.comphenix.protocol.injector.netty;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Protocol;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.injector.packet.MapContainer;
import com.comphenix.protocol.reflect.StructureModifier;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
@@ -20,21 +23,18 @@ import com.google.common.collect.Sets;
* @author Kristian
*/
// TODO: Handle modifications to the BiMap
public abstract class ProtocolRegistry {
public class NettyProtocolRegistry {
/**
* Represents a register we are currently building.
* @author Kristian
*/
protected static class Register {
private static class Register {
// The main lookup table
public BiMap<PacketType, Class<?>> typeToClass = HashBiMap.create();
public volatile Set<PacketType> serverPackets = Sets.newHashSet();
public volatile Set<PacketType> clientPackets = Sets.newHashSet();
public List<MapContainer> containers = Lists.newArrayList();
public Register() {
}
/**
* Determine if the current register is outdated.
* @return TRUE if it is, FALSE otherwise.
@@ -49,12 +49,12 @@ public abstract class ProtocolRegistry {
}
}
protected Class<?> enumProtocol;
private Class<?> enumProtocol;
// Current register
protected volatile Register register;
private volatile Register register;
public ProtocolRegistry() {
public NettyProtocolRegistry() {
enumProtocol = MinecraftReflection.getEnumProtocolClass();
initialize();
}
@@ -106,20 +106,70 @@ public abstract class ProtocolRegistry {
/**
* Load the packet lookup tables in each protocol.
*/
protected abstract void initialize();
protected abstract void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender);
private synchronized void initialize() {
final Object[] protocols = enumProtocol.getEnumConstants();
List<Map<Integer, Class<?>>> serverMaps = Lists.newArrayList();
List<Map<Integer, Class<?>>> clientMaps = Lists.newArrayList();
StructureModifier<Object> modifier = null;
// Result
Register result = new Register();
for (Object protocol : protocols) {
if (modifier == null)
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
StructureModifier<Map<Integer, Class<?>>> maps = modifier.withTarget(protocol).withType(Map.class);
serverMaps.add(maps.read(0));
clientMaps.add(maps.read(1));
}
// Maps we have to occationally check have changed
for (Map<Integer, Class<?>> map : Iterables.concat(serverMaps, clientMaps)) {
result.containers.add(new MapContainer(map));
}
// Heuristic - there are more server packets than client packets
if (sum(clientMaps) > sum(serverMaps)) {
// Swap if this is violated
List<Map<Integer, Class<?>>> temp = serverMaps;
serverMaps = clientMaps;
clientMaps = temp;
}
for (int i = 0; i < protocols.length; i++) {
Enum<?> enumProtocol = (Enum<?>) protocols[i];
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
// Associate known types
associatePackets(result, serverMaps.get(i), equivalent, Sender.SERVER);
associatePackets(result, clientMaps.get(i), equivalent, Sender.CLIENT);
}
// Exchange (thread safe, as we have only one writer)
this.register = result;
}
private void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), PacketType.UNKNOWN_PACKET);
register.typeToClass.put(type, entry.getValue());
if (sender == Sender.SERVER)
register.serverPackets.add(type);
if (sender == Sender.CLIENT)
register.clientPackets.add(type);
}
}
/**
* Retrieve the number of mapping in all the maps.
* @param maps - iterable of maps.
* @return The sum of all the entries.
*/
protected final int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
private int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
int count = 0;
for (Map<Integer, Class<?>> map : maps)
for (Map<Integer, Class<?>> map : maps)
count += map.size();
return count;
}
}
}
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.io.IOException;
import java.io.InputStream;
@@ -24,7 +8,6 @@ import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import net.minecraft.util.io.netty.channel.Channel;
import net.minecraft.util.io.netty.channel.ChannelOption;
import net.minecraft.util.io.netty.channel.socket.SocketChannel;
@@ -36,15 +19,15 @@ import net.minecraft.util.io.netty.channel.socket.SocketChannel;
* {@link UnsupportedOperationException}.
*/
// Thanks MD5. :)
public class ShadedSocketAdapter extends Socket {
class NettySocketAdaptor extends Socket {
private final SocketChannel ch;
private ShadedSocketAdapter(SocketChannel ch) {
private NettySocketAdaptor(SocketChannel ch) {
this.ch = ch;
}
public static ShadedSocketAdapter adapt(SocketChannel ch) {
return new ShadedSocketAdapter(ch);
public static NettySocketAdaptor adapt(SocketChannel ch) {
return new NettySocketAdaptor(ch);
}
@Override
@@ -70,7 +53,7 @@ public class ShadedSocketAdapter extends Socket {
@Override
public boolean equals(Object obj) {
return obj instanceof ShadedSocketAdapter && ch.equals(((ShadedSocketAdapter) obj).ch);
return obj instanceof NettySocketAdaptor && ch.equals(((NettySocketAdaptor) obj).ch);
}
@Override
@@ -1,20 +1,4 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.compat.netty.shaded;
package com.comphenix.protocol.injector.netty;
import java.net.SocketAddress;
import java.util.Iterator;
@@ -34,11 +18,11 @@ import net.minecraft.util.io.netty.util.concurrent.EventExecutorGroup;
* A pipeline proxy.
* @author Kristian
*/
public class ShadedPipelineProxy implements ChannelPipeline {
public class PipelineProxy implements ChannelPipeline {
protected final ChannelPipeline pipeline;
protected final Channel channel;
public ShadedPipelineProxy(ChannelPipeline pipeline, Channel channel) {
public PipelineProxy(ChannelPipeline pipeline, Channel channel) {
this.pipeline = pipeline;
this.channel = channel;
}
@@ -176,16 +160,19 @@ public class ShadedPipelineProxy implements ChannelPipeline {
}
// We have to call the depreciated methods to properly implement the proxy
@SuppressWarnings("deprecation")
@Override
public ChannelFuture deregister() {
return pipeline.deregister();
}
@SuppressWarnings("deprecation")
@Override
public ChannelFuture deregister(ChannelPromise arg0) {
return pipeline.deregister(arg0);
}
@SuppressWarnings("deprecation")
@Override
public ChannelPipeline fireChannelUnregistered() {
pipeline.fireChannelUnregistered();
@@ -1,55 +0,0 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* 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 2 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.injector.netty;
import com.comphenix.protocol.compat.netty.WrappedByteBuf;
/**
* @author dmulloy2
*/
public class WirePacket {
private final int id;
private final byte[] bytes;
public WirePacket(int id, byte[] bytes) {
this.id = id;
this.bytes = bytes;
}
public int getId() {
return id;
}
public byte[] getBytes() {
return bytes;
}
public void writeId(WrappedByteBuf output) {
int i = id;
while ((i & -128) != 0) {
output.writeByte(i & 127 | 128);
i >>>= 7;
}
output.writeByte(i);
}
public void writeBytes(WrappedByteBuf output) {
output.writeBytes(bytes);
}
}
@@ -53,12 +53,11 @@ public class InterceptWritePacket {
this.modifierRest = new WritePacketModifier(reporter, false);
}
// TODO: PacketId should probably do something...
private Class<?> createProxyClass() {
private Class<?> createProxyClass(int packetId) {
// Construct the proxy object
Enhancer ex = EnhancerFactory.getInstance().createEnhancer();
// Attempt to share callback filter
// Attempt to share callback filter
if (filter == null) {
filter = new CallbackFilter() {
@Override
@@ -88,7 +87,7 @@ public class InterceptWritePacket {
if (proxyClass != null) {
// Check that we found the read method
if (!writePacketIntercepted) {
reporter.reportWarning(this,
reporter.reportWarning(this,
Report.newBuilder(REPORT_CANNOT_FIND_WRITE_PACKET_METHOD).
messageParam(MinecraftReflection.getPacketClass()));
}
@@ -102,7 +101,7 @@ public class InterceptWritePacket {
// Concurrent pattern
if (stored == null) {
final Class<?> created = createProxyClass();
final Class<?> created = createProxyClass(packetId);
stored = proxyClasses.putIfAbsent(packetId, created);
// We won!
@@ -116,10 +115,7 @@ public class InterceptWritePacket {
/**
* Construct a new instance of the proxy object.
* @param proxyObject - Object to construct proxy of
* @param event - Packet event
* @param marker - Network marker
* @return New instance of the proxy, or null if we failed.
* @return New instance of proxy, or NULL if we failed.
*/
@SuppressWarnings("deprecation")
public Object constructProxy(Object proxyObject, PacketEvent event, NetworkMarker marker) {
@@ -134,7 +130,7 @@ public class InterceptWritePacket {
return generated;
} catch (Exception e) {
reporter.reportWarning(this,
reporter.reportWarning(this,
Report.newBuilder(REPORT_CANNOT_CONSTRUCT_WRITE_PROXY).
messageParam(proxyClass));
return null;
@@ -1,15 +1,18 @@
package com.comphenix.protocol.injector.packet;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import javax.annotation.Nonnull;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.compat.guava.Guava;
import com.comphenix.protocol.events.ConnectionSide;
import com.comphenix.protocol.events.NetworkMarker;
import com.google.common.io.ByteStreams;
import com.google.common.io.InputSupplier;
import com.google.common.primitives.Bytes;
/**
@@ -37,7 +40,28 @@ public class LegacyNetworkMarker extends NetworkMarker {
}
@Override
@SuppressWarnings("unchecked")
protected DataInputStream addHeader(final DataInputStream input, final PacketType type) {
return Guava.addHeader(input, type);
InputSupplier<InputStream> header = new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
byte[] data = new byte[] { (byte) type.getLegacyId() };
return new ByteArrayInputStream(data);
}
};
InputSupplier<InputStream> data = new InputSupplier<InputStream>() {
@Override
public InputStream getInput() throws IOException {
return input;
}
};
// Combine them into a single stream
try {
return new DataInputStream(ByteStreams.join(header, data).getInput());
} catch (IOException e) {
throw new RuntimeException("Cannot add header.", e);
}
}
}
}
@@ -1,5 +1,7 @@
package com.comphenix.protocol.injector.packet;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.Field;
import com.comphenix.protocol.reflect.FieldUtils;
@@ -10,17 +12,20 @@ import com.comphenix.protocol.reflect.FieldUtils;
*/
public class MapContainer {
// For detecting changes
private Field modCountField;
private final Field modCountField;
private int lastModCount;
// The object along with whether or not this is the initial run
private Object source;
private final Object source;
private boolean changed;
public MapContainer(Object source) {
this.source = source;
this.changed = true;
this.modCountField = FieldUtils.getField(source.getClass(), "modCount", true);
this.changed = false;
Field modCountField = FieldUtils.getField(source.getClass(), "modCount", true);
this.modCountField = checkNotNull(modCountField, "Failed to obtain modCount field");
this.lastModCount = getModificationCount();
}
/**
@@ -55,13 +60,13 @@ public class MapContainer {
/**
* Retrieve the current modification count.
* @return The current count, or something different than lastModCount if not accessible.
* @return The current count
*/
private int getModificationCount() {
try {
return modCountField != null ? modCountField.getInt(source) : lastModCount + 1;
} catch (Exception e) {
throw new RuntimeException("Unable to retrieve modCount.", e);
return modCountField.getInt(source);
} catch (Exception ex) {
throw new RuntimeException("Unable to retrieve modCount.", ex);
}
}
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -25,15 +25,12 @@ import java.util.Set;
import com.comphenix.protocol.PacketType;
import com.comphenix.protocol.PacketType.Sender;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.compat.netty.LegacyProtocolRegistry;
import com.comphenix.protocol.compat.netty.independent.NettyProtocolRegistry;
import com.comphenix.protocol.error.Report;
import com.comphenix.protocol.error.ReportType;
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.InsufficientPacketsException;
import com.comphenix.protocol.reflect.FieldAccessException;
import com.comphenix.protocol.utility.MinecraftReflection;
import com.comphenix.protocol.utility.MinecraftVersion;
import com.comphenix.protocol.wrappers.TroveWrapper.CannotFindTroveNoEntryValue;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
@@ -52,7 +49,7 @@ public class PacketRegistry {
// Two different packet registry
private static volatile LegacyPacketRegistry LEGACY;
private static volatile ProtocolRegistry NETTY;
private static volatile NettyProtocolRegistry NETTY;
// Cached for legacy
private static volatile Set<PacketType> NETTY_SERVER_PACKETS;
@@ -80,17 +77,13 @@ public class PacketRegistry {
// Check for netty
if (MinecraftReflection.isUsingNetty()) {
if (NETTY == null) {
if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
NETTY = new NettyProtocolRegistry();
} else {
NETTY = new LegacyProtocolRegistry();
}
NETTY = new NettyProtocolRegistry();
}
} else {
initializeLegacy();
}
}
/**
* Determine if the given packet type is supported on the current server.
* @param type - the type to check.
@@ -103,7 +96,7 @@ public class PacketRegistry {
return NETTY.getPacketTypeLookup().containsKey(type);
// Look up the correct type
return type.isClient() ?
return type.isClient() ?
LEGACY.getClientPackets().contains(type.getLegacyId()) :
LEGACY.getServerPackets().contains(type.getLegacyId());
}
@@ -127,7 +120,7 @@ public class PacketRegistry {
);
}
} catch (CannotFindTroveNoEntryValue e) {
ProtocolLibrary.getErrorReporter().reportWarning(PacketRegistry.class,
ProtocolLibrary.getErrorReporter().reportWarning(PacketRegistry.class,
Report.newBuilder(REPORT_CANNOT_CORRECT_TROVE_MAP).error(e.getCause()));
}
}
@@ -146,7 +139,6 @@ public class PacketRegistry {
if (NETTY != null) {
@SuppressWarnings("unchecked")
Map<Class, Integer> result = (Map)Maps.transformValues(NETTY.getPacketClassLookup(), new Function<PacketType, Integer>() {
@Override
public Integer apply(PacketType type) {
return type.getLegacyId();
};
@@ -169,7 +161,6 @@ public class PacketRegistry {
return result;
}
return Maps.transformValues(LEGACY.getPacketToID(), new Function<Integer, PacketType>() {
@Override
public PacketType apply(Integer packetId) {
return PacketType.findLegacy(packetId);
};
@@ -297,7 +288,7 @@ public class PacketRegistry {
* @param types - packet type.
* @return Set of integers.
*/
public static Set<Integer> toLegacy(Set<PacketType> types) {
public static Set<Integer> toLegacy(Set<PacketType> types) {
Set<Integer> result = Sets.newHashSet();
for (PacketType type : types)
@@ -307,20 +298,20 @@ public class PacketRegistry {
/**
* Convert a set of legacy packet IDs to packet types.
* @param ids - legacy packet IDs.
* @param types - legacy packet IDs.
* @return Set of packet types.
*/
public static Set<PacketType> toPacketTypes(Set<Integer> ids) {
public static Set<PacketType> toPacketTypes(Set<Integer> ids) {
return toPacketTypes(ids, null);
}
/**
* Convert a set of legacy packet IDs to packet types.
* @param ids - legacy packet IDs.
* @param types - legacy packet IDs.
* @param preference - the sender preference, if any.
* @return Set of packet types.
*/
public static Set<PacketType> toPacketTypes(Set<Integer> ids, Sender preference) {
public static Set<PacketType> toPacketTypes(Set<Integer> ids, Sender preference) {
Set<PacketType> result = Sets.newHashSet();
for (int id : ids)
@@ -426,7 +417,7 @@ public class PacketRegistry {
} else {
final int id = LEGACY.getPacketID(packet);
return PacketType.hasLegacy(id) ?
return PacketType.hasLegacy(id) ?
PacketType.fromLegacy(id, sender) : null;
}
}
@@ -334,7 +334,7 @@ class ProxyPacketInjector implements PacketInjector {
return packetRecieved(packet, client, buffered);
} else {
// The timeout elapsed!
reporter.reportDetailed(this, Report.newBuilder(REPORT_UNKNOWN_ORIGIN_FOR_PACKET).messageParam(input, packet.getType()));
reporter.reportWarning(this, Report.newBuilder(REPORT_UNKNOWN_ORIGIN_FOR_PACKET).messageParam(input, packet.getType()));
return null;
}
@@ -2,16 +2,16 @@
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2012 Kristian S. Stangeland
*
* 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 2 of
* 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 2 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.
* 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
@@ -58,7 +58,7 @@ class NetworkFieldInjector extends PlayerInjector {
// Nothing
}
// After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.),
// After commit 336a4e00668fd2518c41242755ed6b3bdc3b0e6c (Update CraftBukkit to Minecraft 1.4.4.),
// CraftBukkit stopped redirecting map chunk and map chunk bulk packets to a separate queue.
// Thus, NetworkFieldInjector can safely handle every packet (though not perfectly - some packets
// will be slightly processed).
@@ -77,7 +77,9 @@ class NetworkFieldInjector extends PlayerInjector {
// Determine if we're listening
private IntegerSet sendingFilters;
public NetworkFieldInjector(ErrorReporter reporter, Player player, ListenerInvoker manager, IntegerSet sendingFilters) {
public NetworkFieldInjector(ErrorReporter reporter, Player player,
ListenerInvoker manager, IntegerSet sendingFilters) throws IllegalAccessException {
super(reporter, player, manager);
this.sendingFilters = sendingFilters;
}
@@ -176,7 +178,6 @@ class NetworkFieldInjector extends PlayerInjector {
}
}
@Override
@SuppressWarnings("unchecked")
protected void cleanHook() {
// Clean up
Loaded 100 of 214 files, more files were not shown because too many files have changed in this diff. Show more