Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc5caf143d | ||
|
|
35e37121f9 | ||
|
|
86130b5743 | ||
|
|
d5231944b6 | ||
|
|
f042087356 | ||
|
|
d78e00f80f | ||
|
|
421db9f02a | ||
|
|
51a84bbcd1 | ||
|
|
e1715e26b3 | ||
|
|
1e69a116ba | ||
|
|
04c41dc961 | ||
|
|
f1cb43bbc5 |
No files matched your search
@@ -1,38 +0,0 @@
|
||||
Contributing to ProtocolLib
|
||||
===========================
|
||||
This page will detail specific things that must be done if you intend to contribute to this project.
|
||||
|
||||
## Updating ProtocolLib to a New Protocol Version
|
||||
#### Before we get started:
|
||||
1. **When do we need to update the protocol version?**
|
||||
_A Minecraft protocol version is a number for each specification of the Minecraft protocol.
|
||||
This means it is incremented when there is a change to the [Protocol Specification](http://wiki.vg/Protocol),
|
||||
but not necessarily for each Minecraft version update. If the latest Minecraft version contains a protocol change,
|
||||
that means ProtocolLib needs to be updated._
|
||||
2. **When do we need to update other parts of ProtocolLib?**
|
||||
_When the package version guard changes. The package version guard is the version string inserted
|
||||
into the package identifier for CraftBukkit and net.minecraft.server (e.g. v1_9_R2). It is incremented
|
||||
by Spigot if there is a major breaking change in the internal server code. This is to encourage plugins
|
||||
that interact directly with CraftBukkit/nms code to update more specifically. However, since most of
|
||||
ProtocolLib uses reflection, and the structure of packet classes is generally static, one will have
|
||||
to go through the code and change imports from nms/CraftBukkit._
|
||||
|
||||
#### Ready? Let's get started!
|
||||
1. Read the [Protocol Changes](http://wiki.vg/Protocol_History). Always make sure the list is both
|
||||
complete and correct. If you're unsure, don't hesitate to ask in #mcdevs (the people who maintain wiki.vg) on [freenode.net](http://freenode.net)
|
||||
or #spigot on [irc.spi.gt](http://irc.spi.gt) ([webchat](https://irc.spi.gt/iris/?channels=spigot)).
|
||||
2. Search for usages of the now-defunct NMS package guard and change them.
|
||||
3. The class `com.comphenix.protocol.PacketType` contains a list of all the packets. If any packets were added or removed
|
||||
(or had their ID changed), make sure to update this list. If a packet was removed
|
||||
in favor of usage of another packet, instead of removing it, move it to the bottom of the list
|
||||
in its section, add a deprecation warning to it, and redirect it to the packet that replaced it.
|
||||
4. `mvn` in the root directory to build the project.
|
||||
5. If tests fail in the maven build, go through the tests to make sure you removed references to any removed packets
|
||||
and changed the NMS version guards.
|
||||
6. Increment the package version in `com.comphenix.protocol.utility.Constants`.
|
||||
7. `com.comphenix.protocol.ProtocolLibrary` contains several constants that must be updated, including the Minecraft version
|
||||
and the release date.
|
||||
8. `com.comphenix.protocol.utility.MinecraftProtocolVersion` contains a map of all the protocol version integers.
|
||||
If the protocol version has been incremented, add a new line to the map.
|
||||
9. `mvn` in root directory again. If it builds successfully, test on the appropriate version of a Spigot server. If
|
||||
the build fails, debug!
|
||||
@@ -1,2 +0,0 @@
|
||||
github: [dmulloy2]
|
||||
custom: ["https://paypal.me/dmulloy2"]
|
||||
@@ -1,11 +0,0 @@
|
||||
_Follow this template except for feature requests. Use pastebin when providing /protocol dump and any relevant errors._
|
||||
|
||||
Make sure you've done the following:
|
||||
- [ ] You're using the latest build for your server version
|
||||
- [ ] This isn't an issue caused by another plugin
|
||||
- [ ] You've checked for duplicate issues
|
||||
- [ ] You didn't use `/reload`
|
||||
|
||||
Debug paste link:
|
||||
|
||||
Description and relevant errors:
|
||||
@@ -1,29 +0,0 @@
|
||||
---
|
||||
name: API question
|
||||
about: Questions related to using ProtocolLib in your plugins
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Make sure you're doing the following**
|
||||
- [ ] You're using the latest build for your server version
|
||||
- [ ] This isn't an issue caused by another plugin
|
||||
- [ ] You've checked for duplicate issues
|
||||
- [ ] You didn't use `/reload`
|
||||
|
||||
**Describe the question**
|
||||
A clear and concise description of what your question is.
|
||||
|
||||
**API method(s) used**
|
||||
List what API method(s) you're using
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Code**
|
||||
If applicable, add relevant code from your project
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Version Info**
|
||||
Provide your ProtocolLib install info with `/protocol dump` through pastebin.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
+8
-25
@@ -2,25 +2,21 @@
|
||||
## Eclipse
|
||||
#################
|
||||
|
||||
# Generic project files
|
||||
.project
|
||||
.classpath
|
||||
.settings/
|
||||
bin/
|
||||
.idea/
|
||||
*.iml
|
||||
.ipr
|
||||
.iws
|
||||
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/
|
||||
tmp/
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
target/
|
||||
.gitignore
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
@@ -34,12 +30,6 @@ local.properties
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
#################
|
||||
## Maven
|
||||
#################
|
||||
|
||||
target/
|
||||
dependency-reduced-pom.xml
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
@@ -165,18 +155,11 @@ pip-log.txt
|
||||
.coverage
|
||||
.tox
|
||||
|
||||
# Translations
|
||||
#Translations
|
||||
*.mo
|
||||
|
||||
# Mr Developer
|
||||
#Mr Developer
|
||||
.mr.developer.cfg
|
||||
|
||||
# Mac crap
|
||||
.DS_Store
|
||||
|
||||
# Log4J files
|
||||
logs/
|
||||
|
||||
.gradle/
|
||||
build/
|
||||
logs/
|
||||
-11
@@ -1,11 +0,0 @@
|
||||
language: java
|
||||
jdk:
|
||||
- openjdk8
|
||||
script: mvn clean test
|
||||
install: true
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- "dmulloy2@live.com"
|
||||
on_success: change
|
||||
on_failure: always
|
||||
@@ -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
|
||||
@@ -0,0 +1,72 @@
|
||||
<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.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>bukkit-rep</id>
|
||||
<url>http://repo.bukkit.org/content/groups/public</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<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>
|
||||
<resource>
|
||||
<directory>src/main/java</directory>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</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>
|
||||
<url>http://www.gnu.org/licenses/gpl-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
<dependencies>
|
||||
<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>
|
||||
+122
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.itemdisguise;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
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;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
|
||||
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, ConnectionSide.SERVER_SIDE, 0x67, 0x68, 0x3E) {
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
PacketContainer packet = event.getPacket();
|
||||
|
||||
try {
|
||||
// Item packets
|
||||
switch (event.getPacketID()) {
|
||||
case 0x67: // Set slot
|
||||
removeEnchantments(packet.getItemModifier().read(0));
|
||||
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]);
|
||||
}
|
||||
}
|
||||
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, ConnectionSide.CLIENT_SIDE, 0x3) {
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
if (event.getPacketID() == 0x3) {
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
Object[] copy = stack.getEnchantments().keySet().toArray();
|
||||
|
||||
for (Object enchantment : copy) {
|
||||
stack.removeEnchantment((Enchantment) enchantment);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.itemdisguise;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
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(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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
name: ItemDisguiseMod
|
||||
version: 1.0.0
|
||||
description: Change the appearance of inventory items.
|
||||
author: Comphenix
|
||||
website: http://www.comphenix.net/ItemDisguise
|
||||
|
||||
main: com.comphenix.itemdisguise.ItemDisguiseMod
|
||||
depends: [ProtocolLib]
|
||||
database: false
|
||||
|
||||
commands:
|
||||
explosion:
|
||||
description: Creates a fake explosion around the caller.
|
||||
usage: /<command>
|
||||
@@ -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,29 +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>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<parent>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib-Parent</artifactId>
|
||||
<version>v4-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,41 +45,26 @@
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<source>1.6</source>
|
||||
<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>
|
||||
|
||||
<dependencies>
|
||||
<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>
|
||||
</dependencies>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-sign-artifacts</id>
|
||||
+15
-23
@@ -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,6 +101,7 @@ 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();
|
||||
}
|
||||
}
|
||||
+120
-170
@@ -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,212 +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.");
|
||||
|
||||
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) {
|
||||
channel.eventLoop().submit(() -> 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);
|
||||
@@ -239,28 +211,26 @@ 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 receiver - the receiving player, NULL for early login/status packets.
|
||||
* @param channel - the channel that received the packet. Never NULL.
|
||||
* @param reciever - the receiving player, NULL for early login/status packets.
|
||||
* @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.
|
||||
*/
|
||||
public Object onPacketOutAsync(Player receiver, Channel channel, Object packet) {
|
||||
public Object onPacketOutAsync(Player reciever, Channel channel, Object packet) {
|
||||
return packet;
|
||||
}
|
||||
|
||||
@@ -268,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.
|
||||
@@ -277,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, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* 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, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* 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, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* 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, Channel, Object)} will be invoked with this packet.
|
||||
*
|
||||
* 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 channel - the channel to inject.
|
||||
* @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 channel - the channel to inject.
|
||||
* @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) {
|
||||
@@ -423,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);
|
||||
File renamed without changes.
@@ -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
|
||||
@@ -0,0 +1,269 @@
|
||||
<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.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>
|
||||
|
||||
<properties>
|
||||
<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>
|
||||
<testSourceDirectory>src/test/java</testSourceDirectory>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<excludes>
|
||||
<exclude>**/*.java</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
||||
<createDependencyReducedPom>false</createDependencyReducedPom>
|
||||
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>net.sf</pattern>
|
||||
<shadedPattern>com.comphenix.net.sf</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>org.spigotmc:spigot</exclude>
|
||||
<exclude>org.spigotmc:spigot-api</exclude>
|
||||
<exclude>junit:junit</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>2.3.2</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<configuration>
|
||||
<archive>
|
||||
<addMavenDescriptor>false</addMavenDescriptor>
|
||||
</archive>
|
||||
<finalName>${project.name}</finalName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<version>2.5.2</version>
|
||||
<configuration>
|
||||
<threshold>High</threshold>
|
||||
<effort>Default</effort>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>release-sign-artifacts</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>performRelease</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
<version>2.2</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-sources</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<version>2.9</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>attach-javadocs</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
<version>1.4</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>sign-artifacts</id>
|
||||
<phase>verify</phase>
|
||||
<goals>
|
||||
<goal>sign</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<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>
|
||||
<url>http://www.gnu.org/licenses/gpl-2.0.txt</url>
|
||||
<distribution>repo</distribution>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<developers>
|
||||
<developer>
|
||||
<id>dmulloy2</id>
|
||||
<name>Dan Mulloy</name>
|
||||
<url>http://shadowvolt.com/</url>
|
||||
<roles>
|
||||
<role>developer</role>
|
||||
<role>maintainer</role>
|
||||
</roles>
|
||||
</developer>
|
||||
<developer>
|
||||
<id>aadnk</id>
|
||||
<name>Kristian S. Stangeland</name>
|
||||
<email>kr_stang@hotmail.com</email>
|
||||
<url>http://comphenix.net/</url>
|
||||
<roles>
|
||||
<role>former author</role>
|
||||
</roles>
|
||||
<timezone>1</timezone>
|
||||
</developer>
|
||||
</developers>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.comphenix.executors</groupId>
|
||||
<artifactId>BukkitExecutors</artifactId>
|
||||
<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>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<version>1.8.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-module-junit4</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.powermock</groupId>
|
||||
<artifactId>powermock-api-mockito</artifactId>
|
||||
<version>${powermock.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* Ignore this class.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class Application {
|
||||
private static Thread mainThread;
|
||||
private static boolean primaryMethod = true;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// For now, though we might consider making a proper application
|
||||
System.out.println("This is a Bukkit library. Place it in the plugin-folder and restart the server!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are running on the main thread.
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isPrimaryThread() {
|
||||
if (primaryMethod) {
|
||||
try {
|
||||
return Bukkit.isPrimaryThread();
|
||||
} catch (LinkageError e) {
|
||||
primaryMethod = false;
|
||||
}
|
||||
}
|
||||
// Fallback method
|
||||
return Thread.currentThread().equals(mainThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the calling thread as the primary thread.
|
||||
*/
|
||||
static void registerPrimaryThread() {
|
||||
mainThread = Thread.currentThread();
|
||||
}
|
||||
}
|
||||
+45
-25
@@ -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
|
||||
*/
|
||||
|
||||
@@ -42,63 +42,83 @@ public interface AsynchronousManager {
|
||||
* @param listener - the packet listener that will receive these asynchronous events.
|
||||
* @return An asynchronous handler.
|
||||
*/
|
||||
AsyncListenerHandler registerAsyncHandler(PacketListener listener);
|
||||
public abstract AsyncListenerHandler registerAsyncHandler(PacketListener listener);
|
||||
|
||||
/**
|
||||
* Unregisters and closes the given asynchronous handler.
|
||||
* @param handler - asynchronous handler.
|
||||
*/
|
||||
void unregisterAsyncHandler(AsyncListenerHandler handler);
|
||||
public abstract void unregisterAsyncHandler(AsyncListenerHandler handler);
|
||||
|
||||
/**
|
||||
* Unregisters and closes the first asynchronous handler associated with the given listener.
|
||||
* @param listener - asynchronous listener
|
||||
* @param handler - asynchronous handler.
|
||||
*/
|
||||
void unregisterAsyncHandler(PacketListener listener);
|
||||
public abstract void unregisterAsyncHandler(PacketListener listener);
|
||||
|
||||
/**
|
||||
* Unregisters every asynchronous handler associated with this plugin.
|
||||
* @param plugin - the original plugin.
|
||||
*/
|
||||
void unregisterAsyncHandlers(Plugin plugin);
|
||||
public void unregisterAsyncHandlers(Plugin plugin);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @return Every filtered server packet.
|
||||
*/
|
||||
@Deprecated
|
||||
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.
|
||||
*/
|
||||
Set<PacketType> getSendingTypes();
|
||||
|
||||
public abstract Set<PacketType> getSendingTypes();
|
||||
|
||||
/**
|
||||
* Retrieves a immutable set containing the ID of the recieved client packets that will be
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getReceivingTypes()} instead.
|
||||
* observed by the asynchronous listeners.
|
||||
* @return Every filtered client packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract Set<Integer> getReceivingFilters();
|
||||
|
||||
/**
|
||||
* Retrieves a immutable set containing the types of the received client packets that will be
|
||||
* observed by the asynchronous listeners.
|
||||
* @return Every filtered client packet.
|
||||
*/
|
||||
Set<PacketType> getReceivingTypes();
|
||||
public abstract Set<PacketType> getReceivingTypes();
|
||||
|
||||
/**
|
||||
* Determine if a given synchronous packet has asynchronous listeners.
|
||||
* @param packet - packet to test.
|
||||
* @return TRUE if it does, FALSE otherwise.
|
||||
*/
|
||||
boolean hasAsynchronousListeners(PacketEvent packet);
|
||||
public abstract boolean hasAsynchronousListeners(PacketEvent packet);
|
||||
|
||||
/**
|
||||
* Retrieve the default packet stream.
|
||||
* @return Default packet stream.
|
||||
*/
|
||||
PacketStream getPacketStream();
|
||||
public abstract PacketStream getPacketStream();
|
||||
|
||||
/**
|
||||
* Retrieve the default error reporter.
|
||||
* @return Default reporter.
|
||||
*/
|
||||
ErrorReporter getErrorReporter();
|
||||
public abstract ErrorReporter getErrorReporter();
|
||||
|
||||
/**
|
||||
* Remove listeners, close threads and transmit every delayed packet.
|
||||
*/
|
||||
void cleanupAll();
|
||||
public abstract void cleanupAll();
|
||||
|
||||
/**
|
||||
* Signal that a packet is ready to be transmitted.
|
||||
@@ -107,29 +127,29 @@ public interface AsynchronousManager {
|
||||
* has been called previously.
|
||||
* @param packet - packet to signal.
|
||||
*/
|
||||
void signalPacketTransmission(PacketEvent packet);
|
||||
public abstract void signalPacketTransmission(PacketEvent packet);
|
||||
|
||||
/**
|
||||
* Register a synchronous listener that handles packets when they time out.
|
||||
* @param listener - synchronous listener that will handle timed out packets.
|
||||
*/
|
||||
void registerTimeoutHandler(PacketListener listener);
|
||||
public abstract void registerTimeoutHandler(PacketListener listener);
|
||||
|
||||
/**
|
||||
* Unregisters a given timeout listener.
|
||||
* @param listener - the timeout listener to unregister.
|
||||
*/
|
||||
void unregisterTimeoutHandler(PacketListener listener);
|
||||
public abstract void unregisterTimeoutHandler(PacketListener listener);
|
||||
|
||||
/**
|
||||
* Get a immutable set of every registered timeout handler.
|
||||
* @return Set of every registered timeout handler.
|
||||
*/
|
||||
Set<PacketListener> getTimeoutHandlers();
|
||||
public abstract Set<PacketListener> getTimeoutHandlers();
|
||||
|
||||
/**
|
||||
* Get an immutable set of every registered asynchronous packet listener.
|
||||
* @return Set of every asynchronous packet listener.
|
||||
*/
|
||||
Set<PacketListener> getAsyncHandlers();
|
||||
}
|
||||
public abstract Set<PacketListener> getAsyncHandlers();
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.comphenix.protocol.async.AsyncListenerHandler;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.injector.server.AbstractInputStreamLookup;
|
||||
import com.comphenix.protocol.injector.server.TemporaryPlayerFactory;
|
||||
import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.MethodUtils;
|
||||
import com.comphenix.protocol.reflect.ObjectWriter;
|
||||
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
||||
import com.comphenix.protocol.reflect.compiler.StructureCompiler;
|
||||
import com.comphenix.protocol.reflect.instances.CollectionGenerator;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.reflect.instances.PrimitiveGenerator;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
|
||||
|
||||
/**
|
||||
* Used to fix ClassLoader leaks that may lead to filling up the permanent generation.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
class CleanupStaticMembers {
|
||||
// Reports
|
||||
public final static ReportType REPORT_CANNOT_RESET_FIELD = new ReportType("Unable to reset field %s: %s");
|
||||
public final static ReportType REPORT_CANNOT_UNLOAD_CLASS = new ReportType("Unable to unload class %s.");
|
||||
|
||||
private ClassLoader loader;
|
||||
private ErrorReporter reporter;
|
||||
|
||||
public CleanupStaticMembers(ClassLoader loader, ErrorReporter reporter) {
|
||||
this.loader = loader;
|
||||
this.reporter = reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the previous ClassLoader is not leaking.
|
||||
*/
|
||||
public void resetAll() {
|
||||
// This list must always be updated
|
||||
@SuppressWarnings("deprecation")
|
||||
Class<?>[] publicClasses = {
|
||||
AsyncListenerHandler.class, ListeningWhitelist.class, PacketContainer.class,
|
||||
BukkitUnwrapper.class, DefaultInstances.class, CollectionGenerator.class,
|
||||
PrimitiveGenerator.class, FuzzyReflection.class, MethodUtils.class,
|
||||
BackgroundCompiler.class, StructureCompiler.class,
|
||||
ObjectWriter.class, Packets.Server.class, Packets.Client.class,
|
||||
ChunkPosition.class, WrappedDataWatcher.class, WrappedWatchableObject.class,
|
||||
AbstractInputStreamLookup.class, TemporaryPlayerFactory.class, SpigotPacketInjector.class,
|
||||
MinecraftReflection.class, NbtBinarySerializer.class
|
||||
};
|
||||
|
||||
String[] internalClasses = {
|
||||
"com.comphenix.protocol.events.SerializedOfflinePlayer",
|
||||
"com.comphenix.protocol.injector.player.InjectedServerConnection",
|
||||
"com.comphenix.protocol.injector.player.NetworkFieldInjector",
|
||||
"com.comphenix.protocol.injector.player.NetworkObjectInjector",
|
||||
"com.comphenix.protocol.injector.player.NetworkServerInjector",
|
||||
"com.comphenix.protocol.injector.player.PlayerInjector",
|
||||
"com.comphenix.protocol.injector.EntityUtilities",
|
||||
"com.comphenix.protocol.injector.packet.PacketRegistry",
|
||||
"com.comphenix.protocol.injector.packet.PacketInjector",
|
||||
"com.comphenix.protocol.injector.packet.ReadPacketModifier",
|
||||
"com.comphenix.protocol.injector.StructureCache",
|
||||
"com.comphenix.protocol.reflect.compiler.BoxingHelper",
|
||||
"com.comphenix.protocol.reflect.compiler.MethodDescriptor",
|
||||
"com.comphenix.protocol.wrappers.nbt.WrappedElement",
|
||||
};
|
||||
|
||||
resetClasses(publicClasses);
|
||||
resetClasses(getClasses(loader, internalClasses));
|
||||
}
|
||||
|
||||
private void resetClasses(Class<?>[] classes) {
|
||||
// Reset each class one by one
|
||||
for (Class<?> clazz : classes) {
|
||||
resetClass(clazz);
|
||||
}
|
||||
}
|
||||
|
||||
private void resetClass(Class<?> clazz) {
|
||||
for (Field field : clazz.getFields()) {
|
||||
Class<?> type = field.getType();
|
||||
|
||||
// Only check static non-primitive fields. We also skip strings.
|
||||
if (Modifier.isStatic(field.getModifiers()) &&
|
||||
!type.isPrimitive() && !type.equals(String.class) &&
|
||||
!type.equals(ReportType.class)) {
|
||||
|
||||
try {
|
||||
setFinalStatic(field, null);
|
||||
} catch (IllegalAccessException e) {
|
||||
// Just inform the player
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_CANNOT_RESET_FIELD).error(e).messageParam(field.getName(), e.getMessage())
|
||||
);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// HACK! HAACK!
|
||||
private static void setFinalStatic(Field field, Object newValue) throws IllegalAccessException {
|
||||
int modifier = field.getModifiers();
|
||||
boolean isFinal = Modifier.isFinal(modifier);
|
||||
|
||||
Field modifiersField = isFinal ? FieldUtils.getField(Field.class, "modifiers", true) : null;
|
||||
|
||||
// We have to remove the final field first
|
||||
if (isFinal) {
|
||||
FieldUtils.writeField(modifiersField, field, modifier & ~Modifier.FINAL, true);
|
||||
}
|
||||
|
||||
// Now we can safely modify the field
|
||||
FieldUtils.writeStaticField(field, newValue, true);
|
||||
|
||||
// Revert modifier
|
||||
if (isFinal) {
|
||||
FieldUtils.writeField(modifiersField, field, modifier, true);
|
||||
}
|
||||
}
|
||||
|
||||
private Class<?>[] getClasses(ClassLoader loader, String[] names) {
|
||||
List<Class<?>> output = new ArrayList<Class<?>>();
|
||||
|
||||
for (String name : names) {
|
||||
try {
|
||||
output.add(loader.loadClass(name));
|
||||
} catch (ClassNotFoundException e) {
|
||||
// Warn the user
|
||||
reporter.reportWarning(this, Report.newBuilder(REPORT_CANNOT_UNLOAD_CLASS).error(e).messageParam(name));
|
||||
}
|
||||
}
|
||||
|
||||
return output.toArray(new Class<?>[0]);
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -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;
|
||||
}
|
||||
+4
-3
@@ -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)
|
||||
);
|
||||
}
|
||||
+71
-3
@@ -29,12 +29,13 @@ import java.util.WeakHashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.sf.cglib.proxy.Factory;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.utility.ByteBuddyGenerated;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.concurrency.PacketTypeSet;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
@@ -76,6 +77,11 @@ class CommandPacket extends CommandBase {
|
||||
*/
|
||||
public static final int PAGE_LINE_COUNT = 9;
|
||||
|
||||
/**
|
||||
* Number of bytes before we do a hex dump.
|
||||
*/
|
||||
private static final int HEX_DUMP_THRESHOLD = 256;
|
||||
|
||||
private Plugin plugin;
|
||||
private Logger logger;
|
||||
private ProtocolManager manager;
|
||||
@@ -365,7 +371,7 @@ class CommandPacket extends CommandBase {
|
||||
logger.info("Initial packet:\n" + original + " -> ");
|
||||
}
|
||||
|
||||
logger.info(shortDescription + ":\n" + HexDumper.getPacketDescription(
|
||||
logger.info(shortDescription + ":\n" + getPacketDescription(
|
||||
event.getPacket())
|
||||
);
|
||||
} catch (IllegalAccessException e) {
|
||||
@@ -422,7 +428,7 @@ class CommandPacket extends CommandBase {
|
||||
*/
|
||||
private void savePacketState(PacketEvent event) {
|
||||
try {
|
||||
originalPackets.put(event, HexDumper.getPacketDescription(event.getPacket()));
|
||||
originalPackets.put(event, getPacketDescription(event.getPacket()));
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Cannot read packet.", e);
|
||||
}
|
||||
@@ -444,6 +450,68 @@ class CommandPacket extends CommandBase {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a detailed string representation of the given packet.
|
||||
* @param packetContainer - the packet to describe.
|
||||
* @return The detailed description.
|
||||
* @throws IllegalAccessException An error occured.
|
||||
*/
|
||||
public String getPacketDescription(PacketContainer packetContainer) throws IllegalAccessException {
|
||||
Object packet = packetContainer.getHandle();
|
||||
Class<?> clazz = packet.getClass();
|
||||
|
||||
// Get the first Minecraft super class
|
||||
while (clazz != null && clazz != Object.class &&
|
||||
(!MinecraftReflection.isMinecraftClass(clazz) ||
|
||||
Factory.class.isAssignableFrom(clazz))) {
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
|
||||
return PrettyPrinter.printObject(packet, clazz, MinecraftReflection.getPacketClass(), PrettyPrinter.RECURSE_DEPTH, new ObjectPrinter() {
|
||||
@Override
|
||||
public boolean print(StringBuilder output, Object value) {
|
||||
// Special case
|
||||
if (value instanceof byte[]) {
|
||||
byte[] data = (byte[]) value;
|
||||
|
||||
if (data.length > HEX_DUMP_THRESHOLD) {
|
||||
output.append("[");
|
||||
HexDumper.defaultDumper().appendTo(output, data);
|
||||
output.append("]");
|
||||
return true;
|
||||
}
|
||||
} else if (value != null) {
|
||||
EquivalentConverter<Object> converter = findConverter(value.getClass());
|
||||
|
||||
if (converter != null) {
|
||||
output.append(converter.getSpecific(value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the closest equivalent converter to a specific class.
|
||||
* @param clazz - the class.
|
||||
* @return The closest converter, or NULL if not found,
|
||||
*/
|
||||
private EquivalentConverter<Object> findConverter(Class<?> clazz) {
|
||||
Map<Class<?>, EquivalentConverter<Object>> converters = BukkitConverters.getConvertersForGeneric();
|
||||
|
||||
while (clazz != null) {
|
||||
EquivalentConverter<Object> result = converters.get(clazz);
|
||||
|
||||
if (result != null)
|
||||
return result;
|
||||
else
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public PacketListener updatePacketListener() {
|
||||
if (listener != null) {
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.timing.TimedListenerManager;
|
||||
import com.comphenix.protocol.timing.TimingReportGenerator;
|
||||
|
||||
/**
|
||||
* Handles the "protocol" administration command.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
class CommandProtocol extends CommandBase {
|
||||
/**
|
||||
* Name of this command.
|
||||
*/
|
||||
public static final String NAME = "protocol";
|
||||
|
||||
private Plugin plugin;
|
||||
private ProtocolConfig config;
|
||||
|
||||
public CommandProtocol(ErrorReporter reporter, Plugin plugin, ProtocolConfig config) {
|
||||
super(reporter, CommandBase.PERMISSION_ADMIN, NAME, 1);
|
||||
this.plugin = plugin;
|
||||
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"))
|
||||
reloadConfiguration(sender);
|
||||
else if (subCommand.equalsIgnoreCase("timings"))
|
||||
toggleTimings(sender, args);
|
||||
else if (subCommand.equalsIgnoreCase("listeners"))
|
||||
printListeners(sender, args);
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Display every listener on the server
|
||||
private void printListeners(final CommandSender sender, String[] args) {
|
||||
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
|
||||
|
||||
for (PacketListener listener : manager.getPacketListeners()) {
|
||||
sender.sendMessage(ChatColor.GOLD + "Packet listeners:");
|
||||
sender.sendMessage(ChatColor.GOLD + " " + listener);
|
||||
}
|
||||
// Along with every asynchronous listener
|
||||
for (PacketListener listener : manager.getAsynchronousManager().getAsyncHandlers()) {
|
||||
sender.sendMessage(ChatColor.GOLD + "Asynchronous listeners:");
|
||||
sender.sendMessage(ChatColor.GOLD + " " + listener);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
sender.sendMessage(ChatColor.RED + "Specify a state: ON or OFF.");
|
||||
return;
|
||||
}
|
||||
} else if (args.length > 2) {
|
||||
sender.sendMessage(ChatColor.RED + "Too many parameters.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Now change the state
|
||||
if (state) {
|
||||
if (manager.startTiming())
|
||||
sender.sendMessage(ChatColor.GOLD + "Started timing packet listeners.");
|
||||
else
|
||||
sender.sendMessage(ChatColor.RED + "Packet timing already started.");
|
||||
} else {
|
||||
if (manager.stopTiming()) {
|
||||
saveTimings(manager);
|
||||
sender.sendMessage(ChatColor.GOLD + "Stopped and saved result in plugin folder.");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "Packet timing already stopped.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
*/
|
||||
public void updateFinished() {
|
||||
long currentTime = System.currentTimeMillis() / ProtocolLibrary.MILLI_PER_SECOND;
|
||||
|
||||
config.setAutoLastTime(currentTime);
|
||||
config.saveAll();
|
||||
}
|
||||
|
||||
public void reloadConfiguration(CommandSender sender) {
|
||||
plugin.reloadConfig();
|
||||
sender.sendMessage(ChatColor.YELLOW + "Reloaded configuration!");
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+8
-25
@@ -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;
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,951 @@
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
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;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
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), so you cannot
|
||||
* rely on IDs alone.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
// Increment whenever the type changes
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Represents an unknown legacy packet ID.
|
||||
*/
|
||||
public static final int UNKNOWN_PACKET = -1;
|
||||
|
||||
/**
|
||||
* Packets sent during handshake.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Handshake {
|
||||
private static final Protocol PROTOCOL = Protocol.HANDSHAKING;
|
||||
|
||||
/**
|
||||
* Incoming packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Client extends ObjectEnum<PacketType> {
|
||||
private final static Sender SENDER = Sender.CLIENT;
|
||||
/**
|
||||
* Legacy name: HANDSHAKE.
|
||||
*/
|
||||
public static final PacketType SET_PROTOCOL = new PacketType(PROTOCOL, SENDER, 0x00, 2);
|
||||
|
||||
private final static Client INSTANCE = new Client();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Client() { super(PacketType.class); }
|
||||
|
||||
public static Client getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An empty enum, as the server will not send any packets in this protocol.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Server extends ObjectEnum<PacketType> {
|
||||
private final static Sender SENDER = Sender.CLIENT;
|
||||
private final static Server INSTANCE = new Server();
|
||||
private Server() { super(PacketType.class); }
|
||||
|
||||
public static Server getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
}
|
||||
|
||||
public static Protocol getProtocol() {
|
||||
return PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packets sent and received when logged into the game.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Play {
|
||||
private static final Protocol PROTOCOL = Protocol.PLAY;
|
||||
|
||||
/**
|
||||
* Outgoing packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Server() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Server getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
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);
|
||||
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();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Client() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Client getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public static Protocol getProtocol() {
|
||||
return PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packets sent and received when querying the server in the multiplayer menu.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Status {
|
||||
private static final Protocol PROTOCOL = Protocol.STATUS;
|
||||
|
||||
/**
|
||||
* Outgoing packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
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);
|
||||
@SuppressWarnings("deprecation")
|
||||
public static final PacketType OUT_PING = new PacketType(PROTOCOL, SENDER, 0x01, Packets.Server.PING_TIME);
|
||||
|
||||
private final static Server INSTANCE = new Server();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Server() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Server getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
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);
|
||||
@SuppressWarnings("deprecation")
|
||||
public static final PacketType IN_PING = new PacketType(PROTOCOL, SENDER, 0x01, Packets.Client.PING_TIME);
|
||||
|
||||
private final static Client INSTANCE = new Client();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Client() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Client getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public static Protocol getProtocol() {
|
||||
return PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Packets sent and received when logging in to the server.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Login {
|
||||
private static final Protocol PROTOCOL = Protocol.LOGIN;
|
||||
|
||||
/**
|
||||
* Outgoing packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
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);
|
||||
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();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Server() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Server getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Client extends ObjectEnum<PacketType> {
|
||||
private final static Sender SENDER = Sender.CLIENT;
|
||||
|
||||
@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();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Client() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Client getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public static Protocol getProtocol() {
|
||||
return PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains every packet Minecraft 1.6.4 packet removed in Minecraft 1.7.2.
|
||||
* @author Kristian
|
||||
*/
|
||||
public static class Legacy {
|
||||
private static final Protocol PROTOCOL = Protocol.LEGACY;
|
||||
|
||||
/**
|
||||
* Outgoing packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
// Missing server packets: [10, 11, 12, 21, 107, 252]
|
||||
public static class Server extends ObjectEnum<PacketType> {
|
||||
private final static Sender SENDER = Sender.SERVER;
|
||||
|
||||
public static final PacketType PLAYER_FLYING = PacketType.newLegacy(SENDER, 10);
|
||||
public static final PacketType PLAYER_POSITION = PacketType.newLegacy(SENDER, 11);
|
||||
public static final PacketType PLAYER_POSITON_LOOK = PacketType.newLegacy(SENDER, 12);
|
||||
/**
|
||||
* Removed in Minecraft 1.4.6.
|
||||
*/
|
||||
public static final PacketType PICKUP_SPAWN = PacketType.newLegacy(SENDER, 21);
|
||||
/**
|
||||
* Removed in Minecraft 1.7.2
|
||||
*/
|
||||
public static final PacketType SET_CREATIVE_SLOT = PacketType.newLegacy(SENDER, 107);
|
||||
|
||||
/**
|
||||
* Removed in Minecraft 1.7.2
|
||||
*/
|
||||
public static final PacketType KEY_RESPONSE = PacketType.newLegacy(SENDER, 252);
|
||||
|
||||
private final static Server INSTANCE = new Server();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Server() {
|
||||
super(PacketType.class);
|
||||
}
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Server getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Incoming packets.
|
||||
* @author Kristian
|
||||
*/
|
||||
// Missing client packets: [1, 9, 255]
|
||||
public static class Client extends ObjectEnum<PacketType> {
|
||||
private final static Sender SENDER = Sender.CLIENT;
|
||||
|
||||
public static final PacketType LOGIN = PacketType.newLegacy(SENDER, 1);
|
||||
public static final PacketType RESPAWN = PacketType.newLegacy(SENDER, 9);
|
||||
public static final PacketType DISCONNECT = PacketType.newLegacy(SENDER, 255);
|
||||
|
||||
private final static Client INSTANCE = new Client();
|
||||
|
||||
// Prevent accidental construction
|
||||
private Client() { super(PacketType.class); }
|
||||
|
||||
public static Sender getSender() {
|
||||
return SENDER;
|
||||
}
|
||||
public static Client getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
public static Protocol getProtocol() {
|
||||
return PROTOCOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the different protocol or connection states.
|
||||
* @author Kristian
|
||||
*/
|
||||
public enum Protocol {
|
||||
HANDSHAKING,
|
||||
PLAY,
|
||||
STATUS,
|
||||
LOGIN,
|
||||
|
||||
/**
|
||||
* Only for packets removed in Minecraft 1.7.2
|
||||
*/
|
||||
LEGACY;
|
||||
|
||||
/**
|
||||
* Retrieve the correct protocol enum from a given vanilla enum instance.
|
||||
* @param vanilla - the vanilla protocol enum instance.
|
||||
* @return The corresponding protocol.
|
||||
*/
|
||||
public static Protocol fromVanilla(Enum<?> vanilla) {
|
||||
String name = vanilla.name();
|
||||
|
||||
if ("HANDSHAKING".equals(name))
|
||||
return HANDSHAKING;
|
||||
if ("PLAY".equals(name))
|
||||
return PLAY;
|
||||
if ("STATUS".equals(name))
|
||||
return STATUS;
|
||||
if ("LOGIN".equals(name))
|
||||
return LOGIN;
|
||||
throw new IllegalArgumentException("Unrecognized vanilla enum " + vanilla);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the sender of this packet type.
|
||||
* @author Kristian
|
||||
*
|
||||
*/
|
||||
public enum Sender {
|
||||
/**
|
||||
* Indicates that packets of this type will be sent by connected clients.
|
||||
*/
|
||||
CLIENT,
|
||||
|
||||
/**
|
||||
* Indicate that packets of this type will be sent by the current server.
|
||||
*/
|
||||
SERVER;
|
||||
|
||||
/**
|
||||
* Retrieve the equivialent connection side.
|
||||
* @return The connection side.
|
||||
*/
|
||||
public ConnectionSide toSide() {
|
||||
return this == CLIENT ? ConnectionSide.CLIENT_SIDE : ConnectionSide.SERVER_SIDE;
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup of packet types
|
||||
private static PacketTypeLookup LOOKUP;
|
||||
|
||||
/**
|
||||
* Protocol version of all the current IDs.
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Retrieve the current packet/legacy lookup.
|
||||
* @return The packet type lookup.
|
||||
*/
|
||||
private static PacketTypeLookup getLookup() {
|
||||
if (LOOKUP == null) {
|
||||
LOOKUP = new PacketTypeLookup().
|
||||
addPacketTypes(Handshake.Client.getInstance()).
|
||||
addPacketTypes(Handshake.Server.getInstance()).
|
||||
addPacketTypes(Play.Client.getInstance()).
|
||||
addPacketTypes(Play.Server.getInstance()).
|
||||
addPacketTypes(Status.Client.getInstance()).
|
||||
addPacketTypes(Status.Server.getInstance()).
|
||||
addPacketTypes(Login.Client.getInstance()).
|
||||
addPacketTypes(Login.Server.getInstance()).
|
||||
addPacketTypes(Legacy.Client.getInstance()).
|
||||
addPacketTypes(Legacy.Server.getInstance());
|
||||
}
|
||||
return LOOKUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find every packet type known to the current version of ProtocolLib.
|
||||
* @return Every packet type.
|
||||
*/
|
||||
public static Iterable<PacketType> values() {
|
||||
List<Iterable<? extends PacketType>> sources = Lists.newArrayList();
|
||||
sources.add(Handshake.Client.getInstance());
|
||||
sources.add(Handshake.Server.getInstance());
|
||||
sources.add(Play.Client.getInstance());
|
||||
sources.add(Play.Server.getInstance());
|
||||
sources.add(Status.Client.getInstance());
|
||||
sources.add(Status.Server.getInstance());
|
||||
sources.add(Login.Client.getInstance());
|
||||
sources.add(Login.Server.getInstance());
|
||||
|
||||
// Add the missing types in earlier versions
|
||||
if (!MinecraftReflection.isUsingNetty()) {
|
||||
sources.add(Legacy.Client.getInstance());
|
||||
sources.add(Legacy.Server.getInstance());
|
||||
}
|
||||
return Iterables.concat(sources);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a packet type from a legacy (1.6.4 and below) packet ID.
|
||||
* @param packetId - the legacy packet ID.
|
||||
* @return The corresponding packet type.
|
||||
* @throws IllegalArgumentException If the legacy packet could not be found.
|
||||
*/
|
||||
public static PacketType findLegacy(int packetId) {
|
||||
PacketType type = getLookup().getFromLegacy(packetId);
|
||||
|
||||
if (type != null)
|
||||
return type;
|
||||
throw new IllegalArgumentException("Cannot find legacy packet " + packetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a packet type from a legacy (1.6.4 and below) packet ID.
|
||||
* @param packetId - the legacy packet ID.
|
||||
* @param preference - the preferred sender, or NULL for any arbitrary sender.
|
||||
* @return The corresponding packet type.
|
||||
* @throws IllegalArgumentException If the legacy packet could not be found.
|
||||
*/
|
||||
public static PacketType findLegacy(int packetId, Sender preference) {
|
||||
if (preference == null)
|
||||
return findLegacy(packetId);
|
||||
PacketType type = getLookup().getFromLegacy(packetId, preference);
|
||||
|
||||
if (type != null)
|
||||
return type;
|
||||
throw new IllegalArgumentException("Cannot find legacy packet " + packetId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return getLookup().getFromLegacy(packetId) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a packet type from a protocol, sender and packet ID.
|
||||
* <p>
|
||||
* It is usually better to access the packet types statically, like so:
|
||||
* <ul>
|
||||
* <li>{@link PacketType.Play.Server#SPAWN_ENTITY}
|
||||
* </ul>
|
||||
* @param protocol - the current protocol.
|
||||
* @param sender - the sender.
|
||||
* @param packetId - the packet ID.
|
||||
* @return The corresponding packet type.
|
||||
* @throws IllegalArgumentException If the current packet could not be found.
|
||||
*/
|
||||
public static PacketType findCurrent(Protocol protocol, Sender sender, int packetId) {
|
||||
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
|
||||
|
||||
if (type != null)
|
||||
return type;
|
||||
throw new IllegalArgumentException("Cannot find packet " + packetId +
|
||||
"(Protocol: " + protocol + ", Sender: " + sender + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public static boolean hasCurrent(Protocol protocol, Sender sender, int packetId) {
|
||||
return getLookup().getFromCurrent(protocol, sender, packetId) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a packet type from a legacy ID.
|
||||
* <p>
|
||||
* If no associated packet type could be found, a new will be registered under LEGACY.
|
||||
* @param id - the legacy ID.
|
||||
* @param sender - the sender of the packet, or NULL if unknown.
|
||||
* @return The packet type.
|
||||
* @throws IllegalArgumentException If the sender is NULL and the packet doesn't exist.
|
||||
*/
|
||||
public static PacketType fromLegacy(int id, Sender sender) {
|
||||
PacketType type = getLookup().getFromLegacy(id, sender);
|
||||
|
||||
if (type == null) {
|
||||
if (sender == null)
|
||||
throw new IllegalArgumentException("Cannot find legacy packet " + id);
|
||||
type = newLegacy(sender, id);
|
||||
|
||||
// As below
|
||||
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 legacyId - the legacy packet ID. Can be UNKNOWN_PACKET.
|
||||
* @return The corresponding packet type.
|
||||
*/
|
||||
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, legacyId);
|
||||
|
||||
// Many may be scheduled, but only the first will be executed
|
||||
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a packet type from a packet class.
|
||||
* @param packetClass - the packet class.
|
||||
* @return The corresponding packet type, or NULL if not found.
|
||||
*/
|
||||
public static PacketType fromClass(Class<?> packetClass) {
|
||||
PacketType type = PacketRegistry.getPacketType(packetClass);
|
||||
|
||||
if (type != null)
|
||||
return type;
|
||||
throw new IllegalArgumentException("Class " + packetClass + " is not a registered packet.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every packet type with the given UPPER_CAMEL_CASE name.
|
||||
* <p>
|
||||
* Note that the collection is unmodiable.
|
||||
* @param name - the name.
|
||||
* @return Every packet type, or an empty collection.
|
||||
*/
|
||||
public static Collection<PacketType> fromName(String name) {
|
||||
return getLookup().getFromName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given class represents a packet class.
|
||||
* @param packetClass - the class to lookup.
|
||||
* @return TRUE if this is a packet class, FALSE otherwise.
|
||||
*/
|
||||
public static boolean hasClass(Class<?> packetClass) {
|
||||
return PacketRegistry.getPacketType(packetClass) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a particular packet type.
|
||||
* <p>
|
||||
* Note that the registration will be performed on the main thread.
|
||||
* @param type - the type to register.
|
||||
* @param name - the name of the packet.
|
||||
* @return A future telling us if our instance was registered.
|
||||
*/
|
||||
public static Future<Boolean> scheduleRegister(final PacketType type, final String name) {
|
||||
Callable<Boolean> callable = new Callable<Boolean>() {
|
||||
@Override
|
||||
public Boolean call() throws Exception {
|
||||
ObjectEnum<PacketType> objEnum;
|
||||
|
||||
// A bit ugly, but performance is critical
|
||||
objEnum = getObjectEnum(type);
|
||||
|
||||
if (objEnum.registerMember(type, name)) {
|
||||
getLookup().addPacketTypes(Arrays.asList(type));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Execute in the main thread if possible
|
||||
if (Bukkit.getServer() == null || Application.isPrimaryThread()) {
|
||||
try {
|
||||
return Futures.immediateFuture(callable.call());
|
||||
} catch (Exception e) {
|
||||
return Futures.immediateFailedFuture(e);
|
||||
}
|
||||
}
|
||||
return ProtocolLibrary.getExecutorSync().submit(callable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the correct object enum from a specific packet type.
|
||||
* @param type - the packet type.
|
||||
* @return The corresponding object enum.
|
||||
*/
|
||||
public static ObjectEnum<PacketType> getObjectEnum(final PacketType type) {
|
||||
switch (type.getProtocol()) {
|
||||
case HANDSHAKING:
|
||||
return type.isClient() ? Handshake.Client.getInstance() : Handshake.Server.getInstance();
|
||||
case PLAY:
|
||||
return type.isClient() ? Play.Client.getInstance() : Play.Server.getInstance();
|
||||
case STATUS:
|
||||
return type.isClient() ? Status.Client.getInstance() : Status.Server.getInstance();
|
||||
case LOGIN:
|
||||
return type.isClient() ? Login.Client.getInstance() : Login.Server.getInstance();
|
||||
case LEGACY:
|
||||
return type.isClient() ? Legacy.Client.getInstance() : Legacy.Server.getInstance();
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected protocol: " + type.getProtocol());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new packet type.
|
||||
* @param protocol - the current protocol.
|
||||
* @param sender - client or server.
|
||||
* @param currentId - the current packet ID, or
|
||||
* @param legacyId - the legacy packet ID.
|
||||
*/
|
||||
public PacketType(Protocol protocol, Sender sender, int currentId, int legacyId) {
|
||||
this(protocol, sender, currentId, legacyId, PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new packet type.
|
||||
* @param protocol - the current protocol.
|
||||
* @param sender - client or server.
|
||||
* @param currentId - the current packet ID.
|
||||
* @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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a legacy packet type.
|
||||
* @param sender - client or server.
|
||||
* @param legacyId - the legacy packet ID.
|
||||
*/
|
||||
public static PacketType newLegacy(Sender sender, int legacyId) {
|
||||
return new PacketType(Protocol.LEGACY, sender, PacketType.UNKNOWN_PACKET, legacyId, MinecraftVersion.WORLD_UPDATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this packet is supported on the current server.
|
||||
* @return Whether or not the packet is supported.
|
||||
*/
|
||||
public boolean isSupported() {
|
||||
return PacketRegistry.isSupported(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the protocol (the connection state) the packet type belongs.
|
||||
* @return The protocol of this type.
|
||||
*/
|
||||
public Protocol getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve which sender will transmit packets of this type.
|
||||
* @return The sender of these packets.
|
||||
*/
|
||||
public Sender getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this packet was sent by the client.
|
||||
* @return TRUE if it was, FALSE otherwise.
|
||||
*/
|
||||
public boolean isClient() {
|
||||
return sender == Sender.CLIENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this packet was sent by the server.
|
||||
* @return TRUE if it was, FALSE otherwise.
|
||||
*/
|
||||
public boolean isServer() {
|
||||
return sender == Sender.SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current protocol ID for this packet type.
|
||||
* <p>
|
||||
* This is only unique within a specific protocol and target.
|
||||
* <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.
|
||||
*/
|
||||
public int getCurrentId() {
|
||||
return currentId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the equivalent packet class.
|
||||
* @return The packet class, or NULL if not found.
|
||||
*/
|
||||
public Class<?> getPacketClass() {
|
||||
try {
|
||||
return PacketRegistry.getPacketClassFromType(this);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the declared enum name of this packet type.
|
||||
* @return The enum name.
|
||||
*/
|
||||
public String name() {
|
||||
return getObjectEnum(this).getDeclaredName(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the Minecraft version for the current ID.
|
||||
* @return The Minecraft version.
|
||||
*/
|
||||
public MinecraftVersion getCurrentVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the legacy (1.6.4 or below) protocol ID of the packet type.
|
||||
* <p>
|
||||
* This ID is globally unique.
|
||||
* @return The legacy ID, or {@link #UNKNOWN_PACKET} if unknown.
|
||||
*/
|
||||
public int getLegacyId() {
|
||||
return legacyId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(protocol, sender, currentId, legacyId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
if (obj instanceof PacketType) {
|
||||
PacketType other = (PacketType) obj;
|
||||
return protocol == other.protocol &&
|
||||
sender == other.sender &&
|
||||
currentId == other.currentId &&
|
||||
legacyId == other.legacyId;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PacketType other) {
|
||||
return ComparisonChain.start().
|
||||
compare(protocol, other.getProtocol()).
|
||||
compare(sender, other.getSender()).
|
||||
compare(currentId, other.getCurrentId()).
|
||||
compare(legacyId, other.getLegacyId()).
|
||||
result();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
Class<?> clazz = getPacketClass();;
|
||||
|
||||
if (clazz == null)
|
||||
return "UNREGISTERED [" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + "]";
|
||||
else
|
||||
return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]";
|
||||
}
|
||||
}
|
||||
+16
-54
@@ -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.
|
||||
@@ -105,11 +67,21 @@ class PacketTypeLookup {
|
||||
Preconditions.checkNotNull(types, "types cannot be NULL");
|
||||
|
||||
for (PacketType type : types) {
|
||||
int legacy = type.getLegacyId();
|
||||
|
||||
// Skip unknown legacy packets
|
||||
if (legacy != PacketType.UNKNOWN_PACKET) {
|
||||
if (type.isServer())
|
||||
serverLookup.put(type.getLegacyId(), type);
|
||||
if (type.isClient())
|
||||
clientLookup.put(type.getLegacyId(), type);
|
||||
legacyLookup.put(type.getLegacyId(), type);
|
||||
}
|
||||
// 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;
|
||||
@@ -160,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);
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -4,20 +4,19 @@ import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.ConnectionSide;
|
||||
import com.google.common.collect.ContiguousSet;
|
||||
import com.google.common.collect.DiscreteDomain;
|
||||
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 = Range.closed(0, 255);
|
||||
public final static Range<Integer> DEFAULT_MAX_RANGE = Ranges.closed(0, 255);
|
||||
|
||||
private Sender side = null;
|
||||
private Protocol protocol = null;
|
||||
@@ -54,7 +53,7 @@ class PacketTypeParser {
|
||||
// And finally, parse packet names if we have a protocol
|
||||
if (protocol != null) {
|
||||
for (Iterator<String> it = arguments.iterator(); it.hasNext(); ) {
|
||||
String name = it.next().toUpperCase(Locale.ENGLISH);
|
||||
String name = it.next().toUpperCase();
|
||||
Collection<PacketType> names = PacketType.fromName(name);
|
||||
|
||||
for (PacketType type : names) {
|
||||
@@ -73,7 +72,7 @@ class PacketTypeParser {
|
||||
}
|
||||
|
||||
for (Range<Integer> range : ranges) {
|
||||
for (Integer id : ContiguousSet.create(range, DiscreteDomain.integers())) {
|
||||
for (Integer id : range.asSet(DiscreteDomains.integers())) {
|
||||
// Deprecated packets
|
||||
if (protocol == null) {
|
||||
if (PacketType.hasLegacy(id)) {
|
||||
@@ -144,5 +143,5 @@ class PacketTypeParser {
|
||||
return Protocol.STATUS;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,346 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.IntEnum;
|
||||
|
||||
/**
|
||||
* List of known packet IDs since 1.3.2.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @author Kristian
|
||||
*/
|
||||
@Deprecated
|
||||
public final class Packets {
|
||||
|
||||
/**
|
||||
* The highest possible packet ID. It's unlikely that this value will ever change.
|
||||
*/
|
||||
public static final int MAXIMUM_PACKET_ID = 255;
|
||||
|
||||
/**
|
||||
* The maximum number of unique packet IDs. It's unlikely this will ever change.
|
||||
*/
|
||||
public static final int PACKET_COUNT = 256;
|
||||
|
||||
/**
|
||||
* List of packets sent only by the server.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @author Kristian
|
||||
*/
|
||||
@Deprecated
|
||||
public static final class Server extends IntEnum {
|
||||
/**
|
||||
* The singleton instance. Can also be retrieved from the parent class.
|
||||
*/
|
||||
private static Server INSTANCE = new Server();
|
||||
|
||||
public static final int KEEP_ALIVE = 0;
|
||||
public static final int LOGIN = 1;
|
||||
public static final int CHAT = 3;
|
||||
public static final int UPDATE_TIME = 4;
|
||||
public static final int ENTITY_EQUIPMENT = 5;
|
||||
public static final int SPAWN_POSITION = 6;
|
||||
public static final int UPDATE_HEALTH = 8;
|
||||
public static final int RESPAWN = 9;
|
||||
public static final int FLYING = 10;
|
||||
public static final int PLAYER_POSITION = 11;
|
||||
public static final int PLAYER_LOOK = 12;
|
||||
public static final int PLAYER_LOOK_MOVE = 13;
|
||||
/**
|
||||
* Made bi-directional in 1.4.6.
|
||||
*/
|
||||
public static final int BLOCK_ITEM_SWITCH = 16;
|
||||
public static final int ENTITY_LOCATION_ACTION = 17;
|
||||
public static final int ARM_ANIMATION = 18;
|
||||
public static final int NAMED_ENTITY_SPAWN = 20;
|
||||
/**
|
||||
* Removed in 1.4.6 and replaced with VEHICLE_SPAWN.
|
||||
* @see <a href="http://www.wiki.vg/Protocol_History#2012-12-20">Protocol History - MinecraftCoalition</a>
|
||||
*/
|
||||
@Deprecated()
|
||||
public static final int PICKUP_SPAWN = 21;
|
||||
public static final int COLLECT = 22;
|
||||
public static final int VEHICLE_SPAWN = 23;
|
||||
public static final int MOB_SPAWN = 24;
|
||||
public static final int ENTITY_PAINTING = 25;
|
||||
public static final int ADD_EXP_ORB = 26;
|
||||
public static final int ENTITY_VELOCITY = 28;
|
||||
public static final int DESTROY_ENTITY = 29;
|
||||
public static final int ENTITY = 30;
|
||||
public static final int REL_ENTITY_MOVE = 31;
|
||||
public static final int ENTITY_LOOK = 32;
|
||||
public static final int REL_ENTITY_MOVE_LOOK = 33;
|
||||
public static final int ENTITY_TELEPORT = 34;
|
||||
public static final int ENTITY_HEAD_ROTATION = 35;
|
||||
public static final int ENTITY_STATUS = 38;
|
||||
public static final int ATTACH_ENTITY = 39;
|
||||
|
||||
/**
|
||||
* Sent when an entities DataWatcher is updated.
|
||||
* <p>
|
||||
* Remember to clone the packet if you are modifying it.
|
||||
*/
|
||||
public static final int ENTITY_METADATA = 40;
|
||||
public static final int MOB_EFFECT = 41;
|
||||
public static final int REMOVE_MOB_EFFECT = 42;
|
||||
public static final int SET_EXPERIENCE = 43;
|
||||
public static final int UPDATE_ATTRIBUTES = 44;
|
||||
public static final int MAP_CHUNK = 51;
|
||||
public static final int MULTI_BLOCK_CHANGE = 52;
|
||||
public static final int BLOCK_CHANGE = 53;
|
||||
public static final int PLAY_NOTE_BLOCK = 54;
|
||||
public static final int BLOCK_BREAK_ANIMATION = 55;
|
||||
public static final int MAP_CHUNK_BULK = 56;
|
||||
public static final int EXPLOSION = 60;
|
||||
public static final int WORLD_EVENT = 61;
|
||||
public static final int NAMED_SOUND_EFFECT = 62;
|
||||
public static final int WORLD_PARTICLES = 63;
|
||||
public static final int BED = 70;
|
||||
public static final int WEATHER = 71;
|
||||
public static final int OPEN_WINDOW = 100;
|
||||
public static final int CLOSE_WINDOW = 101;
|
||||
public static final int SET_SLOT = 103;
|
||||
public static final int WINDOW_ITEMS = 104;
|
||||
public static final int CRAFT_PROGRESS_BAR = 105;
|
||||
public static final int TRANSACTION = 106;
|
||||
public static final int SET_CREATIVE_SLOT = 107;
|
||||
public static final int UPDATE_SIGN = 130;
|
||||
public static final int ITEM_DATA = 131;
|
||||
|
||||
/**
|
||||
* Sent the first time a tile entity (chest inventory, etc.) is withing range of the player, or has been updated.
|
||||
* <p>
|
||||
* Remember to clone the packet if you are modifying it.
|
||||
*/
|
||||
public static final int TILE_ENTITY_DATA = 132;
|
||||
public static final int OPEN_TILE_ENTITY = 133;
|
||||
public static final int STATISTIC = 200;
|
||||
public static final int PLAYER_INFO = 201;
|
||||
public static final int ABILITIES = 202;
|
||||
public static final int TAB_COMPLETE = 203;
|
||||
public static final int SCOREBOARD_OBJECTIVE = 206;
|
||||
public static final int UPDATE_SCORE = 207;
|
||||
public static final int DISPLAY_SCOREBOARD = 208;
|
||||
public static final int TEAMS = 209;
|
||||
public static final int CUSTOM_PAYLOAD = 250;
|
||||
public static final int KEY_RESPONSE = 252;
|
||||
public static final int KEY_REQUEST = 253;
|
||||
public static final int KICK_DISCONNECT = 255;
|
||||
|
||||
/**
|
||||
* This packet was introduced in 1.7.2.
|
||||
*/
|
||||
public static final int PING_TIME = 230;
|
||||
|
||||
/**
|
||||
* This packet was introduced in 1.7.2.
|
||||
*/
|
||||
public static final int LOGIN_SUCCESS = 232;
|
||||
|
||||
/**
|
||||
* A registry that parses between names and packet IDs.
|
||||
* @return The current server registry.
|
||||
*/
|
||||
public static Server getRegistry() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given packet is a valid server packet in the current version of Minecraft.
|
||||
* <p>
|
||||
* Use {@link PacketType#isSupported()} instead.
|
||||
* @param packetID - the packet to test.
|
||||
* @return TRUE if this packet is supported, FALSE otherwise.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isSupported(int packetID) throws FieldAccessException {
|
||||
return PacketFilterManager.getServerPackets().contains(packetID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every client packet the current version of Minecraft is aware of.
|
||||
* @return Every supported server packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Set<Integer> getSupported() throws FieldAccessException {
|
||||
return PacketFilterManager.getServerPackets();
|
||||
}
|
||||
|
||||
// We only allow a single instance of this class
|
||||
private Server() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List of packets sent by the client.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @author Kristian
|
||||
*/
|
||||
@Deprecated
|
||||
public static class Client extends IntEnum {
|
||||
/**
|
||||
* The singleton instance. Can also be retrieved from the parent class.
|
||||
*/
|
||||
private static Client INSTANCE = new Client();
|
||||
|
||||
public static final int KEEP_ALIVE = 0;
|
||||
public static final int LOGIN = 1;
|
||||
public static final int HANDSHAKE = 2;
|
||||
public static final int CHAT = 3;
|
||||
public static final int USE_ENTITY = 7;
|
||||
|
||||
/**
|
||||
* Since 1.3.1, the client no longer sends a respawn packet. Moved to CLIENT_COMMAND.
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int RESPAWN = 9;
|
||||
|
||||
public static final int FLYING = 10;
|
||||
public static final int PLAYER_POSITION = 11;
|
||||
public static final int PLAYER_LOOK = 12;
|
||||
public static final int PLAYER_LOOK_MOVE = 13;
|
||||
public static final int BLOCK_DIG = 14;
|
||||
public static final int PLACE = 15;
|
||||
public static final int BLOCK_ITEM_SWITCH = 16;
|
||||
public static final int ARM_ANIMATION = 18;
|
||||
public static final int ENTITY_ACTION = 19;
|
||||
public static final int PLAYER_INPUT = 27;
|
||||
public static final int CLOSE_WINDOW = 101;
|
||||
public static final int WINDOW_CLICK = 102;
|
||||
public static final int TRANSACTION = 106;
|
||||
public static final int SET_CREATIVE_SLOT = 107;
|
||||
public static final int BUTTON_CLICK = 108;
|
||||
public static final int UPDATE_SIGN = 130;
|
||||
public static final int ABILITIES = 202;
|
||||
public static final int TAB_COMPLETE = 203;
|
||||
public static final int LOCALE_AND_VIEW_DISTANCE = 204;
|
||||
public static final int CLIENT_COMMAND = 205;
|
||||
public static final int CUSTOM_PAYLOAD = 250;
|
||||
public static final int KEY_RESPONSE = 252;
|
||||
public static final int GET_INFO = 254;
|
||||
public static final int KICK_DISCONNECT = 255;
|
||||
|
||||
/**
|
||||
* This packet was introduced in 1.7.2.
|
||||
*/
|
||||
public static final int PING_TIME = 230;
|
||||
|
||||
/**
|
||||
* This packet was introduced in 1.7.2.
|
||||
*/
|
||||
public static final int LOGIN_START = 231;
|
||||
|
||||
/**
|
||||
* A registry that parses between names and packet IDs.
|
||||
* @return The current client registry.
|
||||
*/
|
||||
public static Client getRegistry() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given packet is a valid client packet in the current version of Minecraft.
|
||||
* @param packetID - the packet to test.
|
||||
* @return TRUE if this packet is supported, FALSE otherwise.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
public static boolean isSupported(int packetID) throws FieldAccessException {
|
||||
return PacketFilterManager.getClientPackets().contains(packetID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every client packet the current version of Minecraft is aware of.
|
||||
* @return Every supported client packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
public static Set<Integer> getSupported() throws FieldAccessException {
|
||||
return PacketFilterManager.getClientPackets();
|
||||
}
|
||||
|
||||
// Like above
|
||||
private Client() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A registry that parses between names and packet IDs.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @return The current client registry.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Server getServerRegistry() {
|
||||
return Server.getRegistry();
|
||||
}
|
||||
|
||||
/**
|
||||
* A registry that parses between names and packet IDs.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @return The current server registry.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Client getClientRegistry() {
|
||||
return Client.INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a packet by name. Must be capitalized and use underscores.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @param name - name of packet to find.
|
||||
* @return The packet ID found.
|
||||
*/
|
||||
@Deprecated
|
||||
public static int valueOf(String name) {
|
||||
Integer serverAttempt = Server.INSTANCE.valueOf(name);
|
||||
|
||||
if (serverAttempt != null)
|
||||
return serverAttempt;
|
||||
else
|
||||
return Client.INSTANCE.valueOf(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the name of a packet.
|
||||
* <p>
|
||||
* Deprecated: Use {@link PacketType} instead.
|
||||
* @param packetID - packet to retrieve name.
|
||||
* @return The name, or NULL if unable to find such a packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getDeclaredName(int packetID) {
|
||||
String serverAttempt = Server.INSTANCE.getDeclaredName(packetID);
|
||||
|
||||
if (serverAttempt != null)
|
||||
return serverAttempt;
|
||||
else
|
||||
return Client.INSTANCE.getDeclaredName(packetID);
|
||||
}
|
||||
}
|
||||
+79
-125
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
@@ -14,19 +14,18 @@
|
||||
* 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 java.util.Locale;
|
||||
|
||||
import org.bukkit.configuration.Configuration;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.injector.PlayerInjectHooks;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Lists;
|
||||
@@ -39,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.
|
||||
*/
|
||||
@@ -90,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));
|
||||
@@ -116,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) {
|
||||
@@ -158,29 +157,25 @@ public class ProtocolConfig {
|
||||
}
|
||||
if (global != null) {
|
||||
updater = global.getConfigurationSection(SECTION_AUTOUPDATER);
|
||||
if (updater.getValues(true).isEmpty()) {
|
||||
plugin.getLogger().warning("Updater section is missing, regenerate your config!");
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
@@ -190,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, false);
|
||||
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) {
|
||||
@@ -315,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) {
|
||||
@@ -337,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.
|
||||
*/
|
||||
@@ -358,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>
|
||||
@@ -379,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() {
|
||||
@@ -413,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)
|
||||
hook = PlayerInjectHooks.valueOf(text.toUpperCase(Locale.ENGLISH).replace(" ", "_"));
|
||||
|
||||
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.
|
||||
*/
|
||||
@@ -496,7 +450,7 @@ public class ProtocolConfig {
|
||||
saveLastUpdate(lastUpdateTime);
|
||||
if (configChanged)
|
||||
plugin.saveConfig();
|
||||
|
||||
|
||||
// And we're done
|
||||
valuesChanged = false;
|
||||
configChanged = false;
|
||||
+147
-138
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
@@ -14,6 +14,7 @@
|
||||
* 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;
|
||||
@@ -26,36 +27,40 @@ import java.util.logging.Logger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.comphenix.executors.BukkitExecutors;
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.*;
|
||||
import com.comphenix.protocol.error.BasicErrorReporter;
|
||||
import com.comphenix.protocol.error.DelegatedErrorReporter;
|
||||
import com.comphenix.protocol.error.DetailedErrorReporter;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.DelayedSingleTask;
|
||||
import com.comphenix.protocol.injector.InternalManager;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.injector.PlayerInjectHooks;
|
||||
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.ByteBuddyFactory;
|
||||
import com.comphenix.protocol.utility.EnhancerFactory;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
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;
|
||||
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
|
||||
|
||||
/**
|
||||
* The main entry point for ProtocolLib.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class ProtocolLib extends JavaPlugin {
|
||||
public class ProtocolLibrary extends JavaPlugin {
|
||||
// Every possible error or warning report type
|
||||
public static final ReportType REPORT_CANNOT_LOAD_CONFIG = new ReportType("Cannot load configuration");
|
||||
public static final ReportType REPORT_CANNOT_DELETE_CONFIG = new ReportType("Cannot delete old ProtocolLib configuration.");
|
||||
@@ -74,16 +79,26 @@ public class ProtocolLib extends JavaPlugin {
|
||||
public static final ReportType REPORT_CANNOT_CREATE_TIMEOUT_TASK = new ReportType("Unable to create packet timeout task.");
|
||||
public static final ReportType REPORT_CANNOT_UPDATE_PLUGIN = new ReportType("Cannot perform automatic updates.");
|
||||
|
||||
// Update information
|
||||
static final String BUKKIT_DEV_SLUG = "protocollib";
|
||||
static final int BUKKIT_DEV_ID = 45564;
|
||||
/**
|
||||
* The minimum version ProtocolLib has been tested with.
|
||||
*/
|
||||
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.7.10";
|
||||
|
||||
/**
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version was released.
|
||||
*/
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2013-12-10";
|
||||
|
||||
// Different commands
|
||||
private enum ProtocolCommand {
|
||||
FILTER,
|
||||
PACKET,
|
||||
PROTOCOL,
|
||||
LOGGING;
|
||||
PROTOCOL
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,6 +120,10 @@ public class ProtocolLib extends JavaPlugin {
|
||||
// Metrics and statistics
|
||||
private Statistics statistics;
|
||||
|
||||
// Executors
|
||||
private static ListeningScheduledExecutorService executorAsync;
|
||||
private static ListeningScheduledExecutorService executorSync;
|
||||
|
||||
// Structure compiler
|
||||
private BackgroundCompiler backgroundCompiler;
|
||||
|
||||
@@ -120,40 +139,35 @@ public class ProtocolLib extends JavaPlugin {
|
||||
// Settings/options
|
||||
private int configExpectedMod = -1;
|
||||
|
||||
// Updater
|
||||
private Updater updater;
|
||||
public static boolean UPDATES_DISABLED;
|
||||
|
||||
// Logger
|
||||
private static Logger logger;
|
||||
private Logger logger;
|
||||
private Handler redirectHandler;
|
||||
|
||||
// Commands
|
||||
private CommandProtocol commandProtocol;
|
||||
private CommandPacket commandPacket;
|
||||
private CommandFilter commandFilter;
|
||||
private PacketLogging packetLogging;
|
||||
|
||||
// Whether or not disable is not needed
|
||||
private boolean skipDisable;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Logging
|
||||
logger = getLogger();
|
||||
ProtocolLogger.init(this);
|
||||
// Load configuration
|
||||
logger = getLoggerSafely();
|
||||
Application.registerPrimaryThread();
|
||||
|
||||
// Initialize enhancer factory
|
||||
ByteBuddyFactory.getInstance().setClassLoader(getClassLoader());
|
||||
EnhancerFactory.getInstance().setClassLoader(getClassLoader());
|
||||
|
||||
// Initialize executors
|
||||
executorAsync = BukkitExecutors.newAsynchronous(this);
|
||||
executorSync = BukkitExecutors.newSynchronous(this);
|
||||
|
||||
// Add global parameters
|
||||
DetailedErrorReporter detailedReporter = new DetailedErrorReporter(this);
|
||||
reporter = getFilteredReporter(detailedReporter);
|
||||
|
||||
// Configuration
|
||||
saveDefaultConfig();
|
||||
reloadConfig();
|
||||
|
||||
try {
|
||||
config = new ProtocolConfig(this);
|
||||
} catch (Exception e) {
|
||||
@@ -184,21 +198,8 @@ public class ProtocolLib 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();
|
||||
|
||||
// Initialize the API
|
||||
ProtocolLibrary.init(this, config, protocolManager, reporter);
|
||||
protocolManager = PacketFilterManager.newBuilder().classLoader(getClassLoader()).server(getServer()).library(this).minecraftVersion(version).unhookTask(unhookTask).reporter(reporter).build();
|
||||
|
||||
// Setup error reporter
|
||||
detailedReporter.addGlobalParameter("manager", protocolManager);
|
||||
@@ -222,6 +223,8 @@ public class ProtocolLib extends JavaPlugin {
|
||||
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (ThreadDeath e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_LOAD_ERROR).error(e).callerParam(protocolManager));
|
||||
disablePlugin();
|
||||
@@ -237,7 +240,7 @@ public class ProtocolLib 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);
|
||||
@@ -245,17 +248,13 @@ public class ProtocolLib extends JavaPlugin {
|
||||
case PACKET:
|
||||
commandPacket = new CommandPacket(reporter, this, logger, commandFilter, protocolManager);
|
||||
break;
|
||||
case LOGGING:
|
||||
packetLogging = new PacketLogging(this, protocolManager);
|
||||
break;
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (LinkageError e) {
|
||||
logger.warning("Failed to register command " + command.name() + ": " + e);
|
||||
} catch (ThreadDeath e) {
|
||||
throw 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,26 +346,19 @@ public class ProtocolLib 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);
|
||||
@@ -381,7 +373,6 @@ public class ProtocolLib extends JavaPlugin {
|
||||
registerCommand(CommandProtocol.NAME, commandProtocol);
|
||||
registerCommand(CommandPacket.NAME, commandPacket);
|
||||
registerCommand(CommandFilter.NAME, commandFilter);
|
||||
registerCommand(PacketLogging.NAME, packetLogging);
|
||||
|
||||
// Player login and logout events
|
||||
protocolManager.registerEvents(manager, this);
|
||||
@@ -389,8 +380,11 @@ public class ProtocolLib 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) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
reporter.reportDetailed(this, Report.newBuilder(REPORT_PLUGIN_ENABLE_ERROR).error(e));
|
||||
disablePlugin();
|
||||
@@ -404,6 +398,8 @@ public class ProtocolLib extends JavaPlugin {
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (ThreadDeath e) {
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
reporter.reportDetailed(this, Report.newBuilder(REPORT_METRICS_IO_ERROR).error(e).callerParam(statistics));
|
||||
} catch (Throwable e) {
|
||||
@@ -411,28 +407,10 @@ public class ProtocolLib extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
// Plugin authors: Notify me to remove these
|
||||
|
||||
private void checkForIncompatibility(PluginManager manager) {
|
||||
for (String plugin : ProtocolLibrary.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(ProtocolLibrary.MINIMUM_MINECRAFT_VERSION);
|
||||
MinecraftVersion maximum = new MinecraftVersion(ProtocolLibrary.MAXIMUM_MINECRAFT_VERSION);
|
||||
MinecraftVersion minimum = new MinecraftVersion(MINIMUM_MINECRAFT_VERSION);
|
||||
MinecraftVersion maximum = new MinecraftVersion(MAXIMUM_MINECRAFT_VERSION);
|
||||
|
||||
try {
|
||||
MinecraftVersion current = new MinecraftVersion(getServer());
|
||||
@@ -445,8 +423,8 @@ public class ProtocolLib 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));
|
||||
|
||||
@@ -457,7 +435,7 @@ public class ProtocolLib 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
|
||||
@@ -465,29 +443,26 @@ public class ProtocolLib 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 : candidates) {
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -496,9 +471,7 @@ public class ProtocolLib 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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,11 +484,11 @@ public class ProtocolLib 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));
|
||||
}
|
||||
@@ -544,15 +517,12 @@ public class ProtocolLib 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) {
|
||||
throw e;
|
||||
} catch (ThreadDeath e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
if (packetTask == -1) {
|
||||
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_CREATE_TIMEOUT_TASK).error(e));
|
||||
@@ -569,29 +539,6 @@ public class ProtocolLib 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) {
|
||||
@@ -629,6 +576,52 @@ public class ProtocolLib extends JavaPlugin {
|
||||
reporter = new BasicErrorReporter();
|
||||
}
|
||||
|
||||
// Get the Bukkit logger first, before we try to create our own
|
||||
private Logger getLoggerSafely() {
|
||||
Logger log = null;
|
||||
|
||||
try {
|
||||
log = getLogger();
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (ThreadDeath e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Use the default logger instead
|
||||
if (log == null)
|
||||
log = Logger.getLogger("Minecraft");
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current error reporter.
|
||||
* <p>
|
||||
* This is guaranteed to not be NULL in 2.5.0 and later.
|
||||
* @return Current error reporter.
|
||||
*/
|
||||
public static ErrorReporter getErrorReporter() {
|
||||
return reporter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the current strongly typed configuration.
|
||||
* @return The configuration, or NULL if ProtocolLib hasn't loaded yet.
|
||||
*/
|
||||
public static ProtocolConfig getConfiguration() {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the packet protocol manager.
|
||||
* @return Packet protocol manager, or NULL if it has been disabled.
|
||||
*/
|
||||
public static ProtocolManager getProtocolManager() {
|
||||
return protocolManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the metrics instance used to measure users of this library.
|
||||
* <p>
|
||||
@@ -640,7 +633,23 @@ public class ProtocolLib extends JavaPlugin {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
public ProtocolConfig getProtocolConfig() {
|
||||
return config;
|
||||
/**
|
||||
* Retrieve an executor service for performing asynchronous tasks on the behalf of ProtocolLib.
|
||||
* <p>
|
||||
* Note that this service is NULL if ProtocolLib has not been initialized yet.
|
||||
* @return The executor service, or NULL.
|
||||
*/
|
||||
public static ListeningScheduledExecutorService getExecutorAsync() {
|
||||
return executorAsync;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an executor service for performing synchronous tasks (main thread) on the behalf of ProtocolLib.
|
||||
* <p>
|
||||
* Note that this service is NULL if ProtocolLib has not been initialized yet.
|
||||
* @return The executor service, or NULL.
|
||||
*/
|
||||
public static ListeningScheduledExecutorService getExecutorSync() {
|
||||
return executorSync;
|
||||
}
|
||||
}
|
||||
+99
-46
@@ -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 org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.async.AsyncMarker;
|
||||
import com.comphenix.protocol.events.ListenerPriority;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.PacketConstructor;
|
||||
@@ -49,12 +48,12 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @param player - the player.
|
||||
* @return The associated protocol version, or {@link Integer#MIN_VALUE} if unknown.
|
||||
*/
|
||||
int getProtocolVersion(Player player);
|
||||
public int getProtocolVersion(Player player);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -63,13 +62,13 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @throws InvocationTargetException - if an error occurred when sending the packet.
|
||||
*/
|
||||
@Override
|
||||
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.
|
||||
@@ -79,7 +78,7 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @throws IllegalAccessException If the underlying method caused an error.
|
||||
*/
|
||||
@Override
|
||||
void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
|
||||
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters)
|
||||
throws IllegalAccessException, InvocationTargetException;
|
||||
|
||||
/**
|
||||
@@ -87,19 +86,19 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @param packet - the packet to broadcast.
|
||||
* @throws FieldAccessException If we were unable to send the packet due to reflection problems.
|
||||
*/
|
||||
void broadcastServerPacket(PacketContainer packet);
|
||||
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.
|
||||
* @param includeTracker - whether or not to also transmit the packet to the entity, if it is a tracker.
|
||||
* @throws FieldAccessException If we were unable to send the packet due to reflection problems.
|
||||
*/
|
||||
void broadcastServerPacket(PacketContainer packet, Entity entity, boolean includeTracker);
|
||||
public void broadcastServerPacket(PacketContainer packet, Entity entity, boolean includeTracker);
|
||||
|
||||
/**
|
||||
* Broadcast a packet to every player within the given maximum observer distance.
|
||||
@@ -107,49 +106,76 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @param origin - the origin to consider when calculating the distance to each observer.
|
||||
* @param maxObserverDistance - the maximum distance to the origin.
|
||||
*/
|
||||
void broadcastServerPacket(PacketContainer packet, Location origin, int maxObserverDistance);
|
||||
public void broadcastServerPacket(PacketContainer packet, Location origin, int maxObserverDistance);
|
||||
|
||||
/**
|
||||
* Retrieves a list of every registered packet listener.
|
||||
* @return Every registered packet listener.
|
||||
*/
|
||||
ImmutableSet<PacketListener> getPacketListeners();
|
||||
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.
|
||||
*/
|
||||
void addPacketListener(PacketListener 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.
|
||||
*/
|
||||
void removePacketListener(PacketListener listener);
|
||||
public void removePacketListener(PacketListener listener);
|
||||
|
||||
/**
|
||||
* Removes every listener associated with the given plugin.
|
||||
* @param plugin - the plugin to unload.
|
||||
*/
|
||||
void removePacketListeners(Plugin plugin);
|
||||
public void removePacketListeners(Plugin plugin);
|
||||
|
||||
/**
|
||||
* Constructs a new encapsulated Minecraft packet with the given ID.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #createPacket(PacketType)} instead.
|
||||
* @param id - packet ID.
|
||||
* @return New encapsulated Minecraft packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketContainer createPacket(int id);
|
||||
|
||||
/**
|
||||
* Constructs a new encapsulated Minecraft packet with the given ID.
|
||||
* @param type - packet type.
|
||||
* @return New encapsulated Minecraft packet.
|
||||
*/
|
||||
PacketContainer createPacket(PacketType type);
|
||||
public PacketContainer createPacket(PacketType type);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #createPacket(PacketType, boolean)} instead.
|
||||
*
|
||||
* @param id - packet ID.
|
||||
* @param forceDefaults - TRUE to use sensible defaults in most fields, FALSE otherwise.
|
||||
* @return New encapsulated Minecraft packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketContainer createPacket(int id, boolean forceDefaults);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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.
|
||||
@@ -158,25 +184,36 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @param forceDefaults - TRUE to use sensible defaults in most fields, FALSE otherwise.
|
||||
* @return New encapsulated Minecraft packet.
|
||||
*/
|
||||
PacketContainer createPacket(PacketType type, boolean forceDefaults);
|
||||
|
||||
public PacketContainer createPacket(PacketType type, boolean forceDefaults);
|
||||
|
||||
/**
|
||||
* Construct a packet using the special builtin Minecraft constructors.
|
||||
* @param type - the packet type.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #createPacketConstructor(PacketType, Object...)} instead.
|
||||
* @param id - the packet ID.
|
||||
* @param arguments - arguments that will be passed to the constructor.
|
||||
* @return The packet constructor.
|
||||
*/
|
||||
PacketConstructor createPacketConstructor(PacketType type, Object... arguments);
|
||||
@Deprecated
|
||||
public PacketConstructor createPacketConstructor(int id, Object... arguments);
|
||||
|
||||
/**
|
||||
* Construct a packet using the special builtin Minecraft constructors.
|
||||
* @param id - the packet type.
|
||||
* @param arguments - arguments that will be passed to the constructor.
|
||||
* @return The packet constructor.
|
||||
*/
|
||||
public PacketConstructor createPacketConstructor(PacketType type, Object... arguments);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException;
|
||||
public void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve the associated entity.
|
||||
@@ -185,7 +222,7 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @return The associated entity.
|
||||
* @throws FieldAccessException Reflection failed.
|
||||
*/
|
||||
Entity getEntityFromID(World container, int id) throws FieldAccessException;
|
||||
public Entity getEntityFromID(World container, int id) throws FieldAccessException;
|
||||
|
||||
/**
|
||||
* Retrieve every client that is receiving information about a given entity.
|
||||
@@ -193,37 +230,53 @@ public interface ProtocolManager extends PacketStream {
|
||||
* @return Every client/player that is tracking the given entity.
|
||||
* @throws FieldAccessException If reflection failed.
|
||||
*/
|
||||
List<Player> getEntityTrackers(Entity entity) throws FieldAccessException;
|
||||
|
||||
public List<Player> getEntityTrackers(Entity entity) throws FieldAccessException;
|
||||
|
||||
/**
|
||||
* Retrieves a immutable set containing the ID of the sent server packets that will be observed by listeners.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getSendingFilterTypes()} instead.
|
||||
* @return Every filtered server packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<Integer> getSendingFilters();
|
||||
|
||||
/**
|
||||
* Retrieves a immutable set containing the type of the sent server packets that will be observed by listeners.
|
||||
* @return Every filtered server packet.
|
||||
*/
|
||||
Set<PacketType> getSendingFilterTypes();
|
||||
|
||||
public Set<PacketType> getSendingFilterTypes();
|
||||
|
||||
/**
|
||||
* Retrieves a immutable set containing the ID of the received client packets that will be observed by listeners.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getReceivingFilterTypes()} instead.
|
||||
* @return Every filtered client packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<Integer> getReceivingFilters();
|
||||
|
||||
/**
|
||||
* Retrieves a immutable set containing the type of the received client packets that will be observed by listeners.
|
||||
* @return Every filtered client packet.
|
||||
*/
|
||||
Set<PacketType> getReceivingFilterTypes();
|
||||
public Set<PacketType> getReceivingFilterTypes();
|
||||
|
||||
/**
|
||||
* Retrieve the current Minecraft version.
|
||||
* @return The current version.
|
||||
*/
|
||||
MinecraftVersion getMinecraftVersion();
|
||||
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.
|
||||
*/
|
||||
boolean isClosed();
|
||||
public boolean isClosed();
|
||||
|
||||
/**
|
||||
* Retrieve the current asynchronous packet manager.
|
||||
* @return Asynchronous packet manager.
|
||||
*/
|
||||
AsynchronousManager getAsynchronousManager();
|
||||
|
||||
void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist);
|
||||
}
|
||||
public AsynchronousManager getAsynchronousManager();
|
||||
}
|
||||
+12
-12
@@ -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.Arrays;
|
||||
import java.util.Deque;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ContiguousSet;
|
||||
import com.google.common.collect.DiscreteDomain;
|
||||
import com.google.common.collect.DiscreteDomains;
|
||||
import com.google.common.collect.Range;
|
||||
import com.google.common.collect.Ranges;
|
||||
|
||||
/**
|
||||
* Used to parse ranges in CommandPacket.
|
||||
@@ -68,7 +68,7 @@ class RangeParser {
|
||||
throw new IllegalArgumentException("Cannot form a range without a upper limit.");
|
||||
|
||||
// This is a proper range
|
||||
range = Range.closed(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
|
||||
@@ -76,7 +76,7 @@ class RangeParser {
|
||||
|
||||
} else {
|
||||
// Just a single number
|
||||
range = Range.singleton(Integer.parseInt(current));
|
||||
range = Ranges.singleton(Integer.parseInt(current));
|
||||
ranges.add(range);
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ class RangeParser {
|
||||
|
||||
// Set every ID
|
||||
for (Range<Integer> range : ranges) {
|
||||
for (int id : ContiguousSet.create(range, DiscreteDomain.integers())) {
|
||||
for (int id : range.asSet(DiscreteDomains.integers())) {
|
||||
set[id] = true;
|
||||
}
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class RangeParser {
|
||||
}
|
||||
} else {
|
||||
if (start >= 0) {
|
||||
result.add(Range.closed(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;
|
||||
}
|
||||
+48
-42
@@ -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,6 +23,10 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
import com.comphenix.protocol.AsynchronousManager;
|
||||
import com.comphenix.protocol.PacketStream;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
@@ -31,17 +35,15 @@ import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager;
|
||||
import com.comphenix.protocol.injector.PrioritizedListener;
|
||||
import com.comphenix.protocol.injector.SortedPacketListenerList;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.scheduler.BukkitScheduler;
|
||||
|
||||
/**
|
||||
* Represents a filter manager for asynchronous packets.
|
||||
* <p>
|
||||
@@ -79,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.
|
||||
*/
|
||||
@@ -87,7 +89,7 @@ public class AsyncFilterManager implements AsynchronousManager {
|
||||
// Initialize timeout listeners
|
||||
this.serverTimeoutListeners = new SortedPacketListenerList();
|
||||
this.clientTimeoutListeners = new SortedPacketListenerList();
|
||||
this.timeoutListeners = Sets.newSetFromMap(new ConcurrentHashMap<>());
|
||||
this.timeoutListeners = Sets.newSetFromMap(new ConcurrentHashMap<PacketListener, Boolean>());
|
||||
|
||||
this.playerSendingHandler = new PlayerSendingHandler(reporter, serverTimeoutListeners, clientTimeoutListeners);
|
||||
this.serverProcessingQueue = new PacketProcessingQueue(playerSendingHandler);
|
||||
@@ -146,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());
|
||||
}
|
||||
@@ -179,11 +181,11 @@ public class AsyncFilterManager implements AsynchronousManager {
|
||||
|
||||
// Add listener to either or both processing queue
|
||||
if (hasValidWhitelist(sendingWhitelist)) {
|
||||
manager.verifyWhitelist(listener, sendingWhitelist);
|
||||
PacketFilterManager.verifyWhitelist(listener, sendingWhitelist);
|
||||
serverProcessingQueue.addListener(handler, sendingWhitelist);
|
||||
}
|
||||
if (hasValidWhitelist(receivingWhitelist)) {
|
||||
manager.verifyWhitelist(listener, receivingWhitelist);
|
||||
PacketFilterManager.verifyWhitelist(listener, receivingWhitelist);
|
||||
clientProcessingQueue.addListener(handler, receivingWhitelist);
|
||||
}
|
||||
|
||||
@@ -219,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) {
|
||||
@@ -230,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()) {
|
||||
@@ -248,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
|
||||
@@ -293,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());
|
||||
@@ -303,35 +305,39 @@ 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 = syncPacket.getPlayer();
|
||||
if (player != null) {
|
||||
// Start the process
|
||||
getSendingQueue(syncPacket).enqueue(newEvent);
|
||||
|
||||
// We know this is occurring 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
|
||||
public Set<Integer> getSendingFilters() {
|
||||
return PacketRegistry.toLegacy(serverProcessingQueue.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PacketType> getReceivingTypes() {
|
||||
return serverProcessingQueue.keySet();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Set<Integer> getReceivingFilters() {
|
||||
return PacketRegistry.toLegacy(clientProcessingQueue.keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PacketType> getSendingTypes() {
|
||||
return clientProcessingQueue.keySet();
|
||||
@@ -356,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
|
||||
@@ -460,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
|
||||
+27
-26
@@ -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,6 +24,8 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
@@ -34,11 +36,10 @@ import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.timing.TimedListenerManager;
|
||||
import com.comphenix.protocol.timing.TimedListenerManager.ListenerType;
|
||||
import com.comphenix.protocol.timing.TimedTracker;
|
||||
import com.comphenix.protocol.utility.WrappedScheduler;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Represents a handler for an asynchronous event.
|
||||
* <p>
|
||||
@@ -47,7 +48,7 @@ import org.bukkit.plugin.Plugin;
|
||||
*/
|
||||
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.
|
||||
@@ -208,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() {
|
||||
@@ -315,7 +315,7 @@ public class AsyncListenerHandler {
|
||||
* public Void apply(@Nullable AsyncRunnable workerLoop) {
|
||||
* Thread thread = Thread.currentThread();
|
||||
* int prevPriority = thread.getPriority();
|
||||
*
|
||||
*
|
||||
* thread.setPriority(Thread.MIN_PRIORITY);
|
||||
* workerLoop.run();
|
||||
* thread.setPriority(prevPriority);
|
||||
@@ -344,7 +344,8 @@ public class AsyncListenerHandler {
|
||||
}
|
||||
|
||||
private void scheduleAsync(Runnable runnable) {
|
||||
listener.getPlugin().getServer().getScheduler().runTaskAsynchronously(listener.getPlugin(), runnable);
|
||||
// Handle deprecation
|
||||
WrappedScheduler.runAsynchronouslyRepeat(listener.getPlugin(), filterManager.getScheduler(), runnable, 0L, -1L);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -356,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())
|
||||
);
|
||||
@@ -382,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.
|
||||
@@ -398,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).
|
||||
@@ -502,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.
|
||||
@@ -562,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.");
|
||||
@@ -583,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;
|
||||
@@ -615,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);
|
||||
@@ -623,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();
|
||||
|
||||
+17
-40
@@ -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.ProtocolLogger;
|
||||
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,36 +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 {
|
||||
ProtocolLogger.log(Level.WARNING, "Failed to determine contents of incoming chat packet!");
|
||||
alwaysSync = true;
|
||||
}
|
||||
} else if (event.getPacketType() == PacketType.Status.Server.SERVER_INFO) {
|
||||
return true;
|
||||
} else {
|
||||
// TODO: Find more cases of async packets
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ProtocolLogger.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);
|
||||
+6
-7
@@ -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;
|
||||
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -243,4 +243,4 @@ public class ExpireHashMap<K, V> {
|
||||
return valueView.toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -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)
|
||||
File renamed without changes.
+15
-16
@@ -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.TreeMap;
|
||||
|
||||
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
|
||||
@@ -67,7 +68,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
|
||||
|
||||
@Override
|
||||
public Range<TKey> getKey() {
|
||||
return Range.closed(left.key, right.key);
|
||||
return Ranges.closed(left.key, right.key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,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
|
||||
@@ -139,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);
|
||||
@@ -150,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
|
||||
@@ -182,7 +181,7 @@ public abstract class AbstractIntervalTree<TKey extends Comparable<TKey>, TValue
|
||||
|
||||
if (next != null) {
|
||||
removed.add(getEntry(last, next));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now remove both ranges
|
||||
@@ -254,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.
|
||||
*
|
||||
@@ -263,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));
|
||||
}
|
||||
@@ -424,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;
|
||||
@@ -440,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;
|
||||
+9
-13
@@ -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.
|
||||
+38
-39
@@ -1,23 +1,24 @@
|
||||
package com.comphenix.protocol.concurrency;
|
||||
|
||||
import com.comphenix.protocol.utility.SafeCacheBuilder;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.AbstractSet;
|
||||
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.google.common.base.Function;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.RemovalListener;
|
||||
import com.google.common.cache.RemovalNotification;
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.util.concurrent.UncheckedExecutionException;
|
||||
|
||||
/**
|
||||
* Represents a concurrent player map.
|
||||
@@ -37,7 +38,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
ADDRESS {
|
||||
@Override
|
||||
public Object apply(Player player) {
|
||||
return player == null ? null : player.getAddress();
|
||||
return player.getAddress();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -47,7 +48,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
NAME {
|
||||
@Override
|
||||
public Object apply(Player player) {
|
||||
return player == null ? null : player.getName();
|
||||
return player.getName();
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -55,21 +56,20 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
/**
|
||||
* An internal map of player keys to values.
|
||||
*/
|
||||
private ConcurrentMap<Object, TValue> valueLookup = createValueMap();
|
||||
protected ConcurrentMap<Object, TValue> valueLookup = createValueMap();
|
||||
|
||||
/**
|
||||
* A cache of the associated keys for each player.
|
||||
*/
|
||||
|
||||
private ConcurrentMap<Object, Player> keyLookup = createKeyCache();
|
||||
|
||||
protected ConcurrentMap<Object, Player> keyLookup = createKeyCache();
|
||||
/**
|
||||
* The method used to retrieve a unique key for a player.
|
||||
*/
|
||||
private final Function<Player, Object> keyMethod;
|
||||
protected final Function<Player, Object> keyMethod;
|
||||
|
||||
/**
|
||||
* 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() {
|
||||
@@ -89,7 +88,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
* Construct a new concurrent player map using the given standard key method.
|
||||
* @param standardMethod - the standard key method.
|
||||
*/
|
||||
private ConcurrentPlayerMap(PlayerKey standardMethod) {
|
||||
public ConcurrentPlayerMap(PlayerKey standardMethod) {
|
||||
this.keyMethod = standardMethod;
|
||||
}
|
||||
|
||||
@@ -107,7 +106,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
* The default implementation uses a {@link ConcurrentHashMap}.
|
||||
* @return The value map.
|
||||
*/
|
||||
private ConcurrentMap<Object, TValue> createValueMap() {
|
||||
protected ConcurrentMap<Object, TValue> createValueMap() {
|
||||
return Maps.newConcurrentMap();
|
||||
}
|
||||
|
||||
@@ -115,16 +114,19 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
* Construct a cache of keys and the associated player.
|
||||
* @return The key map.
|
||||
*/
|
||||
private ConcurrentMap<Object, Player> createKeyCache() {
|
||||
protected ConcurrentMap<Object, Player> createKeyCache() {
|
||||
return SafeCacheBuilder.newBuilder().
|
||||
weakValues().
|
||||
removalListener(
|
||||
(RemovalListener<Object, Player>) removed -> {
|
||||
// We ignore explicit removal
|
||||
if (removed.wasEvicted()) {
|
||||
onCacheEvicted(removed.getKey());
|
||||
}
|
||||
}).
|
||||
new RemovalListener<Object, Player>() {
|
||||
@Override
|
||||
public void onRemoval(RemovalNotification<Object, Player> removed) {
|
||||
// We ignore explicit removal
|
||||
if (removed.wasEvicted()) {
|
||||
onCacheEvicted(removed.getKey());
|
||||
}
|
||||
}
|
||||
}).
|
||||
build(
|
||||
new CacheLoader<Object, Player>() {
|
||||
@Override
|
||||
@@ -144,6 +146,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
/**
|
||||
* Invoked when an entry in the cache has been evicted, typically by the garbage collector.
|
||||
* @param key - the key.
|
||||
* @param player - the value that was evicted or collected.
|
||||
*/
|
||||
private void onCacheEvicted(Object key) {
|
||||
Player newPlayer = findOnlinePlayer(key);
|
||||
@@ -161,8 +164,8 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
* @param key - a non-null key.
|
||||
* @return The player with the given key, or NULL if not found.
|
||||
*/
|
||||
private Player findOnlinePlayer(Object key) {
|
||||
for (Player player : Util.getOnlinePlayers()) {
|
||||
protected Player findOnlinePlayer(Object key) {
|
||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||
if (key.equals(keyMethod.apply(player))) {
|
||||
return player;
|
||||
}
|
||||
@@ -174,8 +177,9 @@ 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
|
||||
*/
|
||||
private Player lookupPlayer(Object key) {
|
||||
protected Player lookupPlayer(Object key) {
|
||||
try {
|
||||
return keyLookup.get(key);
|
||||
} catch (UncheckedExecutionException e) {
|
||||
@@ -188,9 +192,7 @@ public class ConcurrentPlayerMap<TValue> extends AbstractMap<Player, TValue> imp
|
||||
* @param player - the player whose key we want to retrieve.
|
||||
* @return The key.
|
||||
*/
|
||||
private Object cachePlayerKey(Player player) {
|
||||
Preconditions.checkNotNull(player, "player cannot be null");
|
||||
|
||||
protected Object cachePlayerKey(Player player) {
|
||||
Object key = keyMethod.apply(player);
|
||||
|
||||
keyLookup.put(key, player);
|
||||
@@ -291,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() {
|
||||
@@ -313,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();
|
||||
}
|
||||
+8
-8
@@ -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;
|
||||
+2
-2
@@ -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.
|
||||
*/
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+22
-38
@@ -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.ProtocolLogger;
|
||||
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]";
|
||||
@@ -464,15 +450,13 @@ public class DetailedErrorReporter implements ErrorReporter {
|
||||
} else {
|
||||
try {
|
||||
if (!apacheCommonsMissing)
|
||||
return ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null);
|
||||
return (ToStringBuilder.reflectionToString(value, ToStringStyle.MULTI_LINE_STYLE, false, null));
|
||||
} catch (LinkageError ex) {
|
||||
// Apache is probably missing
|
||||
apacheCommonsMissing = true;
|
||||
} catch (ThreadDeath | OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (Throwable ex) {
|
||||
} catch (Exception e) {
|
||||
// Don't use the error logger to log errors in error logging (that could lead to infinite loops)
|
||||
ProtocolLogger.log(Level.WARNING, "Cannot convert to a String with Apache: " + ex.getMessage());
|
||||
System.err.print("[ProtocolLib] Warning: Cannot convert to a String with Apache: " + e.getMessage());
|
||||
}
|
||||
|
||||
// Use our custom object printer instead
|
||||
@@ -489,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());
|
||||
}
|
||||
|
||||
+10
-10
@@ -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);
|
||||
@@ -87,4 +87,4 @@ public interface ErrorReporter {
|
||||
* @param reportBuilder - an error report builder that will be used to get the report.
|
||||
*/
|
||||
public abstract void reportDetailed(Object sender, ReportBuilder reportBuilder);
|
||||
}
|
||||
}
|
||||
+13
-12
@@ -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;
|
||||
}
|
||||
}
|
||||
+9
-9
@@ -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;
|
||||
+10
-9
@@ -55,7 +55,7 @@ public class ReportType {
|
||||
*/
|
||||
public static Class<?> getSenderClass(Object sender) {
|
||||
if (sender == null)
|
||||
throw new IllegalArgumentException("sender cannot be null.");
|
||||
throw new IllegalArgumentException("sender cannot be NUll.");
|
||||
else if (sender instanceof Class<?>)
|
||||
return (Class<?>) sender;
|
||||
else
|
||||
@@ -75,7 +75,7 @@ public class ReportType {
|
||||
*/
|
||||
public static String getReportName(Object sender, ReportType type) {
|
||||
if (sender == null)
|
||||
throw new IllegalArgumentException("sender cannot be null.");
|
||||
throw new IllegalArgumentException("sender cannot be NUll.");
|
||||
return getReportName(getSenderClass(sender), type);
|
||||
}
|
||||
|
||||
@@ -83,13 +83,13 @@ public class ReportType {
|
||||
* Retrieve the full canonical name of a given report type.
|
||||
* <p>
|
||||
* This is in the format <i>canonical_name_of_class#report_type</i>
|
||||
* @param sender - the sender class.
|
||||
* @param clazz - the sender class.
|
||||
* @param type - the report instance.
|
||||
* @return The full canonical name.
|
||||
*/
|
||||
private static String getReportName(Class<?> sender, ReportType type) {
|
||||
if (sender == null)
|
||||
throw new IllegalArgumentException("sender cannot be null.");
|
||||
throw new IllegalArgumentException("sender cannot be NUll.");
|
||||
|
||||
// Whether or not we need to retrieve the report name again
|
||||
if (type.reportName == null) {
|
||||
@@ -138,10 +138,11 @@ public class ReportType {
|
||||
* @return All associated report fields.
|
||||
*/
|
||||
private static List<Field> getReportFields(Class<?> clazz) {
|
||||
return FuzzyReflection.fromClass(clazz, true)
|
||||
.getFieldList(FuzzyFieldContract.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.typeDerivedOf(ReportType.class)
|
||||
.build());
|
||||
return FuzzyReflection.fromClass(clazz).getFieldList(
|
||||
FuzzyFieldContract.newBuilder().
|
||||
requireModifier(Modifier.STATIC).
|
||||
typeDerivedOf(ReportType.class).
|
||||
build()
|
||||
);
|
||||
}
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
-1
@@ -2,7 +2,6 @@ package com.comphenix.protocol.events;
|
||||
|
||||
import com.comphenix.protocol.injector.GamePhase;
|
||||
|
||||
|
||||
/**
|
||||
* Represents additional options a listener may require.
|
||||
*
|
||||
+7
-7
@@ -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);
|
||||
+141
-17
@@ -2,22 +2,26 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.injector.GamePhase;
|
||||
@@ -28,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 {
|
||||
/**
|
||||
@@ -40,21 +44,93 @@ public class ListeningWhitelist {
|
||||
private final GamePhase gamePhase;
|
||||
private final Set<ListenerOptions> options;
|
||||
private final Set<PacketType> types;
|
||||
|
||||
|
||||
// Cache whitelist
|
||||
private transient Set<Integer> intWhitelist;
|
||||
|
||||
private ListeningWhitelist(Builder builder) {
|
||||
this.priority = builder.priority;
|
||||
this.types = builder.types;
|
||||
this.gamePhase = builder.gamePhase;
|
||||
this.options = builder.options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet whitelist for a given priority with a set of packet IDs.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #newBuilder()} instead.
|
||||
* @param priority - the listener priority.
|
||||
* @param whitelist - set of IDs to observe/enable.
|
||||
*/
|
||||
@Deprecated
|
||||
public ListeningWhitelist(ListenerPriority priority, Set<Integer> whitelist) {
|
||||
this(priority, whitelist, GamePhase.PLAYING);
|
||||
}
|
||||
|
||||
private ListeningWhitelist(ListenerPriority priority) {
|
||||
/**
|
||||
* Creates a packet whitelist for a given priority with a set of packet IDs.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #newBuilder()} instead.
|
||||
* @param priority - the listener priority.
|
||||
* @param whitelist - set of IDs to observe/enable.
|
||||
* @param gamePhase - which game phase to receieve notifications on.
|
||||
*/
|
||||
@Deprecated
|
||||
public ListeningWhitelist(ListenerPriority priority, Set<Integer> whitelist, GamePhase gamePhase) {
|
||||
this.priority = priority;
|
||||
this.types = new HashSet<>();
|
||||
this.types = PacketRegistry.toPacketTypes(safeSet(whitelist));
|
||||
this.gamePhase = gamePhase;
|
||||
this.options = EnumSet.noneOf(ListenerOptions.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet whitelist of a given priority for a list of packets.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #newBuilder()} instead.
|
||||
* @param priority - the listener priority.
|
||||
* @param whitelist - list of packet IDs to observe/enable.
|
||||
*/
|
||||
@Deprecated
|
||||
public ListeningWhitelist(ListenerPriority priority, Integer... whitelist) {
|
||||
this.priority = priority;
|
||||
this.types = PacketRegistry.toPacketTypes(Sets.newHashSet(whitelist));
|
||||
this.gamePhase = GamePhase.PLAYING;
|
||||
this.options = EnumSet.noneOf(ListenerOptions.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet whitelist for a given priority with a set of packet IDs.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #newBuilder()} instead.
|
||||
* @param priority - the listener priority.
|
||||
* @param whitelist - list of packet IDs to observe/enable.
|
||||
* @param gamePhase - which game phase to receieve notifications on.
|
||||
*/
|
||||
@Deprecated
|
||||
public ListeningWhitelist(ListenerPriority priority, Integer[] whitelist, GamePhase gamePhase) {
|
||||
this.priority = priority;
|
||||
this.types = PacketRegistry.toPacketTypes(Sets.newHashSet(whitelist));
|
||||
this.gamePhase = gamePhase;
|
||||
this.options = EnumSet.noneOf(ListenerOptions.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet whitelist for a given priority with a set of packet IDs and options.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #newBuilder()} instead.
|
||||
* @param priority - the listener priority.
|
||||
* @param whitelist - list of packet IDs to observe/enable.
|
||||
* @param gamePhase - which game phase to receieve notifications on.
|
||||
* @param options - every special option associated with this whitelist.
|
||||
*/
|
||||
@Deprecated
|
||||
public ListeningWhitelist(ListenerPriority priority, Integer[] whitelist, GamePhase gamePhase, ListenerOptions... options) {
|
||||
this.priority = priority;
|
||||
this.types = PacketRegistry.toPacketTypes(Sets.newHashSet(whitelist));
|
||||
this.gamePhase = gamePhase;
|
||||
this.options = safeEnumSet(Arrays.asList(options), ListenerOptions.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this whitelist has any enabled packets.
|
||||
* @return TRUE if there are any packets, FALSE otherwise.
|
||||
@@ -71,6 +147,19 @@ public class ListeningWhitelist {
|
||||
return priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of packets that will be observed by the listeners.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getTypes()} instead.
|
||||
* @return Packet whitelist.
|
||||
*/
|
||||
@Deprecated
|
||||
public Set<Integer> getWhitelist() {
|
||||
if (intWhitelist == null)
|
||||
intWhitelist = PacketRegistry.toLegacy(types);
|
||||
return intWhitelist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a set of the packets that will be observed by the listeners.
|
||||
* @return Packet whitelist.
|
||||
@@ -100,6 +189,23 @@ public class ListeningWhitelist {
|
||||
return Objects.hashCode(priority, types, gamePhase, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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) {
|
||||
if (whitelist != null) {
|
||||
for (int i = 0; i < idList.length; i++) {
|
||||
if (whitelist.getWhitelist().contains(idList[i]))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the given whitelist is empty or not.
|
||||
* @param whitelist - the whitelist to test.
|
||||
@@ -132,7 +238,12 @@ public class ListeningWhitelist {
|
||||
if (this == EMPTY_WHITELIST)
|
||||
return "EMPTY_WHITELIST";
|
||||
else
|
||||
return "ListeningWhitelist[priority=" + priority + ", packets=" + types + ", gamephase=" + gamePhase + ", options=" + options + "]";
|
||||
return Objects.toStringHelper(this).
|
||||
add("priority", priority).
|
||||
add("packets", types).
|
||||
add("gamephase", gamePhase).
|
||||
add("options", options).
|
||||
toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,7 +278,7 @@ public class ListeningWhitelist {
|
||||
|
||||
/**
|
||||
* Construct a copy of a given set.
|
||||
* @param set - the set to copy.
|
||||
* @param list - the set to copy.
|
||||
* @return The copied set.
|
||||
*/
|
||||
private static <T> Set<T> safeSet(Collection<T> set) {
|
||||
@@ -258,7 +369,20 @@ public class ListeningWhitelist {
|
||||
public Builder high() {
|
||||
return priority(ListenerPriority.HIGH);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the whitelist of packet IDs to copy when constructing new whitelists.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #types(Collection)} instead.
|
||||
* @param whitelist - the whitelist of packets.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
@Deprecated
|
||||
public Builder whitelist(Collection<Integer> whitelist) {
|
||||
this.types = PacketRegistry.toPacketTypes(safeSet(whitelist));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the whitelist of packet types to copy when constructing new whitelists.
|
||||
* @param types - the whitelist of packets.
|
||||
@@ -318,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) {
|
||||
@@ -328,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) {
|
||||
@@ -337,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) {
|
||||
+21
-8
@@ -17,12 +17,16 @@
|
||||
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.injector.GamePhase;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
|
||||
/**
|
||||
* Represents a listener that is notified of every sent and received packet.
|
||||
*
|
||||
@@ -41,17 +45,26 @@ public abstract class MonitorAdapter implements PacketListener {
|
||||
public MonitorAdapter(Plugin plugin, ConnectionSide side, Logger logger) {
|
||||
initialize(plugin, side, logger);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private void initialize(Plugin plugin, ConnectionSide side, Logger logger) {
|
||||
this.plugin = plugin;
|
||||
|
||||
// Recover in case something goes wrong
|
||||
if (side.isForServer())
|
||||
this.sending = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getServerPacketTypes()).gamePhaseBoth().build();
|
||||
if (side.isForClient())
|
||||
this.receiving = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getClientPacketTypes()).gamePhaseBoth().build();
|
||||
try {
|
||||
if (side.isForServer())
|
||||
this.sending = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getServerPacketTypes()).gamePhaseBoth().build();
|
||||
if (side.isForClient())
|
||||
this.receiving = ListeningWhitelist.newBuilder().monitor().types(PacketRegistry.getClientPacketTypes()).gamePhaseBoth().build();
|
||||
} catch (FieldAccessException e) {
|
||||
if (side.isForServer())
|
||||
this.sending = new ListeningWhitelist(ListenerPriority.MONITOR, Packets.Server.getRegistry().values(), GamePhase.BOTH);
|
||||
if (side.isForClient())
|
||||
this.receiving = new ListeningWhitelist(ListenerPriority.MONITOR, Packets.Client.getRegistry().values(), GamePhase.BOTH);
|
||||
logger.log(Level.WARNING, "Defaulting to 1.3 packets.", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a logger, even if we're running in a CraftBukkit version that doesn't support it.
|
||||
* @param plugin - the plugin to retrieve.
|
||||
+20
-26
@@ -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);
|
||||
+231
-25
@@ -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
|
||||
*/
|
||||
|
||||
@@ -19,17 +19,19 @@ package com.comphenix.protocol.events;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.injector.GamePhase;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
/**
|
||||
* Represents a packet listener with useful constructors.
|
||||
* <p>
|
||||
@@ -48,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
|
||||
);
|
||||
}
|
||||
@@ -56,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) {
|
||||
@@ -101,10 +104,154 @@ public abstract class PacketAdapter implements PacketListener {
|
||||
public PacketAdapter(Plugin plugin, ListenerPriority listenerPriority, PacketType... types) {
|
||||
this(params(plugin, types).listenerPriority(listenerPriority));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a packet listener with default priority.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, Integer... packets) {
|
||||
this(plugin, connectionSide, ListenerPriority.NORMAL, packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param listenerPriority - the event priority.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, Set<Integer> packets) {
|
||||
this(plugin, connectionSide, listenerPriority, GamePhase.PLAYING, packets.toArray(new Integer[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param gamePhase - which game phase this listener is active under.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, GamePhase gamePhase, Set<Integer> packets) {
|
||||
this(plugin, connectionSide, ListenerPriority.NORMAL, gamePhase, packets.toArray(new Integer[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param listenerPriority - the event priority.
|
||||
* @param gamePhase - which game phase this listener is active under.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, GamePhase gamePhase, Set<Integer> packets) {
|
||||
this(plugin, connectionSide, listenerPriority, gamePhase, packets.toArray(new Integer[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param listenerPriority - the event priority.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, Integer... packets) {
|
||||
this(plugin, connectionSide, listenerPriority, GamePhase.PLAYING, packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param options - which listener options to use.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerOptions[] options, Integer... packets) {
|
||||
this(plugin, connectionSide, ListenerPriority.NORMAL, GamePhase.PLAYING, options, packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param gamePhase - which game phase this listener is active under.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, GamePhase gamePhase, Integer... packets) {
|
||||
this(plugin, connectionSide, ListenerPriority.NORMAL, gamePhase, packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param listenerPriority - the event priority.
|
||||
* @param gamePhase - which game phase this listener is active under.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority, GamePhase gamePhase, Integer... packets) {
|
||||
this(plugin, connectionSide, listenerPriority, gamePhase, new ListenerOptions[0], packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a packet listener for a single connection side.
|
||||
* <p>
|
||||
* The game phase is used to optimize performance. A listener should only choose BOTH or LOGIN if it's absolutely necessary.
|
||||
* <p>
|
||||
* Listener options must be specified in order for {@link NetworkMarker#getInputBuffer()} to function correctly.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #params()} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param connectionSide - the packet type the listener is looking for.
|
||||
* @param listenerPriority - the event priority.
|
||||
* @param gamePhase - which game phase this listener is active under.
|
||||
* @param options - which listener options to use.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketAdapter(
|
||||
Plugin plugin, ConnectionSide connectionSide, ListenerPriority listenerPriority,
|
||||
GamePhase gamePhase, ListenerOptions[] options, Integer... packets) {
|
||||
|
||||
this(plugin, connectionSide, listenerPriority, gamePhase, options,
|
||||
PacketRegistry.toPacketTypes(Sets.newHashSet(packets), connectionSide.getSender()).toArray(new PacketType[0])
|
||||
);
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -125,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);
|
||||
}
|
||||
|
||||
@@ -200,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);
|
||||
}
|
||||
@@ -228,6 +377,20 @@ public abstract class PacketAdapter implements PacketListener {
|
||||
public static AdapterParameteters params() {
|
||||
return new AdapterParameteters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a helper object for passing parameters to the packet adapter.
|
||||
* <p>
|
||||
* This is often simpler and better than passing them directly to each constructor.
|
||||
* Deprecated: Use {@link #params(Plugin, PacketType...)} instead.
|
||||
* @param plugin - the plugin that spawned this listener.
|
||||
* @param packets - the packet IDs the listener is looking for.
|
||||
* @return Helper object.
|
||||
*/
|
||||
@Deprecated
|
||||
public static AdapterParameteters params(Plugin plugin, Integer... packets) {
|
||||
return new AdapterParameteters().plugin(plugin).packets(packets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a helper object for passing parameters to the packet adapter.
|
||||
@@ -278,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() {
|
||||
@@ -286,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() {
|
||||
@@ -294,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.
|
||||
@@ -372,7 +535,17 @@ public abstract class PacketAdapter implements PacketListener {
|
||||
public AdapterParameteters optionIntercept() {
|
||||
return addOption(ListenerOptions.INTERCEPT_INPUT_BUFFER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the listener option to {@link ListenerOptions#DISABLE_GAMEPHASE_DETECTION}, causing ProtocolLib to ignore automatic game phase detection.
|
||||
* <p>
|
||||
* This is no longer relevant in 1.7.2.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
public AdapterParameteters optionManualGamePhase() {
|
||||
return addOption(ListenerOptions.DISABLE_GAMEPHASE_DETECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener option to {@link ListenerOptions#ASYNC}, indicating that our listener is thread safe.
|
||||
* <p>
|
||||
@@ -382,7 +555,40 @@ public abstract class PacketAdapter implements PacketListener {
|
||||
public AdapterParameteters optionAsync() {
|
||||
return addOption(ListenerOptions.ASYNC);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the packet IDs of the packets the listener is looking for.
|
||||
* <p>
|
||||
* This parameter is required.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #types(PacketType...)} instead.
|
||||
* @param packets - the packet IDs to look for.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
@Deprecated
|
||||
public AdapterParameteters packets(@Nonnull Integer... packets) {
|
||||
Preconditions.checkNotNull(packets, "packets cannot be NULL");
|
||||
PacketType[] types = new PacketType[packets.length];
|
||||
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
types[i] = PacketType.findLegacy(packets[i]);
|
||||
}
|
||||
this.packets = types;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the packet IDs of the packets the listener is looking for.
|
||||
* <p>
|
||||
* This parameter is required.
|
||||
* @param packets - a set of the packet IDs to look for.
|
||||
* @return This builder, for chaining.
|
||||
*/
|
||||
@Deprecated
|
||||
public AdapterParameteters packets(@Nonnull Set<Integer> packets) {
|
||||
return packets(packets.toArray(new Integer[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the packet types the listener is looking for.
|
||||
* <p>
|
||||
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.events;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
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 com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.injector.StructureCache;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.ObjectWriter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner;
|
||||
import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
|
||||
import com.comphenix.protocol.reflect.cloning.BukkitCloner;
|
||||
import com.comphenix.protocol.reflect.cloning.Cloner;
|
||||
import com.comphenix.protocol.reflect.cloning.CollectionCloner;
|
||||
import com.comphenix.protocol.reflect.cloning.FieldCloner;
|
||||
import com.comphenix.protocol.reflect.cloning.ImmutableDetector;
|
||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
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.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.Difficulty;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
|
||||
import com.comphenix.protocol.wrappers.WrappedAttribute;
|
||||
import com.comphenix.protocol.wrappers.WrappedChatComponent;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.comphenix.protocol.wrappers.WrappedGameProfile;
|
||||
import com.comphenix.protocol.wrappers.WrappedServerPing;
|
||||
import com.comphenix.protocol.wrappers.WrappedStatistic;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft packet indirectly.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class PacketContainer implements Serializable {
|
||||
private static final long serialVersionUID = 3;
|
||||
|
||||
protected PacketType type;
|
||||
protected transient Object handle;
|
||||
|
||||
// Current structure modifier
|
||||
protected transient StructureModifier<Object> structureModifier;
|
||||
|
||||
// Support for serialization
|
||||
private static ConcurrentMap<Class<?>, Method> writeMethods = Maps.newConcurrentMap();
|
||||
private static ConcurrentMap<Class<?>, Method> readMethods = Maps.newConcurrentMap();
|
||||
|
||||
// Used to clone packets
|
||||
private static final AggregateCloner DEEP_CLONER = AggregateCloner.newBuilder().
|
||||
instanceProvider(DefaultInstances.DEFAULT).
|
||||
andThen(BukkitCloner.class).
|
||||
andThen(ImmutableDetector.class).
|
||||
andThen(CollectionCloner.class).
|
||||
andThen(getSpecializedDeepClonerFactory()).
|
||||
build();
|
||||
|
||||
private static final AggregateCloner SHALLOW_CLONER = AggregateCloner.newBuilder().
|
||||
instanceProvider(DefaultInstances.DEFAULT).
|
||||
andThen(new Function<BuilderParameters, Cloner>() {
|
||||
@Override
|
||||
public Cloner apply(@Nullable BuilderParameters param) {
|
||||
if (param == null)
|
||||
throw new IllegalArgumentException("Cannot be NULL.");
|
||||
|
||||
return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
|
||||
// Use a default writer with no concept of cloning
|
||||
writer = new ObjectWriter();
|
||||
}};
|
||||
}
|
||||
}).
|
||||
build();
|
||||
|
||||
// Packets that cannot be cloned by our default deep cloner
|
||||
private static final Set<PacketType> CLONING_UNSUPPORTED = Sets.newHashSet(
|
||||
PacketType.Play.Server.UPDATE_ATTRIBUTES, PacketType.Status.Server.OUT_SERVER_INFO);
|
||||
|
||||
/**
|
||||
* Creates a packet container for a new packet.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #PacketContainer(PacketType)} instead.
|
||||
* @param id - ID of the packet to create.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketContainer(int id) {
|
||||
this(PacketType.findLegacy(id), StructureCache.newPacket(PacketType.findLegacy(id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
public PacketContainer(int id, Object handle) {
|
||||
this(PacketType.findLegacy(id), handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
public PacketContainer(int id, Object handle, StructureModifier<Object> structure) {
|
||||
this(PacketType.findLegacy(id), handle, structure);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet container for a new packet.
|
||||
* @param type - the type of the packet to create.
|
||||
*/
|
||||
public PacketContainer(PacketType type) {
|
||||
this(type, StructureCache.newPacket(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet container for an existing packet.
|
||||
* @param id - ID of the given packet.
|
||||
* @param handle - contained packet.
|
||||
*/
|
||||
public PacketContainer(PacketType type, Object handle) {
|
||||
this(type, handle, StructureCache.getStructure(type).withTarget(handle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a packet container for an existing packet.
|
||||
* @param id - ID of the given packet.
|
||||
* @param handle - contained packet.
|
||||
* @param structure - structure modifier.
|
||||
*/
|
||||
public PacketContainer(PacketType type, Object handle, StructureModifier<Object> structure) {
|
||||
if (handle == null)
|
||||
throw new IllegalArgumentException("handle cannot be null.");
|
||||
if (type == null)
|
||||
throw new IllegalArgumentException("type cannot be null.");
|
||||
|
||||
this.type = type;
|
||||
this.handle = handle;
|
||||
this.structureModifier = structure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new packet container from a given handle.
|
||||
* @param packet - the NMS packet.
|
||||
* @return The packet container.
|
||||
*/
|
||||
public static PacketContainer fromPacket(Object packet) {
|
||||
PacketType type = PacketType.fromClass(packet.getClass());
|
||||
return new PacketContainer(type, packet);
|
||||
}
|
||||
|
||||
/**
|
||||
* For serialization.
|
||||
*/
|
||||
protected PacketContainer() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the underlying Minecraft packet.
|
||||
* @return Underlying Minecraft packet.
|
||||
*/
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the generic structure modifier for this packet.
|
||||
* @return Structure modifier.
|
||||
*/
|
||||
public StructureModifier<Object> getModifier() {
|
||||
return structureModifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every field with the given type.
|
||||
* @param primitiveType - the type to find.
|
||||
* @return A modifier for this specific type.
|
||||
*/
|
||||
public <T> StructureModifier<T> getSpecificModifier(Class<T> primitiveType) {
|
||||
return structureModifier.withType(primitiveType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every byte field.
|
||||
* @return A modifier for every byte field.
|
||||
*/
|
||||
public StructureModifier<Byte> getBytes() {
|
||||
return structureModifier.withType(byte.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every boolean field.
|
||||
* @return A modifier for every boolean field.
|
||||
*/
|
||||
public StructureModifier<Boolean> getBooleans() {
|
||||
return structureModifier.withType(boolean.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every short field.
|
||||
* @return A modifier for every short field.
|
||||
*/
|
||||
public StructureModifier<Short> getShorts() {
|
||||
return structureModifier.withType(short.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every integer field.
|
||||
* @return A modifier for every integer field.
|
||||
*/
|
||||
public StructureModifier<Integer> getIntegers() {
|
||||
return structureModifier.withType(int.class);
|
||||
}
|
||||
/**
|
||||
* Retrieves a read/write structure for every long field.
|
||||
* @return A modifier for every long field.
|
||||
*/
|
||||
public StructureModifier<Long> getLongs() {
|
||||
return structureModifier.withType(long.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every float field.
|
||||
* @return A modifier for every float field.
|
||||
*/
|
||||
public StructureModifier<Float> getFloat() {
|
||||
return structureModifier.withType(float.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every double field.
|
||||
* @return A modifier for every double field.
|
||||
*/
|
||||
public StructureModifier<Double> getDoubles() {
|
||||
return structureModifier.withType(double.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every String field.
|
||||
* @return A modifier for every String field.
|
||||
*/
|
||||
public StructureModifier<String> getStrings() {
|
||||
return structureModifier.withType(String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every String array field.
|
||||
* @return A modifier for every String array field.
|
||||
*/
|
||||
public StructureModifier<String[]> getStringArrays() {
|
||||
return structureModifier.withType(String[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every byte array field.
|
||||
* @return A modifier for every byte array field.
|
||||
*/
|
||||
public StructureModifier<byte[]> getByteArrays() {
|
||||
return structureModifier.withType(byte[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a serializer for reading and writing ItemStacks stored in a byte array.
|
||||
* @return A instance of the serializer.
|
||||
*/
|
||||
public StreamSerializer getByteArraySerializer() {
|
||||
return new StreamSerializer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every int array field.
|
||||
* @return A modifier for every int array field.
|
||||
*/
|
||||
public StructureModifier<int[]> getIntegerArrays() {
|
||||
return structureModifier.withType(int[].class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for ItemStack.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the Bukkit ItemStack and the
|
||||
* internal Minecraft ItemStack.
|
||||
* @return A modifier for ItemStack fields.
|
||||
*/
|
||||
public StructureModifier<ItemStack> getItemModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<ItemStack>withType(
|
||||
MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for arrays of ItemStacks.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the Bukkit ItemStack and the
|
||||
* internal Minecraft ItemStack.
|
||||
* @return A modifier for ItemStack array fields.
|
||||
*/
|
||||
public StructureModifier<ItemStack[]> getItemArrayModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<ItemStack[]>withType(
|
||||
MinecraftReflection.getItemStackArrayClass(),
|
||||
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for maps of statistics.
|
||||
* <p>
|
||||
* Note that you must write back the changed map to persist it.
|
||||
* @return A modifier for maps of statistics.
|
||||
*/
|
||||
public StructureModifier<Map<WrappedStatistic, Integer>> getStatisticMaps() {
|
||||
return structureModifier.withType(Map.class,
|
||||
BukkitConverters.<WrappedStatistic, Integer>getMapConverter(
|
||||
MinecraftReflection.getStatisticClass(),
|
||||
BukkitConverters.getWrappedStatisticConverter()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for the world type enum.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the Bukkit world type and the
|
||||
* internal Minecraft world type.
|
||||
* @return A modifier for world type fields.
|
||||
*/
|
||||
public StructureModifier<WorldType> getWorldTypeModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WorldType>withType(
|
||||
MinecraftReflection.getWorldTypeClass(),
|
||||
BukkitConverters.getWorldTypeConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for data watchers.
|
||||
* @return A modifier for data watchers.
|
||||
*/
|
||||
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WrappedDataWatcher>withType(
|
||||
MinecraftReflection.getDataWatcherClass(),
|
||||
BukkitConverters.getDataWatcherConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for entity objects.
|
||||
* <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
|
||||
* is essential.
|
||||
*
|
||||
* @param world - the world each entity is currently occupying.
|
||||
* @return A modifier entity types.
|
||||
*/
|
||||
public StructureModifier<Entity> getEntityModifier(@Nonnull World world) {
|
||||
Preconditions.checkNotNull(world, "world cannot be NULL.");
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<Entity>withType(
|
||||
int.class, BukkitConverters.getEntityConverter(world));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for entity objects.
|
||||
* <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
|
||||
* is essential.
|
||||
*
|
||||
* @param event - the original packet event.
|
||||
* @return A modifier entity types.
|
||||
*/
|
||||
public StructureModifier<Entity> getEntityModifier(@Nonnull PacketEvent event) {
|
||||
Preconditions.checkNotNull(event, "event cannot be NULL.");
|
||||
return getEntityModifier(event.getPlayer().getWorld());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for chunk positions.
|
||||
* @return A modifier for a ChunkPosition.
|
||||
*/
|
||||
public StructureModifier<ChunkPosition> getPositionModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getChunkPositionClass(),
|
||||
ChunkPosition.getConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for wrapped ChunkCoordIntPairs.
|
||||
* @return A modifier for ChunkCoordIntPair.
|
||||
*/
|
||||
public StructureModifier<ChunkCoordIntPair> getChunkCoordIntPairs() {
|
||||
// Allow access to the NBT class in packet 130
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getChunkCoordIntPair(),
|
||||
ChunkCoordIntPair.getConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for NBT classes.
|
||||
* @return A modifier for NBT classes.
|
||||
*/
|
||||
public StructureModifier<NbtBase<?>> getNbtModifier() {
|
||||
// Allow access to the NBT class in packet 130
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getNBTBaseClass(),
|
||||
BukkitConverters.getNbtConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of attribute snapshots.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the visible ProtocolLib WrappedAttribute and the
|
||||
* internal Minecraft AttributeSnapshot.
|
||||
* @return A modifier for AttributeSnapshot collection fields.
|
||||
*/
|
||||
public StructureModifier<List<WrappedAttribute>> getAttributeCollectionModifier() {
|
||||
// Convert to and from the ProtocolLib wrapper
|
||||
return structureModifier.withType(
|
||||
Collection.class,
|
||||
BukkitConverters.getListConverter(
|
||||
MinecraftReflection.getAttributeSnapshotClass(),
|
||||
BukkitConverters.getWrappedAttributeConverter())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of chunk positions.
|
||||
* <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() {
|
||||
// Convert to and from the ProtocolLib wrapper
|
||||
return structureModifier.withType(
|
||||
Collection.class,
|
||||
BukkitConverters.getListConverter(
|
||||
MinecraftReflection.getChunkPositionClass(),
|
||||
ChunkPosition.getConverter())
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of watchable objects.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the visible WrappedWatchableObject and the
|
||||
* internal Minecraft WatchableObject.
|
||||
* @return A modifier for watchable object list fields.
|
||||
*/
|
||||
public StructureModifier<List<WrappedWatchableObject>> getWatchableCollectionModifier() {
|
||||
// Convert to and from the ProtocolLib wrapper
|
||||
return structureModifier.withType(
|
||||
Collection.class,
|
||||
BukkitConverters.getListConverter(
|
||||
MinecraftReflection.getWatchableObjectClass(),
|
||||
BukkitConverters.getWatchableObjectConverter())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for block fields.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between Material and the
|
||||
* internal Minecraft Block.
|
||||
* @return A modifier for GameProfile fields.
|
||||
*/
|
||||
public StructureModifier<Material> getBlocks() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<Material>withType(
|
||||
MinecraftReflection.getBlockClass(), BukkitConverters.getBlockConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for game profiles in Minecraft 1.7.2.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between WrappedGameProfile and the
|
||||
* internal Minecraft GameProfile.
|
||||
* @return A modifier for GameProfile fields.
|
||||
*/
|
||||
public StructureModifier<WrappedGameProfile> getGameProfiles() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WrappedGameProfile>withType(
|
||||
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 GameProfile.
|
||||
* @return A modifier for ChatComponent fields.
|
||||
*/
|
||||
public StructureModifier<WrappedChatComponent> getChatComponents() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WrappedChatComponent>withType(
|
||||
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the ServerPing fields in the following packet: <br>
|
||||
* <ul>
|
||||
* <li>{@link PacketType.Status.Server#OUT_SERVER_INFO}
|
||||
* </ul>
|
||||
* @return A modifier for ServerPing fields.
|
||||
*/
|
||||
public StructureModifier<WrappedServerPing> getServerPings() {
|
||||
// Convert to and from the wrapper
|
||||
return structureModifier.<WrappedServerPing>withType(
|
||||
MinecraftReflection.getServerPingClass(), BukkitConverters.getWrappedServerPingConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the Protocol enum in 1.7.2.
|
||||
* @return A modifier for Protocol enum fields.
|
||||
*/
|
||||
public StructureModifier<Protocol> getProtocols() {
|
||||
// Convert to and from the wrapper
|
||||
return structureModifier.<Protocol>withType(
|
||||
EnumWrappers.getProtocolClass(), EnumWrappers.getProtocolConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the ClientCommand enum in 1.7.2.
|
||||
* @return A modifier for ClientCommand enum fields.
|
||||
*/
|
||||
public StructureModifier<ClientCommand> getClientCommands() {
|
||||
// Convert to and from the wrapper
|
||||
return structureModifier.<ClientCommand>withType(
|
||||
EnumWrappers.getClientCommandClass(), EnumWrappers.getClientCommandConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the ChatVisibility enum in 1.7.2.
|
||||
* @return A modifier for ChatVisibility enum fields.
|
||||
*/
|
||||
public StructureModifier<ChatVisibility> getChatVisibilities() {
|
||||
// Convert to and from the wrapper
|
||||
return structureModifier.<ChatVisibility>withType(
|
||||
EnumWrappers.getChatVisibilityClass(), EnumWrappers.getChatVisibilityConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the Difficulty enum in 1.7.2.
|
||||
* @return A modifier for Difficulty enum fields.
|
||||
*/
|
||||
public StructureModifier<Difficulty> getDifficulties() {
|
||||
// Convert to and from the wrapper
|
||||
return structureModifier.<Difficulty>withType(
|
||||
EnumWrappers.getDifficultyClass(), EnumWrappers.getDifficultyConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the EntityUse enum in 1.7.2.
|
||||
* @return A modifier for EntityUse enum fields.
|
||||
*/
|
||||
public StructureModifier<EntityUseAction> getEntityUseActions() {
|
||||
// Convert to and from the wrapper
|
||||
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.
|
||||
*/
|
||||
public StructureModifier<NativeGameMode> getGameModes() {
|
||||
// Convert to and from the wrapper
|
||||
return structureModifier.<NativeGameMode>withType(
|
||||
EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ID of this packet.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getType()} instead.
|
||||
* @return Packet ID.
|
||||
*/
|
||||
@Deprecated
|
||||
public int getID() {
|
||||
return type.getLegacyId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the packet type of this packet.
|
||||
* @return The packet type.
|
||||
*/
|
||||
public PacketType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return A shallow copy of the current packet.
|
||||
*/
|
||||
public PacketContainer shallowClone() {
|
||||
Object clonedPacket = SHALLOW_CLONER.clone(getHandle());
|
||||
return new PacketContainer(getType(), clonedPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a deep copy of the current packet.
|
||||
* <p>
|
||||
* This will perform a full copy of the entire object tree, only skipping
|
||||
* known immutable objects and primitive types.
|
||||
* <p>
|
||||
* Note that the inflated buffers in packet 51 and 56 will be copied directly to save memory.
|
||||
*
|
||||
* @return A deep copy of the current packet.
|
||||
*/
|
||||
public PacketContainer deepClone() {
|
||||
Object clonedPacket = null;
|
||||
|
||||
// Fall back on the alternative (but slower) method of reading and writing back the packet
|
||||
if (CLONING_UNSUPPORTED.contains(type)) {
|
||||
clonedPacket = SerializableCloner.clone(this).getHandle();
|
||||
} else {
|
||||
clonedPacket = DEEP_CLONER.clone(getHandle());
|
||||
}
|
||||
return new PacketContainer(getType(), clonedPacket);
|
||||
}
|
||||
|
||||
// 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!!
|
||||
return new Function<BuilderParameters, Cloner>() {
|
||||
@Override
|
||||
public Cloner apply(@Nullable BuilderParameters param) {
|
||||
return new FieldCloner(param.getAggregateCloner(), param.getInstanceProvider()) {{
|
||||
this.writer = new ObjectWriter() {
|
||||
protected void transformField(StructureModifier<Object> modifierSource,
|
||||
StructureModifier<Object> modifierDest, int fieldIndex) {
|
||||
// No need to clone inflated buffers
|
||||
if (modifierSource.getField(fieldIndex).getName().startsWith("inflatedBuffer"))
|
||||
modifierDest.write(fieldIndex, modifierSource.read(fieldIndex));
|
||||
else
|
||||
defaultTransform(modifierSource, modifierDest, getDefaultCloner(), fieldIndex);
|
||||
};
|
||||
};
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream output) throws IOException {
|
||||
// Default serialization
|
||||
output.defaultWriteObject();
|
||||
|
||||
// We'll take care of NULL packets as well
|
||||
output.writeBoolean(handle != null);
|
||||
|
||||
try {
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
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));
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IOException("Minecraft packet doesn't support DataOutputStream", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Insufficient security privileges.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new IOException("Could not serialize Minecraft packet.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
|
||||
// Default deserialization
|
||||
input.defaultReadObject();
|
||||
|
||||
// Get structure modifier
|
||||
structureModifier = StructureCache.getStructure(type);
|
||||
|
||||
// Don't read NULL packets
|
||||
if (input.readBoolean()) {
|
||||
|
||||
// Create a default instance of the packet
|
||||
handle = StructureCache.newPacket(type);
|
||||
|
||||
// Call the read method
|
||||
try {
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
ByteBuf buffer = createPacketBuffer();
|
||||
buffer.writeBytes(input, input.readInt());
|
||||
|
||||
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.");
|
||||
|
||||
getMethodLazily(readMethods, handle.getClass(), "read", DataInput.class).
|
||||
invoke(handle, new DataInputStream(input));
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IOException("Minecraft packet doesn't support DataInputStream", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Insufficient security privileges.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new IOException("Could not deserialize Minecraft packet.", e);
|
||||
}
|
||||
|
||||
// And we're done
|
||||
structureModifier = structureModifier.withTarget(handle);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new packet data serializer.
|
||||
* @return The packet data serializer.
|
||||
*/
|
||||
private ByteBuf createPacketBuffer() {
|
||||
return MinecraftReflection.getPacketDataSerializer(UnpooledByteBufAllocator.DEFAULT.buffer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the cached method concurrently.
|
||||
* @param lookup - a lazy lookup cache.
|
||||
* @param handleClass - class type of the current packet.
|
||||
* @param methodName - name of method to retrieve.
|
||||
* @param parameterClass - the one parameter type in the method.
|
||||
* @return Reflected method.
|
||||
*/
|
||||
private Method getMethodLazily(ConcurrentMap<Class<?>, Method> lookup,
|
||||
Class<?> handleClass, String methodName, Class<?> parameterClass) {
|
||||
Method method = lookup.get(handleClass);
|
||||
|
||||
// Atomic operation
|
||||
if (method == null) {
|
||||
Method initialized = FuzzyReflection.fromClass(handleClass).getMethod(
|
||||
FuzzyMethodContract.newBuilder().
|
||||
parameterCount(1).
|
||||
parameterDerivedOf(parameterClass).
|
||||
returnTypeVoid().
|
||||
build());
|
||||
method = lookup.putIfAbsent(handleClass, initialized);
|
||||
|
||||
// Use our version if we succeeded
|
||||
if (method == null) {
|
||||
method = initialized;
|
||||
}
|
||||
}
|
||||
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents an equivalent converter for ItemStack arrays.
|
||||
* @author Kristian
|
||||
*/
|
||||
private static class ItemStackArrayConverter implements EquivalentConverter<ItemStack[]> {
|
||||
final EquivalentConverter<ItemStack> stackConverter = BukkitConverters.getItemStackConverter();
|
||||
|
||||
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]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getSpecific(Object generic) {
|
||||
Object[] input = (Object[]) generic;
|
||||
ItemStack[] result = new ItemStack[input.length];
|
||||
|
||||
// Add the wrapper
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = stackConverter.getSpecific(input[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ItemStack[]> getSpecificType() {
|
||||
return ItemStack[].class;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-72
@@ -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,17 +23,15 @@ import java.io.ObjectOutputStream;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.EventObject;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
|
||||
import com.comphenix.protocol.Application;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.async.AsyncMarker;
|
||||
import com.comphenix.protocol.error.PluginContext;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.server.TemporaryPlayer;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
@@ -41,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
|
||||
*/
|
||||
@@ -49,8 +47,8 @@ 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 =
|
||||
Multimaps.synchronizedSetMultimap(HashMultimap.create());
|
||||
private static final SetMultimap<PacketType, PacketType> CHANGE_WARNINGS =
|
||||
Multimaps.synchronizedSetMultimap(HashMultimap.<PacketType, PacketType>create());
|
||||
|
||||
/**
|
||||
* Automatically generated by Eclipse.
|
||||
@@ -58,7 +56,8 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
private static final long serialVersionUID = -5360289379097430620L;
|
||||
|
||||
private transient WeakReference<Player> playerReference;
|
||||
|
||||
private transient Player offlinePlayer;
|
||||
|
||||
private PacketContainer packet;
|
||||
private boolean serverPacket;
|
||||
private boolean cancel;
|
||||
@@ -89,7 +88,7 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
private PacketEvent(Object source, PacketContainer packet, NetworkMarker marker, Player player, boolean serverPacket, boolean filtered) {
|
||||
super(source);
|
||||
this.packet = packet;
|
||||
this.playerReference = new WeakReference<>(player);
|
||||
this.playerReference = new WeakReference<Player>(player);
|
||||
this.networkMarker = marker;
|
||||
this.serverPacket = serverPacket;
|
||||
this.filtered = filtered;
|
||||
@@ -98,7 +97,7 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
private PacketEvent(PacketEvent origial, AsyncMarker asyncMarker) {
|
||||
super(origial.source);
|
||||
this.packet = origial.packet;
|
||||
this.playerReference = origial.getPlayerReference();
|
||||
this.playerReference = origial.playerReference;
|
||||
this.cancel = origial.cancel;
|
||||
this.serverPacket = origial.serverPacket;
|
||||
this.filtered = origial.filtered;
|
||||
@@ -203,7 +202,7 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
public boolean isAsync() {
|
||||
return !Bukkit.isPrimaryThread();
|
||||
return !Application.isPrimaryThread();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,9 +229,9 @@ 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(PluginContext.getPluginCaller(new Exception()), oldType, newType).
|
||||
messageParam(oldType, newType).
|
||||
build());
|
||||
}
|
||||
}
|
||||
@@ -247,7 +246,7 @@ public class PacketEvent extends EventObject implements Cancellable {
|
||||
*/
|
||||
@Deprecated
|
||||
public int getPacketID() {
|
||||
return packet.getId();
|
||||
return packet.getID();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -262,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;
|
||||
}
|
||||
@@ -309,55 +307,18 @@ 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.");
|
||||
this.cancel = cancel;
|
||||
}
|
||||
|
||||
private WeakReference<Player> getPlayerReference() {
|
||||
Player player = playerReference.get();
|
||||
|
||||
if (player instanceof TemporaryPlayer) {
|
||||
Player updated = player.getPlayer();
|
||||
if (updated != null && !(updated instanceof TemporaryPlayer)) {
|
||||
playerReference.clear();
|
||||
playerReference = new WeakReference<>(updated);
|
||||
}
|
||||
}
|
||||
|
||||
return playerReference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the player that has sent the packet or is receiving it.
|
||||
* Retrieves the player that has sent the packet or is recieving it.
|
||||
* @return The player associated with this event.
|
||||
*/
|
||||
public Player getPlayer() {
|
||||
return getPlayerReference().get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the player in this PacketEvent is temporary (i.e. they don't have a true player instance yet).
|
||||
* Temporary players have a limited subset of methods that may be used:
|
||||
* <ul>
|
||||
* <li>getPlayer</li>
|
||||
* <li>getAddress</li>
|
||||
* <li>getServer</li>
|
||||
* <li>chat</li>
|
||||
* <li>sendMessage</li>
|
||||
* <li>kickPlayer</li>
|
||||
* <li>isOnline</li>
|
||||
* </ul>
|
||||
*
|
||||
* Anything else will throw an UnsupportedOperationException. Use this check before calling other methods when
|
||||
* dealing with packets early in the login sequence or if you get the aforementioned exception.
|
||||
*
|
||||
* @return True if the player is temporary, false if not.
|
||||
*/
|
||||
public boolean isPlayerTemporary() {
|
||||
return getPlayer() instanceof TemporaryPlayer;
|
||||
return playerReference.get();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -393,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.
|
||||
*/
|
||||
@@ -464,12 +425,11 @@ 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)
|
||||
Player player = getPlayer();
|
||||
output.writeObject(player != null ? new SerializedOfflinePlayer(player) : null);
|
||||
output.writeObject(playerReference.get() != null ? new SerializedOfflinePlayer(playerReference.get()) : null);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
|
||||
@@ -479,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
|
||||
Player offlinePlayer = serialized.getPlayer();
|
||||
playerReference = new WeakReference<>(offlinePlayer);
|
||||
offlinePlayer = serialized.getPlayer();
|
||||
playerReference = new WeakReference<Player>(offlinePlayer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PacketEvent[player=" + getPlayer() + ", packet=" + packet + "]";
|
||||
}
|
||||
}
|
||||
+10
-10
@@ -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.
|
||||
*/
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+6
-1
@@ -7,6 +7,7 @@ import org.bukkit.entity.Player;
|
||||
import com.comphenix.protocol.PacketStream;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
/**
|
||||
@@ -137,6 +138,10 @@ public class ScheduledPacket {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ScheduledPacket[packet=" + packet + ", target=" + target + ", filtered=" + filtered + "]";
|
||||
return Objects.toStringHelper(this)
|
||||
.add("packet", packet)
|
||||
.add("target", target)
|
||||
.add("filtered", filtered)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
/*
|
||||
* 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
|
||||
* 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.events;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.utility.EnhancerFactory;
|
||||
|
||||
/**
|
||||
* Represents a player object that can be serialized by Java.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
|
||||
|
||||
/**
|
||||
* Generated by Eclipse.
|
||||
*/
|
||||
private static final long serialVersionUID = -2728976288470282810L;
|
||||
|
||||
private transient Location bedSpawnLocation;
|
||||
|
||||
// Relevant data about an offline player
|
||||
private String name;
|
||||
private UUID uuid;
|
||||
private long firstPlayed;
|
||||
private long lastPlayed;
|
||||
private boolean operator;
|
||||
private boolean banned;
|
||||
private boolean playedBefore;
|
||||
private boolean online;
|
||||
private boolean whitelisted;
|
||||
|
||||
// Proxy helper
|
||||
private static Map<String, Method> lookup = new ConcurrentHashMap<String, Method>();
|
||||
|
||||
/**
|
||||
* Constructor used by serialization.
|
||||
*/
|
||||
public SerializedOfflinePlayer() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this serializable offline player from another player.
|
||||
* @param offline - another player.
|
||||
*/
|
||||
public SerializedOfflinePlayer(OfflinePlayer offline) {
|
||||
this.name = offline.getName();
|
||||
this.uuid = offline.getUniqueId();
|
||||
this.firstPlayed = offline.getFirstPlayed();
|
||||
this.lastPlayed = offline.getLastPlayed();
|
||||
this.operator = offline.isOp();
|
||||
this.banned = offline.isBanned();
|
||||
this.playedBefore = offline.hasPlayedBefore();
|
||||
this.online = offline.isOnline();
|
||||
this.whitelisted = offline.isWhitelisted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOp() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOp(boolean operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> serialize() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getBedSpawnLocation() {
|
||||
return bedSpawnLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getFirstPlayed() {
|
||||
return firstPlayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastPlayed() {
|
||||
return lastPlayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getUniqueId() {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPlayedBefore() {
|
||||
return playedBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBanned() {
|
||||
return banned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBanned(boolean banned) {
|
||||
this.banned = banned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOnline() {
|
||||
return online;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWhitelisted() {
|
||||
return whitelisted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWhitelisted(boolean whitelisted) {
|
||||
this.whitelisted = whitelisted;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream output) throws IOException {
|
||||
output.defaultWriteObject();
|
||||
|
||||
// Serialize the bed spawn location
|
||||
output.writeUTF(bedSpawnLocation.getWorld().getName());
|
||||
output.writeDouble(bedSpawnLocation.getX());
|
||||
output.writeDouble(bedSpawnLocation.getY());
|
||||
output.writeDouble(bedSpawnLocation.getZ());
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream input) throws ClassNotFoundException, IOException {
|
||||
input.defaultReadObject();
|
||||
|
||||
// Well, this is a problem
|
||||
bedSpawnLocation = new Location(
|
||||
getWorld(input.readUTF()),
|
||||
input.readDouble(),
|
||||
input.readDouble(),
|
||||
input.readDouble()
|
||||
);
|
||||
}
|
||||
|
||||
private World getWorld(String name) {
|
||||
try {
|
||||
// Try to get the world at least
|
||||
return Bukkit.getServer().getWorld(name);
|
||||
} catch (Exception e) {
|
||||
// Screw it
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Player getPlayer() {
|
||||
try {
|
||||
// Try to get the real player underneath
|
||||
return Bukkit.getServer().getPlayerExact(name);
|
||||
} catch (Exception e) {
|
||||
return getProxyPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a player object that implements OfflinePlayer by refering to this object.
|
||||
* <p>
|
||||
* All other methods cause an exception.
|
||||
* @return Proxy object.
|
||||
*/
|
||||
public Player getProxyPlayer() {
|
||||
|
||||
// Remember to initialize the method filter
|
||||
if (lookup.size() == 0) {
|
||||
// Add all public methods
|
||||
for (Method method : OfflinePlayer.class.getMethods()) {
|
||||
lookup.put(method.getName(), method);
|
||||
}
|
||||
}
|
||||
|
||||
// MORE CGLIB magic!
|
||||
Enhancer ex = EnhancerFactory.getInstance().createEnhancer();
|
||||
ex.setSuperclass(Player.class);
|
||||
ex.setCallback(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
|
||||
// There's no overloaded methods, so we don't care
|
||||
Method offlineMethod = lookup.get(method.getName());
|
||||
|
||||
// Ignore all other methods
|
||||
if (offlineMethod == null) {
|
||||
throw new UnsupportedOperationException(
|
||||
"The method " + method.getName() + " is not supported for offline players.");
|
||||
}
|
||||
|
||||
// Invoke our on method
|
||||
return offlineMethod.invoke(SerializedOfflinePlayer.this, args);
|
||||
}
|
||||
});
|
||||
|
||||
return (Player) ex.create();
|
||||
}
|
||||
}
|
||||
+18
-57
@@ -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,9 +24,6 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
@@ -34,7 +31,6 @@ import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
/**
|
||||
@@ -42,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
|
||||
@@ -95,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);
|
||||
|
||||
@@ -153,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) {
|
||||
@@ -163,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) {
|
||||
@@ -182,59 +178,24 @@ 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) {
|
||||
// Maybe it's a proxy?
|
||||
Unwrapper proxyUnwrapper = getProxyUnwrapper(type);
|
||||
if (proxyUnwrapper != null)
|
||||
return proxyUnwrapper;
|
||||
|
||||
// Try getting the field unwrapper too
|
||||
Unwrapper fieldUnwrapper = getFieldUnwrapper(type);
|
||||
|
||||
if (fieldUnwrapper != null)
|
||||
return fieldUnwrapper;
|
||||
else
|
||||
reporter.reportDetailed(this,
|
||||
reporter.reportDetailed(this,
|
||||
Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
|
||||
}
|
||||
|
||||
|
||||
// Default method
|
||||
return null;
|
||||
}
|
||||
|
||||
// Players should /always/ be able to be unwrapped
|
||||
// We should only get here if the 'Player' is a proxy
|
||||
private Unwrapper getProxyUnwrapper(final Class<?> type) {
|
||||
try {
|
||||
if (Player.class.isAssignableFrom(type)) {
|
||||
final Method getHandle = MinecraftReflection.getCraftPlayerClass().getMethod("getHandle");
|
||||
|
||||
Unwrapper unwrapper = new Unwrapper() {
|
||||
@Override
|
||||
public Object unwrapItem(Object wrapped) {
|
||||
try {
|
||||
return getHandle.invoke(((Player) wrapped).getPlayer());
|
||||
} catch (Throwable ex) {
|
||||
try {
|
||||
return getHandle.invoke(Bukkit.getPlayer(((Player) wrapped).getUniqueId()));
|
||||
} catch (ReflectiveOperationException ex1) {
|
||||
throw new RuntimeException("Failed to unwrap proxy " + wrapped, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
unwrapperCache.put(type, unwrapper);
|
||||
return unwrapper;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve a cached unwrapper using the handle field.
|
||||
* @param type - a cached field unwrapper.
|
||||
@@ -253,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;
|
||||
@@ -266,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;
|
||||
@@ -0,0 +1,480 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import com.comphenix.protocol.AsynchronousManager;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
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.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.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
/**
|
||||
* A protocol manager that delays all packet listener registrations and unregistrations until
|
||||
* an underlying protocol manager can be constructed.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
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_REGISTER_QUEUED_LISTENER = new ReportType("Cannot register queued listener %s.");
|
||||
|
||||
private volatile InternalManager delegate;
|
||||
|
||||
// Queued actions
|
||||
private final List<Runnable> queuedActions = Collections.synchronizedList(Lists.<Runnable>newArrayList());
|
||||
private final List<PacketListener> queuedListeners = Collections.synchronizedList(Lists.<PacketListener>newArrayList());
|
||||
|
||||
private AsynchronousManager asyncManager;
|
||||
private ErrorReporter reporter;
|
||||
|
||||
// The current hook
|
||||
private PlayerInjectHooks hook = PlayerInjectHooks.NETWORK_SERVER_OBJECT;
|
||||
|
||||
// If we have been closed
|
||||
private boolean closed;
|
||||
private boolean debug;
|
||||
|
||||
// Queued registration
|
||||
private PluginManager queuedManager;
|
||||
private Plugin queuedPlugin;
|
||||
|
||||
private MinecraftVersion version;
|
||||
|
||||
public DelayedPacketManager(@Nonnull ErrorReporter reporter, @Nonnull MinecraftVersion version) {
|
||||
Preconditions.checkNotNull(reporter, "reporter cannot be NULL.");
|
||||
Preconditions.checkNotNull(version, "version cannot be NULL.");
|
||||
|
||||
this.reporter = reporter;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the underlying protocol manager.
|
||||
* @return The underlying manager.
|
||||
*/
|
||||
public InternalManager getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProtocolVersion(Player player) {
|
||||
if (delegate != null)
|
||||
return delegate.getProtocolVersion(player);
|
||||
else
|
||||
return Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MinecraftVersion getMinecraftVersion() {
|
||||
if (delegate != null)
|
||||
return delegate.getMinecraftVersion();
|
||||
else
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the delegate to the underlying manager.
|
||||
* <p>
|
||||
* This will prompt this packet manager to immediately transmit and
|
||||
* register all queued packets an listeners.
|
||||
* @param delegate - delegate to the new manager.
|
||||
*/
|
||||
protected void setDelegate(InternalManager delegate) {
|
||||
this.delegate = delegate;
|
||||
|
||||
if (delegate != null) {
|
||||
// Update the hook if needed
|
||||
if (!Objects.equal(delegate.getPlayerHook(), hook)) {
|
||||
delegate.setPlayerHook(hook);
|
||||
}
|
||||
// Register events as well
|
||||
if (queuedManager != null && queuedPlugin != null) {
|
||||
delegate.registerEvents(queuedManager, queuedPlugin);
|
||||
}
|
||||
// And update the debug mode
|
||||
delegate.setDebug(debug);
|
||||
|
||||
// Add any pending listeners
|
||||
synchronized (queuedListeners) {
|
||||
for (PacketListener listener : queuedListeners) {
|
||||
try {
|
||||
delegate.addPacketListener(listener);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// Inform about this plugin error
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_CANNOT_REGISTER_QUEUED_LISTENER).
|
||||
callerParam(delegate).messageParam(listener).error(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute any delayed actions
|
||||
synchronized (queuedActions) {
|
||||
for (Runnable action : queuedActions) {
|
||||
action.run();
|
||||
}
|
||||
}
|
||||
|
||||
// Don't keep this around anymore
|
||||
queuedListeners.clear();
|
||||
queuedActions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable queuedAddPacket(final ConnectionSide side, final Player player, final PacketContainer packet,
|
||||
final NetworkMarker marker, final boolean filtered) {
|
||||
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// Attempt to send it now
|
||||
switch (side) {
|
||||
case CLIENT_SIDE:
|
||||
delegate.recieveClientPacket(player, packet, marker, filtered);
|
||||
break;
|
||||
case SERVER_SIDE:
|
||||
delegate.sendServerPacket(player, packet, marker, filtered);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("side cannot be " + side);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Inform about this plugin error
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_CANNOT_SEND_QUEUED_PACKET).
|
||||
callerParam(delegate).messageParam(packet).error(e));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerHook(PlayerInjectHooks playerHook) {
|
||||
this.hook = playerHook;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerInjectHooks getPlayerHook() {
|
||||
return hook;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Player receiver, PacketContainer packet) throws InvocationTargetException {
|
||||
sendServerPacket(receiver, packet, null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Player receiver, PacketContainer packet, boolean filters) throws InvocationTargetException {
|
||||
sendServerPacket(receiver, packet, null, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendServerPacket(Player receiver, PacketContainer packet, NetworkMarker marker, boolean filters) throws InvocationTargetException {
|
||||
if (delegate != null) {
|
||||
delegate.sendServerPacket(receiver, packet, marker, filters);
|
||||
} else {
|
||||
queuedActions.add(queuedAddPacket(ConnectionSide.SERVER_SIDE, receiver, packet, marker, filters));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recieveClientPacket(Player sender, PacketContainer packet) throws IllegalAccessException, InvocationTargetException {
|
||||
recieveClientPacket(sender, packet, null, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recieveClientPacket(Player sender, PacketContainer packet, boolean filters) throws IllegalAccessException, InvocationTargetException {
|
||||
recieveClientPacket(sender, packet, null, filters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recieveClientPacket(Player sender, PacketContainer packet, NetworkMarker marker, boolean filters) throws IllegalAccessException, InvocationTargetException {
|
||||
if (delegate != null) {
|
||||
delegate.recieveClientPacket(sender, packet, marker, filters);
|
||||
} else {
|
||||
queuedActions.add(queuedAddPacket(ConnectionSide.CLIENT_SIDE, sender, packet, marker, filters));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastServerPacket(final PacketContainer packet, final Entity entity, final boolean includeTracker) {
|
||||
if (delegate != null) {
|
||||
delegate.broadcastServerPacket(packet, entity, includeTracker);
|
||||
} else {
|
||||
queuedActions.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.broadcastServerPacket(packet, entity, includeTracker);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastServerPacket(final PacketContainer packet, final Location origin, final int maxObserverDistance) {
|
||||
if (delegate != null) {
|
||||
delegate.broadcastServerPacket(packet, origin, maxObserverDistance);
|
||||
} else {
|
||||
queuedActions.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.broadcastServerPacket(packet, origin, maxObserverDistance);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastServerPacket(final PacketContainer packet) {
|
||||
if (delegate != null) {
|
||||
delegate.broadcastServerPacket(packet);
|
||||
} else {
|
||||
queuedActions.add(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.broadcastServerPacket(packet);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImmutableSet<PacketListener> getPacketListeners() {
|
||||
if (delegate != null)
|
||||
return delegate.getPacketListeners();
|
||||
else
|
||||
return ImmutableSet.copyOf(queuedListeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPacketListener(PacketListener listener) {
|
||||
if (delegate != null)
|
||||
delegate.addPacketListener(listener);
|
||||
else
|
||||
queuedListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePacketListener(PacketListener listener) {
|
||||
if (delegate != null)
|
||||
delegate.removePacketListener(listener);
|
||||
else
|
||||
queuedListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removePacketListeners(Plugin plugin) {
|
||||
if (delegate != null) {
|
||||
delegate.removePacketListeners(plugin);
|
||||
} else {
|
||||
for (Iterator<PacketListener> it = queuedListeners.iterator(); it.hasNext(); ) {
|
||||
// Remove listeners of the same plugin
|
||||
if (Objects.equal(it.next().getPlugin(), plugin)) {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PacketContainer createPacket(int id) {
|
||||
if (delegate != null)
|
||||
return delegate.createPacket(id);
|
||||
return createPacket(id, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PacketContainer createPacket(int id, boolean forceDefaults) {
|
||||
if (delegate != null) {
|
||||
return delegate.createPacket(id);
|
||||
} else {
|
||||
// Fallback implementation
|
||||
PacketContainer packet = new PacketContainer(id);
|
||||
|
||||
// Use any default values if possible
|
||||
if (forceDefaults) {
|
||||
try {
|
||||
packet.getModifier().writeDefaults();
|
||||
} catch (FieldAccessException e) {
|
||||
throw new RuntimeException("Security exception.", e);
|
||||
}
|
||||
}
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public PacketConstructor createPacketConstructor(int id, Object... arguments) {
|
||||
if (delegate != null)
|
||||
return delegate.createPacketConstructor(id, arguments);
|
||||
else
|
||||
return PacketConstructor.DEFAULT.withPacket(id, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketConstructor createPacketConstructor(PacketType type, Object... arguments) {
|
||||
if (delegate != null)
|
||||
return delegate.createPacketConstructor(type, arguments);
|
||||
else
|
||||
return PacketConstructor.DEFAULT.withPacket(type, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Set<Integer> getSendingFilters() {
|
||||
if (delegate != null) {
|
||||
return delegate.getSendingFilters();
|
||||
} else {
|
||||
// Linear scan is fast enough here
|
||||
Set<Integer> sending = Sets.newHashSet();
|
||||
|
||||
for (PacketListener listener : queuedListeners) {
|
||||
sending.addAll(listener.getSendingWhitelist().getWhitelist());
|
||||
}
|
||||
return sending;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Set<Integer> getReceivingFilters() {
|
||||
if (delegate != null) {
|
||||
return delegate.getReceivingFilters();
|
||||
} else {
|
||||
Set<Integer> recieving = Sets.newHashSet();
|
||||
|
||||
for (PacketListener listener : queuedListeners) {
|
||||
recieving.addAll(listener.getReceivingWhitelist().getWhitelist());
|
||||
}
|
||||
return recieving;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer createPacket(PacketType type) {
|
||||
return createPacket(type.getLegacyId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer createPacket(PacketType type, boolean forceDefaults) {
|
||||
return createPacket(type.getLegacyId(), forceDefaults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PacketType> getSendingFilterTypes() {
|
||||
return PacketRegistry.toPacketTypes(getSendingFilters(), Sender.SERVER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<PacketType> getReceivingFilterTypes() {
|
||||
return PacketRegistry.toPacketTypes(getReceivingFilters(), Sender.CLIENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
|
||||
if (delegate != null)
|
||||
delegate.updateEntity(entity, observers);
|
||||
else
|
||||
EntityUtilities.updateEntity(entity, observers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getEntityFromID(World container, int id) throws FieldAccessException {
|
||||
if (delegate != null)
|
||||
return delegate.getEntityFromID(container, id);
|
||||
else
|
||||
return EntityUtilities.getEntityFromID(container, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Player> getEntityTrackers(Entity entity) throws FieldAccessException {
|
||||
if (delegate != null)
|
||||
return delegate.getEntityTrackers(entity);
|
||||
else
|
||||
return EntityUtilities.getEntityTrackers(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return closed || (delegate != null && delegate.isClosed());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AsynchronousManager getAsynchronousManager() {
|
||||
if (delegate != null)
|
||||
return delegate.getAsynchronousManager();
|
||||
else
|
||||
return asyncManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
|
||||
if (delegate != null) {
|
||||
delegate.setDebug(debug);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the asynchronous manager. This must be set.
|
||||
* @param asyncManager - the asynchronous manager.
|
||||
*/
|
||||
public void setAsynchronousManager(AsynchronousManager asyncManager) {
|
||||
this.asyncManager = asyncManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEvents(PluginManager manager, Plugin plugin) {
|
||||
if (delegate != null) {
|
||||
delegate.registerEvents(manager, plugin);
|
||||
} else {
|
||||
queuedManager = manager;
|
||||
queuedPlugin = plugin;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (delegate != null)
|
||||
delegate.close();
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* 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
|
||||
* 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;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
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;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.WrappedIntHashMap;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
/**
|
||||
* Used to perform certain operations on entities.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
class EntityUtilities {
|
||||
|
||||
private static Field entityTrackerField;
|
||||
private static Field trackedEntitiesField;
|
||||
private static Field trackedPlayersField;
|
||||
private static Field trackerField;
|
||||
|
||||
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
|
||||
* version of the following:
|
||||
*
|
||||
* @SuppressWarnings("unchecked")
|
||||
* public static void updateEntity2(Entity entity, List<Player> observers) {
|
||||
*
|
||||
* World world = entity.getWorld();
|
||||
* WorldServer worldServer = ((CraftWorld) world).getHandle();
|
||||
*
|
||||
* EntityTracker tracker = worldServer.tracker;
|
||||
* EntityTrackerEntry entry = (EntityTrackerEntry) tracker.trackedEntities.get(entity.getEntityId());
|
||||
*
|
||||
* List<EntityPlayer> nmsPlayers = getNmsPlayers(observers);
|
||||
*
|
||||
* entry.trackedPlayers.removeAll(nmsPlayers);
|
||||
* entry.scanPlayers(nmsPlayers);
|
||||
* }
|
||||
*
|
||||
* private static List<EntityPlayer> getNmsPlayers(List<Player> players) {
|
||||
* List<EntityPlayer> nsmPlayers = new ArrayList<EntityPlayer>();
|
||||
*
|
||||
* for (Player bukkitPlayer : players) {
|
||||
* CraftPlayer craftPlayer = (CraftPlayer) bukkitPlayer;
|
||||
* nsmPlayers.add(craftPlayer.getHandle());
|
||||
* }
|
||||
*
|
||||
* return nsmPlayers;
|
||||
* }
|
||||
*
|
||||
*/
|
||||
public static void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
|
||||
try {
|
||||
// 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 = getCollection(FieldUtils.readField(trackedPlayersField, trackerEntry, false));
|
||||
List<Object> nmsPlayers = unwrapBukkit(observers);
|
||||
|
||||
trackedPlayers.removeAll(nmsPlayers);
|
||||
|
||||
// We have to rely on a NAME once again. Damn it.
|
||||
if (scanPlayersMethod == null) {
|
||||
scanPlayersMethod = trackerEntry.getClass().getMethod("scanPlayers", List.class);
|
||||
}
|
||||
|
||||
scanPlayersMethod.invoke(trackerEntry, nmsPlayers);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw e;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Security limitation prevents access to 'get' method in IntHashMap", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("Exception occurred in Minecraft.", e);
|
||||
} catch (SecurityException e) {
|
||||
throw new FieldAccessException("Security limitation prevents access to 'scanPlayers' method in trackerEntry.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new FieldAccessException("Cannot find 'scanPlayers' method. Is ProtocolLib up to date?", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every client that is receiving information about a given entity.
|
||||
* @param entity - the entity that is being tracked.
|
||||
* @return Every client/player that is tracking the given entity.
|
||||
* @throws FieldAccessException If reflection failed.
|
||||
*/
|
||||
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." : "."));
|
||||
}
|
||||
|
||||
if (trackedPlayersField == null) {
|
||||
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
|
||||
}
|
||||
|
||||
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) {
|
||||
if (MinecraftReflection.isMinecraftPlayer(tracker)) {
|
||||
result.add((Player) MinecraftReflection.getBukkitEntity(tracker));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the entity tracker entry given a ID.
|
||||
* @param world - world server.
|
||||
* @param entityID - entity ID.
|
||||
* @return The entity tracker entry.
|
||||
* @throws FieldAccessException
|
||||
*/
|
||||
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
Object worldServer = unwrapper.unwrapItem(world);
|
||||
|
||||
if (entityTrackerField == null)
|
||||
entityTrackerField = FuzzyReflection.fromObject(worldServer).
|
||||
getFieldByType("tracker", MinecraftReflection.getEntityTrackerClass());
|
||||
|
||||
// Get the tracker
|
||||
Object tracker = null;
|
||||
|
||||
try {
|
||||
tracker = FieldUtils.readField(entityTrackerField, worldServer, false);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Cannot access 'tracker' field due to security limitations.", e);
|
||||
}
|
||||
|
||||
if (trackedEntitiesField == null) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Set<Class> ignoredTypes = new HashSet<Class>();
|
||||
|
||||
// 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()) {
|
||||
ignoredTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
// The Minecraft field that's NOT filled in by the constructor
|
||||
trackedEntitiesField = FuzzyReflection.fromObject(tracker, true).
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectRegex(), ignoredTypes);
|
||||
}
|
||||
|
||||
// Read the entity hashmap
|
||||
Object trackedEntities = null;
|
||||
|
||||
try {
|
||||
trackedEntities = FieldUtils.readField(trackedEntitiesField, tracker, true);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Cannot access 'trackedEntities' field due to security limitations.", e);
|
||||
}
|
||||
|
||||
return WrappedIntHashMap.fromHandle(trackedEntities).get(entityID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve entity from a ID, even it it's newly created.
|
||||
* @return The asssociated entity.
|
||||
* @throws FieldAccessException Reflection error.
|
||||
*/
|
||||
public static Entity getEntityFromID(World world, int entityID) throws FieldAccessException {
|
||||
try {
|
||||
Object trackerEntry = getEntityTrackerEntry(world, entityID);
|
||||
Object tracker = null;
|
||||
|
||||
// Handle NULL cases
|
||||
if (trackerEntry != null) {
|
||||
if (trackerField == null) {
|
||||
try {
|
||||
trackerField = trackerEntry.getClass().getField("tracker");
|
||||
} catch (NoSuchFieldException e) {
|
||||
// Assume it's the first public entity field then
|
||||
trackerField = FuzzyReflection.fromObject(trackerEntry).getFieldByType(
|
||||
"tracker", MinecraftReflection.getEntityClass());
|
||||
}
|
||||
}
|
||||
|
||||
tracker = FieldUtils.readField(trackerField, trackerEntry, true);
|
||||
}
|
||||
|
||||
// If the tracker is NULL, we'll just assume this entity doesn't exist
|
||||
if (tracker != null)
|
||||
return (Entity) MinecraftReflection.getBukkitEntity(tracker);
|
||||
else
|
||||
return null;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new FieldAccessException("Cannot find entity from ID " + entityID + ".", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Object> unwrapBukkit(List<Player> players) {
|
||||
|
||||
List<Object> output = Lists.newArrayList();
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
|
||||
// Get the NMS equivalent
|
||||
for (Player player : players) {
|
||||
Object result = unwrapper.unwrapItem(player);
|
||||
|
||||
if (result != null)
|
||||
output.add(result);
|
||||
else
|
||||
throw new IllegalArgumentException("Cannot unwrap item " + player);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+1
@@ -4,6 +4,7 @@ import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||
|
||||
/**
|
||||
* Yields access to the internal hook configuration.
|
||||
+43
-5
@@ -19,6 +19,7 @@ package com.comphenix.protocol.injector;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.injector.packet.InterceptWritePacket;
|
||||
|
||||
/**
|
||||
* Represents an object that initiate the packet listeners.
|
||||
@@ -31,13 +32,13 @@ public interface ListenerInvoker {
|
||||
* Invokes the given packet event for every registered listener.
|
||||
* @param event - the packet event to invoke.
|
||||
*/
|
||||
void invokePacketRecieving(PacketEvent event);
|
||||
public abstract void invokePacketRecieving(PacketEvent event);
|
||||
|
||||
/**
|
||||
* Invokes the given packet event for every registered listener.
|
||||
* @param event - the packet event to invoke.
|
||||
*/
|
||||
void invokePacketSending(PacketEvent event);
|
||||
public abstract void invokePacketSending(PacketEvent event);
|
||||
|
||||
/**
|
||||
* Retrieve the associated ID of a packet.
|
||||
@@ -45,12 +46,49 @@ public interface ListenerInvoker {
|
||||
* @return The packet ID.
|
||||
*/
|
||||
@Deprecated
|
||||
int getPacketID(Object packet);
|
||||
public abstract int getPacketID(Object packet);
|
||||
|
||||
/**
|
||||
* Retrieve the associated type of a packet.
|
||||
* @param packet - the packet.
|
||||
* @return The packet type.
|
||||
*/
|
||||
PacketType getPacketType(Object packet);
|
||||
}
|
||||
public abstract PacketType getPacketType(Object packet);
|
||||
|
||||
/**
|
||||
* Retrieve the object responsible for intercepting write packets.
|
||||
* @return Object that intercepts write packets.
|
||||
*/
|
||||
public InterceptWritePacket getInterceptWritePacket();
|
||||
|
||||
/**
|
||||
* Determine if a given packet requires input buffering.
|
||||
* @param packetId - the packet to check.
|
||||
* @return TRUE if it does, FALSE otherwise.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean requireInputBuffer(int packetId);
|
||||
|
||||
/**
|
||||
* Associate a given class with the given packet ID. Internal method.
|
||||
* @param clazz - class to associate.
|
||||
*/
|
||||
public abstract void unregisterPacketClass(Class<?> clazz);
|
||||
|
||||
/**
|
||||
* Register a given class in the packet registry. Internal method.
|
||||
* @param clazz - class to register.
|
||||
* @param packetID - the the new associated packet ID.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract void registerPacketClass(Class<?> clazz, int packetID);
|
||||
|
||||
/**
|
||||
* Retrieves the correct packet class from a given packet ID.
|
||||
* @param packetID - the packet ID.
|
||||
* @param forceVanilla - whether or not to look for vanilla classes, not injected classes.
|
||||
* @return The associated class.
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract Class<?> getPacketClassFromID(int packetID, boolean forceVanilla);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.Packets;
|
||||
import com.comphenix.protocol.concurrency.IntegerSet;
|
||||
import com.comphenix.protocol.events.ConnectionSide;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
/**
|
||||
* Packets that are known to be transmitted during login.
|
||||
* <p>
|
||||
* This may be dynamically extended later.
|
||||
* @author Kristian
|
||||
*/
|
||||
class LoginPackets {
|
||||
private IntegerSet clientSide = new IntegerSet(Packets.PACKET_COUNT);
|
||||
private IntegerSet serverSide = new IntegerSet(Packets.PACKET_COUNT);
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public LoginPackets(MinecraftVersion version) {
|
||||
// Ordinary login
|
||||
clientSide.add(Packets.Client.HANDSHAKE);
|
||||
serverSide.add(Packets.Server.KEY_REQUEST);
|
||||
clientSide.add(Packets.Client.KEY_RESPONSE);
|
||||
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
|
||||
if (version.compareTo(MinecraftVersion.HORSE_UPDATE) >= 0 || triesForgeIntegration()) {
|
||||
clientSide.add(Packets.Client.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 runnign MCPC.
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
private static boolean triesForgeIntegration() {
|
||||
String version = Bukkit.getVersion();
|
||||
return version.contains("MCPC-Plus") || version.contains("Cauldron") || version.contains("Thermos");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a packet may be sent during login from a given direction.
|
||||
* @param packetId - the ID of the packet.
|
||||
* @param side - the direction.
|
||||
* @return TRUE if it may, FALSE otherwise.
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean isLoginPacket(int packetId, ConnectionSide side) {
|
||||
switch (side) {
|
||||
case CLIENT_SIDE:
|
||||
return clientSide.contains(packetId);
|
||||
case SERVER_SIDE:
|
||||
return serverSide.contains(packetId);
|
||||
case BOTH:
|
||||
return clientSide.contains(packetId) ||
|
||||
serverSide.contains(packetId);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unknown connection side: " + side);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given packet may be sent during login.
|
||||
* @param type - the packet type.
|
||||
* @return TRUE if it may, FALSE otherwise.
|
||||
*/
|
||||
public boolean isLoginPacket(PacketType type) {
|
||||
if (!MinecraftReflection.isUsingNetty())
|
||||
return isLoginPacket(type.getLegacyId(), type.getSender().toSide());
|
||||
|
||||
return PacketType.Login.Client.getInstance().hasMember(type) ||
|
||||
PacketType.Login.Server.getInstance().hasMember(type) ||
|
||||
PacketType.Status.Client.getInstance().hasMember(type) ||
|
||||
PacketType.Status.Server.getInstance().hasMember(type);
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -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) {
|
||||
+28
-12
@@ -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) {
|
||||
@@ -81,7 +81,7 @@ public class PacketConstructor {
|
||||
*/
|
||||
@Deprecated
|
||||
public int getPacketID() {
|
||||
return type.getCurrentId();
|
||||
return type.getLegacyId();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -101,10 +101,26 @@ public class PacketConstructor {
|
||||
return new PacketConstructor(type, constructorMethod, unwrappers, paramUnwrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #withPacket(PacketType, Object[])} instead.
|
||||
* @param id - legacy (1.6.4) packet ID.
|
||||
* @param values - the values that will match each parameter in the desired constructor.
|
||||
* @return A packet constructor with these types.
|
||||
* @throws IllegalArgumentException If no packet constructor could be created with these types.
|
||||
*/
|
||||
@Deprecated
|
||||
public PacketConstructor withPacket(int id, Object[] values) {
|
||||
return withPacket(PacketType.findLegacy(id), values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@@ -113,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
|
||||
@@ -242,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.
|
||||
+69
-4
@@ -2,14 +2,26 @@ package com.comphenix.protocol.injector;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.event.world.WorldInitEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.executors.BukkitFutures;
|
||||
import com.comphenix.protocol.async.AsyncFilterManager;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.player.InjectedServerConnection;
|
||||
import com.comphenix.protocol.injector.spigot.SpigotPacketInjector;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
|
||||
public class PacketFilterBuilder {
|
||||
public static final ReportType REPORT_TEMPORARY_EVENT_ERROR = new ReportType("Unable to register or handle temporary event.");
|
||||
public static final ReportType REPORT_SPIGOT_IS_DELAYING_INJECTOR = new ReportType("Delaying due to Spigot.");
|
||||
|
||||
private ClassLoader classLoader;
|
||||
private Server server;
|
||||
private Plugin library;
|
||||
@@ -173,10 +185,63 @@ public class PacketFilterBuilder {
|
||||
|
||||
asyncManager = new AsyncFilterManager(reporter, server.getScheduler());
|
||||
nettyEnabled = false;
|
||||
|
||||
// Spigot
|
||||
if (SpigotPacketInjector.canUseSpigotListener()) {
|
||||
// If the server hasn't loaded yet - wait
|
||||
if (InjectedServerConnection.getServerConnection(reporter, server) == null) {
|
||||
// We need to delay this until we know if Netty is enabled
|
||||
final DelayedPacketManager delayed = new DelayedPacketManager(reporter, mcVersion);
|
||||
|
||||
// They must reference each other
|
||||
delayed.setAsynchronousManager(asyncManager);
|
||||
asyncManager.setManager(delayed);
|
||||
|
||||
Futures.addCallback(BukkitFutures.nextEvent(library, WorldInitEvent.class),
|
||||
new FutureCallback<WorldInitEvent>() {
|
||||
@Override
|
||||
public void onSuccess(WorldInitEvent event) {
|
||||
// Nevermind
|
||||
if (delayed.isClosed())
|
||||
return;
|
||||
|
||||
try {
|
||||
registerSpigot(delayed);
|
||||
} catch (Exception e) {
|
||||
onFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable error) {
|
||||
reporter.reportWarning(PacketFilterBuilder.this, Report
|
||||
.newBuilder(REPORT_TEMPORARY_EVENT_ERROR).error(error));
|
||||
}
|
||||
});
|
||||
|
||||
reporter.reportWarning(this, Report.newBuilder(REPORT_SPIGOT_IS_DELAYING_INJECTOR));
|
||||
|
||||
// Let plugins use this version instead
|
||||
return delayed;
|
||||
} else {
|
||||
nettyEnabled = !MinecraftReflection.isMinecraftObject(
|
||||
InjectedServerConnection.getServerConnection(reporter, server));
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise - construct the packet filter manager right away
|
||||
return buildInternal();
|
||||
}
|
||||
|
||||
private void registerSpigot(DelayedPacketManager delayed) {
|
||||
// Use netty if we have a non-standard ServerConnection class
|
||||
nettyEnabled = !MinecraftReflection.isMinecraftObject(
|
||||
InjectedServerConnection.getServerConnection(reporter, server));
|
||||
|
||||
// Switch to the standard manager
|
||||
delayed.setDelegate(buildInternal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new packet filter manager without checking for Netty.
|
||||
* @return A new packet filter manager.
|
||||
+375
-110
@@ -18,39 +18,19 @@
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.comphenix.protocol.AsynchronousManager;
|
||||
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.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.events.*;
|
||||
import com.comphenix.protocol.injector.netty.ProtocolInjector;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
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.player.PlayerInjectionHandler.ConflictStrategy;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
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.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import net.sf.cglib.proxy.Enhancer;
|
||||
import net.sf.cglib.proxy.MethodInterceptor;
|
||||
import net.sf.cglib.proxy.MethodProxy;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
@@ -68,6 +48,45 @@ import org.bukkit.event.server.PluginDisableEvent;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
|
||||
import com.comphenix.protocol.AsynchronousManager;
|
||||
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.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.ListenerPriority;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.NetworkMarker;
|
||||
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.NettyProtocolInjector;
|
||||
import com.comphenix.protocol.injector.packet.InterceptWritePacket;
|
||||
import com.comphenix.protocol.injector.packet.PacketInjector;
|
||||
import com.comphenix.protocol.injector.packet.PacketInjectorBuilder;
|
||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler.ConflictStrategy;
|
||||
import com.comphenix.protocol.injector.player.PlayerInjector.ServerHandlerNull;
|
||||
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.google.common.base.Objects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
public final class PacketFilterManager implements ListenerInvoker, InternalManager {
|
||||
|
||||
public static final ReportType REPORT_CANNOT_LOAD_PACKET_LIST = new ReportType("Cannot load server and client packet list.");
|
||||
@@ -77,8 +96,8 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
new ReportType("%s doesn't depend on ProtocolLib. Check that its plugin.yml has a 'depend' directive.");
|
||||
|
||||
// Registering packet IDs that are not supported
|
||||
public static final ReportType REPORT_UNSUPPORTED_SERVER_PACKET = new ReportType("[%s] Unsupported server packet in current Minecraft version: %s");
|
||||
public static final ReportType REPORT_UNSUPPORTED_CLIENT_PACKET = new ReportType("[%s] Unsupported client packet in current Minecraft version: %s");
|
||||
public static final ReportType REPORT_UNSUPPORTED_SERVER_PACKET_ID = new ReportType("[%s] Unsupported server packet ID in current Minecraft version: %s");
|
||||
public static final ReportType REPORT_UNSUPPORTED_CLIENT_PACKET_ID = new ReportType("[%s] Unsupported client packet ID in current Minecraft version: %s");
|
||||
|
||||
// Problems injecting and uninjecting players
|
||||
public static final ReportType REPORT_CANNOT_UNINJECT_PLAYER = new ReportType("Unable to uninject net handler for player.");
|
||||
@@ -93,6 +112,36 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
*/
|
||||
public static final int TICKS_PER_SECOND = 20;
|
||||
|
||||
/**
|
||||
* Sets the inject hook type. Different types allow for maximum compatibility.
|
||||
* @author Kristian
|
||||
*/
|
||||
public enum PlayerInjectHooks {
|
||||
/**
|
||||
* The injection hook that does nothing. Set when every other inject hook fails.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Override the network handler object itself. Only works in 1.3.
|
||||
* <p>
|
||||
* Cannot intercept MapChunk packets.
|
||||
*/
|
||||
NETWORK_MANAGER_OBJECT,
|
||||
|
||||
/**
|
||||
* Override the packet queue lists in NetworkHandler.
|
||||
* <p>
|
||||
* Cannot intercept MapChunk packets.
|
||||
*/
|
||||
NETWORK_HANDLER_FIELDS,
|
||||
|
||||
/**
|
||||
* Override the server handler object. Versatile, but a tad slower.
|
||||
*/
|
||||
NETWORK_SERVER_OBJECT;
|
||||
}
|
||||
|
||||
// The amount of time to wait until we actually unhook every player
|
||||
private static final int UNHOOK_DELAY = 5 * TICKS_PER_SECOND;
|
||||
|
||||
@@ -100,7 +149,8 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
private DelayedSingleTask unhookTask;
|
||||
|
||||
// Create a concurrent set
|
||||
private Set<PacketListener> packetListeners = Collections.newSetFromMap(new ConcurrentHashMap<>());
|
||||
private Set<PacketListener> packetListeners =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<PacketListener, Boolean>());
|
||||
|
||||
// Packet injection
|
||||
private PacketInjector packetInjector;
|
||||
@@ -108,6 +158,9 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
// Different injection types per game phase
|
||||
private PlayerInjectionHandler playerInjection;
|
||||
|
||||
// Intercepting write packet methods
|
||||
private InterceptWritePacket interceptWritePacket;
|
||||
|
||||
// Whether or not a packet must be input buffered
|
||||
private volatile Set<PacketType> inputBufferedPackets = Sets.newHashSet();
|
||||
|
||||
@@ -144,8 +197,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
// Whether or not plugins are using the send/receive methods
|
||||
private AtomicBoolean packetCreation = new AtomicBoolean();
|
||||
|
||||
// Spigot listener, if in use
|
||||
private SpigotPacketInjector spigotInjector;
|
||||
|
||||
// Netty injector (for 1.7.2)
|
||||
private ProtocolInjector nettyInjector;
|
||||
private NettyProtocolInjector nettyInjector;
|
||||
|
||||
// Plugin verifier
|
||||
private PluginVerifier pluginVerifier;
|
||||
@@ -156,24 +212,29 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
// The current Minecraft version
|
||||
private MinecraftVersion minecraftVersion;
|
||||
|
||||
// Login packets
|
||||
private LoginPackets loginPackets;
|
||||
|
||||
// Debug mode
|
||||
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
|
||||
Predicate<GamePhase> isInjectionNecessary = phase -> {
|
||||
boolean result = true;
|
||||
Predicate<GamePhase> isInjectionNecessary = new Predicate<GamePhase>() {
|
||||
@Override
|
||||
public boolean apply(@Nullable GamePhase phase) {
|
||||
boolean result = true;
|
||||
|
||||
if (phase.hasLogin())
|
||||
result &= getPhaseLoginCount() > 0;
|
||||
// Note that we will still hook players if the unhooking has been delayed
|
||||
if (phase.hasPlaying())
|
||||
result &= getPhasePlayingCount() > 0 || unhookTask.isRunning();
|
||||
return result;
|
||||
if (phase.hasLogin())
|
||||
result &= getPhaseLoginCount() > 0;
|
||||
// Note that we will still hook players if the unhooking has been delayed
|
||||
if (phase.hasPlaying())
|
||||
result &= getPhasePlayingCount() > 0 || unhookTask.isRunning();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// Listener containers
|
||||
@@ -191,6 +252,8 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
this.pluginVerifier = new PluginVerifier(builder.getLibrary());
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (ThreadDeath e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
reporter.reportWarning(this, Report.newBuilder(REPORT_PLUGIN_VERIFIER_ERROR).
|
||||
messageParam(e.getMessage()).error(e));
|
||||
@@ -198,11 +261,47 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
|
||||
// Prepare version
|
||||
this.minecraftVersion = builder.getMinecraftVersion();
|
||||
this.loginPackets = new LoginPackets(minecraftVersion);
|
||||
|
||||
this.nettyInjector = new ProtocolInjector(builder.getLibrary(), this, reporter);
|
||||
this.playerInjection = nettyInjector.getPlayerInjector();
|
||||
this.packetInjector = nettyInjector.getPacketInjector();
|
||||
// The write packet interceptor
|
||||
this.interceptWritePacket = new InterceptWritePacket(reporter);
|
||||
|
||||
// Use the correct injection type
|
||||
if (MinecraftReflection.isUsingNetty()) {
|
||||
this.nettyInjector = new NettyProtocolInjector(builder.getLibrary(), this, reporter);
|
||||
this.playerInjection = nettyInjector.getPlayerInjector();
|
||||
this.packetInjector = nettyInjector.getPacketInjector();
|
||||
|
||||
} else if (builder.isNettyEnabled()) {
|
||||
this.spigotInjector = new SpigotPacketInjector(reporter, this, server);
|
||||
this.playerInjection = spigotInjector.getPlayerHandler();
|
||||
this.packetInjector = spigotInjector.getPacketInjector();
|
||||
|
||||
// Set real injector, in case we need it
|
||||
spigotInjector.setProxyPacketInjector(PacketInjectorBuilder.newBuilder().
|
||||
invoker(this).
|
||||
reporter(reporter).
|
||||
playerInjection(playerInjection).
|
||||
buildInjector()
|
||||
);
|
||||
|
||||
} else {
|
||||
// Initialize standard injection mangers
|
||||
this.playerInjection = PlayerInjectorBuilder.newBuilder().
|
||||
invoker(this).
|
||||
server(server).
|
||||
reporter(reporter).
|
||||
packetListeners(packetListeners).
|
||||
injectionFilter(isInjectionNecessary).
|
||||
version(builder.getMinecraftVersion()).
|
||||
buildHandler();
|
||||
|
||||
this.packetInjector = PacketInjectorBuilder.newBuilder().
|
||||
invoker(this).
|
||||
reporter(reporter).
|
||||
playerInjection(playerInjection).
|
||||
buildInjector();
|
||||
}
|
||||
this.asyncFilterManager = builder.getAsyncManager();
|
||||
this.library = builder.getLibrary();
|
||||
|
||||
@@ -276,6 +375,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
return ImmutableSet.copyOf(packetListeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterceptWritePacket getInterceptWritePacket() {
|
||||
return interceptWritePacket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Warn of common programming mistakes.
|
||||
* @param plugin - plugin to check.
|
||||
@@ -333,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) {
|
||||
@@ -342,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);
|
||||
@@ -350,25 +454,13 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given packet may be sent during login.
|
||||
* @param type - the packet type.
|
||||
* @return TRUE if it may, FALSE otherwise.
|
||||
*/
|
||||
public boolean isLoginPacket(PacketType type) {
|
||||
return PacketType.Login.Client.getInstance().hasMember(type) ||
|
||||
PacketType.Login.Server.getInstance().hasMember(type) ||
|
||||
PacketType.Status.Client.getInstance().hasMember(type) ||
|
||||
PacketType.Status.Server.getInstance().hasMember(type);
|
||||
}
|
||||
|
||||
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)) {
|
||||
|
||||
for (PacketType type : whitelist.getTypes()) {
|
||||
if (isLoginPacket(type)) {
|
||||
if (loginPackets.isLoginPacket(type)) {
|
||||
return GamePhase.BOTH;
|
||||
}
|
||||
}
|
||||
@@ -387,7 +479,9 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
|
||||
// We only check the recieving whitelist
|
||||
if (whitelist.getOptions().contains(ListenerOptions.INTERCEPT_INPUT_BUFFER)) {
|
||||
updated.addAll(whitelist.getTypes());
|
||||
for (PacketType type : whitelist.getTypes()) {
|
||||
updated.add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Update it
|
||||
@@ -411,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,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());
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -445,8 +539,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
* @param whitelist - whitelist of packet IDs.
|
||||
* @throws IllegalArgumentException If the whitelist is illegal.
|
||||
*/
|
||||
@Override
|
||||
public void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist) {
|
||||
public static void verifyWhitelist(PacketListener listener, ListeningWhitelist whitelist) {
|
||||
for (PacketType type : whitelist.getTypes()) {
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException(String.format("Packet type in in listener %s was NULL.",
|
||||
@@ -474,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
|
||||
@@ -517,6 +610,11 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requireInputBuffer(int packetId) {
|
||||
return inputBufferedPackets.contains(PacketType.findLegacy(packetId, Sender.CLIENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a packet sending or receiving event.
|
||||
* <p>
|
||||
@@ -557,6 +655,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
* Note that all packets are disabled by default.
|
||||
*
|
||||
* @param listener - the listener that requested to enable these filters.
|
||||
* @param side - which side the event will arrive from.
|
||||
* @param packets - the packet id(s).
|
||||
*/
|
||||
private void enablePacketFilters(PacketListener listener, Iterable<PacketType> packets) {
|
||||
@@ -571,7 +670,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
playerInjection.addPacketHandler(type, listener.getSendingWhitelist().getOptions());
|
||||
else
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_UNSUPPORTED_SERVER_PACKET).messageParam(PacketAdapter.getPluginName(listener), type)
|
||||
Report.newBuilder(REPORT_UNSUPPORTED_SERVER_PACKET_ID).messageParam(PacketAdapter.getPluginName(listener), type)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -581,7 +680,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
packetInjector.addPacketHandler(type, listener.getReceivingWhitelist().getOptions());
|
||||
else
|
||||
reporter.reportWarning(this,
|
||||
Report.newBuilder(REPORT_UNSUPPORTED_CLIENT_PACKET).messageParam(PacketAdapter.getPluginName(listener), type)
|
||||
Report.newBuilder(REPORT_UNSUPPORTED_CLIENT_PACKET_ID).messageParam(PacketAdapter.getPluginName(listener), type)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -607,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
|
||||
@@ -633,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) {
|
||||
|
||||
@@ -707,7 +806,7 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
|
||||
if (!filters) {
|
||||
// We may have to delay the packet due to non-asynchronous monitor listeners
|
||||
if (!Bukkit.isPrimaryThread() && playerInjection.hasMainThreadListener(packet.getType())) {
|
||||
if (!filters && !Bukkit.isPrimaryThread() && playerInjection.hasMainThreadListener(packet.getType())) {
|
||||
final NetworkMarker copy = marker;
|
||||
|
||||
server.getScheduler().scheduleSyncDelayedTask(library, new Runnable() {
|
||||
@@ -733,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 {
|
||||
Channel 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);
|
||||
@@ -805,11 +888,23 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PacketContainer createPacket(int id) {
|
||||
return createPacket(PacketType.findLegacy(id), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer createPacket(PacketType type) {
|
||||
return createPacket(type, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PacketContainer createPacket(int id, boolean forceDefaults) {
|
||||
return createPacket(PacketType.findLegacy(id), forceDefaults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketContainer createPacket(PacketType type, boolean forceDefaults) {
|
||||
PacketContainer packet = new PacketContainer(type);
|
||||
@@ -826,11 +921,27 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
return packet;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PacketConstructor createPacketConstructor(int id, Object... arguments) {
|
||||
return PacketConstructor.DEFAULT.withPacket(id, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketConstructor createPacketConstructor(PacketType type, Object... arguments) {
|
||||
return PacketConstructor.DEFAULT.withPacket(type, arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Set<Integer> getSendingFilters() {
|
||||
return PacketRegistry.toLegacy(playerInjection.getSendingFilters());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Integer> getReceivingFilters() {
|
||||
return PacketRegistry.toLegacy(packetInjector.getPacketHandlers());
|
||||
}
|
||||
@Override
|
||||
public Set<PacketType> getSendingFilterTypes() {
|
||||
return Collections.unmodifiableSet(playerInjection.getSendingFilters());
|
||||
@@ -843,17 +954,17 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
|
||||
@Override
|
||||
public void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
|
||||
EntityUtilities.getInstance().updateEntity(entity, observers);
|
||||
EntityUtilities.updateEntity(entity, observers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getEntityFromID(World container, int id) throws FieldAccessException {
|
||||
return EntityUtilities.getInstance().getEntityFromID(container, id);
|
||||
return EntityUtilities.getEntityFromID(container, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Player> getEntityTrackers(Entity entity) throws FieldAccessException {
|
||||
return EntityUtilities.getInstance().getEntityTrackers(entity);
|
||||
return EntityUtilities.getEntityTrackers(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -877,43 +988,45 @@ 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.
|
||||
*/
|
||||
@Override
|
||||
public void registerEvents(PluginManager manager, final Plugin plugin) {
|
||||
if (spigotInjector != null && !spigotInjector.register(plugin))
|
||||
throw new IllegalArgumentException("Spigot has already been registered.");
|
||||
if (nettyInjector != null)
|
||||
nettyInjector.inject();
|
||||
|
||||
manager.registerEvents(new Listener() {
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
try {
|
||||
manager.registerEvents(new Listener() {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||
PacketFilterManager.this.onPlayerLogin(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPrePlayerJoin(PlayerJoinEvent event) {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPrePlayerJoin(PlayerJoinEvent event) {
|
||||
PacketFilterManager.this.onPrePlayerJoin(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
PacketFilterManager.this.onPlayerJoin(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
}
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
PacketFilterManager.this.onPlayerQuit(event);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPluginDisabled(PluginDisableEvent event) {
|
||||
}
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onPluginDisabled(PluginDisableEvent event) {
|
||||
PacketFilterManager.this.onPluginDisabled(event, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
}, plugin);
|
||||
}, plugin);
|
||||
|
||||
} catch (NoSuchMethodError e) {
|
||||
// Oh wow! We're running on 1.0.0 or older.
|
||||
registerOld(manager, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlayerLogin(PlayerLoginEvent event) {
|
||||
@@ -929,6 +1042,8 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
// Let's clean up the other injection first.
|
||||
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++. Ignore it.
|
||||
} catch (Exception e) {
|
||||
reporter.reportDetailed(PacketFilterManager.this,
|
||||
Report.newBuilder(REPORT_CANNOT_INJECT_PLAYER).callerParam(event).error(e)
|
||||
@@ -1002,6 +1117,151 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void registerPacketClass(Class<?> clazz, int packetID) {
|
||||
PacketRegistry.getPacketToID().put(clazz, packetID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public void unregisterPacketClass(Class<?> clazz) {
|
||||
PacketRegistry.getPacketToID().remove(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Class<?> getPacketClassFromID(int packetID, boolean forceVanilla) {
|
||||
return PacketRegistry.getPacketClassFromID(packetID, forceVanilla);
|
||||
}
|
||||
|
||||
// Yes, this is crazy.
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void registerOld(PluginManager manager, final Plugin plugin) {
|
||||
try {
|
||||
ClassLoader loader = manager.getClass().getClassLoader();
|
||||
|
||||
// The different enums we are going to need
|
||||
Class eventTypes = loader.loadClass("org.bukkit.event.Event$Type");
|
||||
Class eventPriority = loader.loadClass("org.bukkit.event.Event$Priority");
|
||||
|
||||
// Get the priority
|
||||
Object priorityLowest = Enum.valueOf(eventPriority, "Lowest");
|
||||
Object priorityMonitor = Enum.valueOf(eventPriority, "Monitor");
|
||||
|
||||
// Get event types
|
||||
Object playerJoinType = Enum.valueOf(eventTypes, "PLAYER_JOIN");
|
||||
Object playerQuitType = Enum.valueOf(eventTypes, "PLAYER_QUIT");
|
||||
Object pluginDisabledType = Enum.valueOf(eventTypes, "PLUGIN_DISABLE");
|
||||
|
||||
// The player listener! Good times.
|
||||
Class<?> playerListener = loader.loadClass("org.bukkit.event.player.PlayerListener");
|
||||
Class<?> serverListener = loader.loadClass("org.bukkit.event.server.ServerListener");
|
||||
|
||||
// Find the register event method
|
||||
Method registerEvent = FuzzyReflection.fromObject(manager).getMethodByParameters("registerEvent",
|
||||
eventTypes, Listener.class, eventPriority, Plugin.class);
|
||||
|
||||
Enhancer playerLow = EnhancerFactory.getInstance().createEnhancer();
|
||||
Enhancer playerEx = EnhancerFactory.getInstance().createEnhancer();
|
||||
Enhancer serverEx = EnhancerFactory.getInstance().createEnhancer();
|
||||
|
||||
playerLow.setSuperclass(playerListener);
|
||||
playerLow.setClassLoader(classLoader);
|
||||
playerLow.setCallback(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
|
||||
throws Throwable {
|
||||
// Must have a parameter
|
||||
if (args.length == 1) {
|
||||
Object event = args[0];
|
||||
|
||||
if (event instanceof PlayerJoinEvent) {
|
||||
onPrePlayerJoin((PlayerJoinEvent) event);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
playerEx.setSuperclass(playerListener);
|
||||
playerEx.setClassLoader(classLoader);
|
||||
playerEx.setCallback(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||
if (args.length == 1) {
|
||||
Object event = args[0];
|
||||
|
||||
// Check for the correct event
|
||||
if (event instanceof PlayerJoinEvent) {
|
||||
onPlayerJoin((PlayerJoinEvent) event);
|
||||
} else if (event instanceof PlayerQuitEvent) {
|
||||
onPlayerQuit((PlayerQuitEvent) event);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
serverEx.setSuperclass(serverListener);
|
||||
serverEx.setClassLoader(classLoader);
|
||||
serverEx.setCallback(new MethodInterceptor() {
|
||||
@Override
|
||||
public Object intercept(Object obj, Method method, Object[] args,
|
||||
MethodProxy proxy) throws Throwable {
|
||||
// Must have a parameter
|
||||
if (args.length == 1) {
|
||||
Object event = args[0];
|
||||
|
||||
if (event instanceof PluginDisableEvent)
|
||||
onPluginDisabled((PluginDisableEvent) event, plugin);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
// Create our listener
|
||||
Object playerProxyLow = playerLow.create();
|
||||
Object playerProxy = playerEx.create();
|
||||
Object serverProxy = serverEx.create();
|
||||
|
||||
registerEvent.invoke(manager, playerJoinType, playerProxyLow, priorityLowest, plugin);
|
||||
registerEvent.invoke(manager, playerJoinType, playerProxy, priorityMonitor, plugin);
|
||||
registerEvent.invoke(manager, playerQuitType, playerProxy, priorityMonitor, plugin);
|
||||
registerEvent.invoke(manager, pluginDisabledType, serverProxy, priorityMonitor, plugin);
|
||||
|
||||
// A lot can go wrong
|
||||
} catch (ClassNotFoundException e1) {
|
||||
e1.printStackTrace();
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InvocationTargetException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known and supported server packet.
|
||||
* @return An immutable set of every known server packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the server packet data from Minecraft.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Set<Integer> getServerPackets() throws FieldAccessException {
|
||||
return PacketRegistry.getServerPackets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve every known and supported client packet.
|
||||
* @return An immutable set of every known client packet.
|
||||
* @throws FieldAccessException If we're unable to retrieve the client packet data from Minecraft.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Set<Integer> getClientPackets() throws FieldAccessException {
|
||||
return PacketRegistry.getClientPackets();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the current plugin class loader.
|
||||
* @return Class loader.
|
||||
@@ -1024,6 +1284,8 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
// Remove packet handlers
|
||||
if (packetInjector != null)
|
||||
packetInjector.cleanupAll();
|
||||
if (spigotInjector != null)
|
||||
spigotInjector.cleanupAll();
|
||||
if (nettyInjector != null)
|
||||
nettyInjector.close();
|
||||
|
||||
@@ -1036,6 +1298,9 @@ public final class PacketFilterManager implements ListenerInvoker, InternalManag
|
||||
recievedListeners = null;
|
||||
sendingListeners = null;
|
||||
|
||||
// Also cleanup the interceptor for the write packet method
|
||||
interceptWritePacket.cleanup();
|
||||
|
||||
// Clean up async handlers. We have to do this last.
|
||||
asyncFilterManager.cleanupAll();
|
||||
}
|
||||
File renamed without changes.
+9
-16
@@ -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.
|
||||
File renamed without changes.
File renamed without changes.
+43
-7
@@ -37,9 +37,22 @@ import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
*/
|
||||
public class StructureCache {
|
||||
// Structure modifiers
|
||||
private static ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
|
||||
private static ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers =
|
||||
new ConcurrentHashMap<PacketType, StructureModifier<Object>>();
|
||||
|
||||
private static Set<PacketType> compiling = new HashSet<>();
|
||||
private static Set<PacketType> compiling = new HashSet<PacketType>();
|
||||
|
||||
/**
|
||||
* Creates an empty Minecraft packet of the given id.
|
||||
* <p>
|
||||
* Decreated: Use {@link #newPacket(PacketType)} instead.
|
||||
* @param legacyId - legacy (1.6.4) packet id.
|
||||
* @return Created packet.
|
||||
*/
|
||||
@Deprecated
|
||||
public static Object newPacket(int legacyId) {
|
||||
return newPacket(PacketType.findLegacy(legacyId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty Minecraft packet of the given type.
|
||||
@@ -54,15 +67,25 @@ public class StructureCache {
|
||||
// TODO: Optimize DefaultInstances
|
||||
Object result = DefaultInstances.DEFAULT.create(clazz);
|
||||
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("Failed to create packet for type: " + type);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot find associated packet class: " + type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached structure modifier for the given packet id.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getStructure(PacketType)} instead.
|
||||
* @param legacyId - the legacy (1.6.4) packet ID.
|
||||
* @return A structure modifier.
|
||||
*/
|
||||
@Deprecated
|
||||
public static StructureModifier<Object> getStructure(int legacyId) {
|
||||
return getStructure(PacketType.findLegacy(legacyId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached structure modifier for the given packet type.
|
||||
* @param type - packet type.
|
||||
@@ -94,6 +117,19 @@ public class StructureCache {
|
||||
return getStructure(PacketRegistry.getPacketType(packetType), compile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached structure modifier for the given packet ID.
|
||||
* <p>
|
||||
* Deprecated: Use {@link #getStructure(PacketType, boolean)} instead.
|
||||
* @param legacyId - the legacy (1.6.4) packet ID.
|
||||
* @param compile - whether or not to asynchronously compile the structure modifier.
|
||||
* @return A structure modifier.
|
||||
*/
|
||||
@Deprecated
|
||||
public static StructureModifier<Object> getStructure(final int legacyId, boolean compile) {
|
||||
return getStructure(PacketType.findLegacy(legacyId), compile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached structure modifier for the given packet type.
|
||||
* @param type - packet type.
|
||||
@@ -136,4 +172,4 @@ public class StructureCache {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
-41
@@ -1,34 +1,19 @@
|
||||
/**
|
||||
* 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 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 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 BootstrapList implements List<Object> {
|
||||
class BootstrapList implements List<Object> {
|
||||
private List<Object> delegate;
|
||||
private ChannelHandler handler;
|
||||
|
||||
@@ -131,102 +116,82 @@ public class BootstrapList 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);
|
||||
}
|
||||
Loaded 100 of 380 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user