Merge branch 'master' into gh-pages
Dieser Commit ist enthalten in:
Commit
3d166ae353
@ -4,7 +4,7 @@
|
|||||||
<groupId>com.comphenix.protocol</groupId>
|
<groupId>com.comphenix.protocol</groupId>
|
||||||
<artifactId>ProtocolLib</artifactId>
|
<artifactId>ProtocolLib</artifactId>
|
||||||
<name>ProtocolLib</name>
|
<name>ProtocolLib</name>
|
||||||
<version>1.7.1</version>
|
<version>1.8.0</version>
|
||||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||||
<url>http://dev.bukkit.org/server-mods/protocollib/</url>
|
<url>http://dev.bukkit.org/server-mods/protocollib/</url>
|
||||||
<developers>
|
<developers>
|
||||||
@ -139,7 +139,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bukkit</groupId>
|
<groupId>org.bukkit</groupId>
|
||||||
<artifactId>craftbukkit</artifactId>
|
<artifactId>craftbukkit</artifactId>
|
||||||
<version>1.3.2-R1.0</version>
|
<version>1.4.5-R0.3-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>com.comphenix.protocol</groupId>
|
<groupId>com.comphenix.protocol</groupId>
|
||||||
<artifactId>ProtocolLib</artifactId>
|
<artifactId>ProtocolLib</artifactId>
|
||||||
<version>1.7.1</version>
|
<version>1.8.0</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||||
|
|
||||||
@ -202,7 +202,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.bukkit</groupId>
|
<groupId>org.bukkit</groupId>
|
||||||
<artifactId>craftbukkit</artifactId>
|
<artifactId>craftbukkit</artifactId>
|
||||||
<version>1.3.2-R1.0</version>
|
<version>1.4.5-R0.3-SNAPSHOT</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -10,7 +10,6 @@ import java.util.WeakHashMap;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.Factory;
|
import net.sf.cglib.proxy.Factory;
|
||||||
|
|
||||||
import org.bukkit.ChatColor;
|
import org.bukkit.ChatColor;
|
||||||
@ -29,6 +28,7 @@ import com.comphenix.protocol.injector.GamePhase;
|
|||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.PrettyPrinter;
|
import com.comphenix.protocol.reflect.PrettyPrinter;
|
||||||
import com.comphenix.protocol.utility.ChatExtensions;
|
import com.comphenix.protocol.utility.ChatExtensions;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.collect.DiscreteDomains;
|
import com.google.common.collect.DiscreteDomains;
|
||||||
import com.google.common.collect.Range;
|
import com.google.common.collect.Range;
|
||||||
import com.google.common.collect.Ranges;
|
import com.google.common.collect.Ranges;
|
||||||
@ -394,7 +394,7 @@ class CommandPacket extends CommandBase {
|
|||||||
// Detailed will print the packet's content too
|
// Detailed will print the packet's content too
|
||||||
if (detailed) {
|
if (detailed) {
|
||||||
try {
|
try {
|
||||||
Packet packet = event.getPacket().getHandle();
|
Object packet = event.getPacket().getHandle();
|
||||||
Class<?> clazz = packet.getClass();
|
Class<?> clazz = packet.getClass();
|
||||||
|
|
||||||
// Get the first Minecraft super class
|
// Get the first Minecraft super class
|
||||||
@ -404,7 +404,7 @@ class CommandPacket extends CommandBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info(shortDescription + ":\n" +
|
logger.info(shortDescription + ":\n" +
|
||||||
PrettyPrinter.printObject(packet, clazz, Packet.class)
|
PrettyPrinter.printObject(packet, clazz, MinecraftReflection.getPacketClass())
|
||||||
);
|
);
|
||||||
|
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
|
@ -47,6 +47,7 @@ class CommandProtocol extends CommandBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void checkVersion(final CommandSender sender) {
|
public void checkVersion(final CommandSender sender) {
|
||||||
// Perform on an async thread
|
// Perform on an async thread
|
||||||
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
|
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
|
||||||
@ -64,6 +65,7 @@ class CommandProtocol extends CommandBase {
|
|||||||
updateFinished();
|
updateFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public void updateVersion(final CommandSender sender) {
|
public void updateVersion(final CommandSender sender) {
|
||||||
// Perform on an async thread
|
// Perform on an async thread
|
||||||
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
|
plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
|
||||||
|
161
ProtocolLib/src/main/java/com/comphenix/protocol/MinecraftVersion.java
Normale Datei
161
ProtocolLib/src/main/java/com/comphenix/protocol/MinecraftVersion.java
Normale Datei
@ -0,0 +1,161 @@
|
|||||||
|
package com.comphenix.protocol;
|
||||||
|
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.bukkit.Server;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.ComparisonChain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the current Minecraft version.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||||
|
/**
|
||||||
|
* Regular expression used to parse version strings.
|
||||||
|
*/
|
||||||
|
private static final String VERSION_PATTERN = ".*\\(MC:\\s*((?:\\d+\\.)*\\d)\\s*\\)";
|
||||||
|
|
||||||
|
private final int major;
|
||||||
|
private final int minor;
|
||||||
|
private final int build;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine the current Minecraft version.
|
||||||
|
* @param server - the Bukkit server that will be used to examine the MC version.
|
||||||
|
*/
|
||||||
|
public MinecraftVersion(Server server) {
|
||||||
|
this(extractVersion(server.getVersion()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a version object from the format major.minor.build.
|
||||||
|
* @param versionOnly - the version in text form.
|
||||||
|
*/
|
||||||
|
public MinecraftVersion(String versionOnly) {
|
||||||
|
int[] numbers = parseVersion(versionOnly);
|
||||||
|
|
||||||
|
this.major = numbers[0];
|
||||||
|
this.minor = numbers[1];
|
||||||
|
this.build = numbers[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a version object directly.
|
||||||
|
* @param major - major version number.
|
||||||
|
* @param minor - minor version number.
|
||||||
|
* @param build - build version number.
|
||||||
|
*/
|
||||||
|
public MinecraftVersion(int major, int minor, int build) {
|
||||||
|
this.major = major;
|
||||||
|
this.minor = minor;
|
||||||
|
this.build = build;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int[] parseVersion(String version) {
|
||||||
|
String[] elements = version.split("\\.");
|
||||||
|
int[] numbers = new int[3];
|
||||||
|
|
||||||
|
// Make sure it's even a valid version
|
||||||
|
if (elements.length < 1)
|
||||||
|
throw new IllegalStateException("Corrupt MC version: " + version);
|
||||||
|
|
||||||
|
// The String 1 or 1.2 is interpreted as 1.0.0 and 1.2.0 respectively.
|
||||||
|
for (int i = 0; i < Math.min(numbers.length, elements.length); i++)
|
||||||
|
numbers[i] = Integer.parseInt(elements[i].trim());
|
||||||
|
return numbers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Major version number
|
||||||
|
* @return Current major version number.
|
||||||
|
*/
|
||||||
|
public int getMajor() {
|
||||||
|
return major;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minor version number
|
||||||
|
* @return Current minor version number.
|
||||||
|
*/
|
||||||
|
public int getMinor() {
|
||||||
|
return minor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build version number
|
||||||
|
* @return Current build version number.
|
||||||
|
*/
|
||||||
|
public int getBuild() {
|
||||||
|
return build;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the version String (major.minor.build) only.
|
||||||
|
* @return A normal version string.
|
||||||
|
*/
|
||||||
|
public String getVersion() {
|
||||||
|
return String.format("%s.%s.%s", major, minor, build);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(MinecraftVersion o) {
|
||||||
|
if (o == null)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return ComparisonChain.start().
|
||||||
|
compare(major, o.major).
|
||||||
|
compare(minor, o.minor).
|
||||||
|
compare(build, o.build).
|
||||||
|
result();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (obj == this)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (obj instanceof MinecraftVersion) {
|
||||||
|
MinecraftVersion other = (MinecraftVersion) obj;
|
||||||
|
|
||||||
|
return major == other.major &&
|
||||||
|
minor == other.minor &&
|
||||||
|
build == other.build;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(major, minor, build);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
// Convert to a String that we can parse back again
|
||||||
|
return String.format("(MC: %s)", getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the Minecraft version from CraftBukkit itself.
|
||||||
|
* @param server - the server object representing CraftBukkit.
|
||||||
|
* @return The underlying MC version.
|
||||||
|
* @throws IllegalStateException If we could not parse the version string.
|
||||||
|
*/
|
||||||
|
public static String extractVersion(String text) {
|
||||||
|
Pattern versionPattern = Pattern.compile(VERSION_PATTERN);
|
||||||
|
Matcher version = versionPattern.matcher(text);
|
||||||
|
|
||||||
|
if (version.matches() && version.group(1) != null) {
|
||||||
|
return version.group(1);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Cannot parse version String '" + text + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -18,6 +18,8 @@ class ProtocolConfig {
|
|||||||
|
|
||||||
private static final String METRICS_ENABLED = "metrics";
|
private static final String METRICS_ENABLED = "metrics";
|
||||||
|
|
||||||
|
private static final String IGNORE_VERSION_CHECK = "ignore version check";
|
||||||
|
|
||||||
private static final String BACKGROUND_COMPILER_ENABLED = "background compiler";
|
private static final String BACKGROUND_COMPILER_ENABLED = "background compiler";
|
||||||
|
|
||||||
private static final String UPDATER_NOTIFY = "notify";
|
private static final String UPDATER_NOTIFY = "notify";
|
||||||
@ -149,6 +151,26 @@ class ProtocolConfig {
|
|||||||
return updater.getLong(UPDATER_LAST_TIME, 0);
|
return updater.getLong(UPDATER_LAST_TIME, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version of Minecraft to ignore the built-in safety feature.
|
||||||
|
* @return The version to ignore ProtocolLib's satefy.
|
||||||
|
*/
|
||||||
|
public String getIgnoreVersionCheck() {
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @param ignoreVersion - the version of Minecraft where the satefy will be disabled.
|
||||||
|
*/
|
||||||
|
public void setIgnoreVersionCheck(String ignoreVersion) {
|
||||||
|
global.set(IGNORE_VERSION_CHECK, ignoreVersion);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve whether or not metrics is enabled.
|
* Retrieve whether or not metrics is enabled.
|
||||||
* @return TRUE if metrics is enabled, FALSE otherwise.
|
* @return TRUE if metrics is enabled, FALSE otherwise.
|
||||||
|
@ -19,6 +19,7 @@ package com.comphenix.protocol;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.logging.Handler;
|
import java.util.logging.Handler;
|
||||||
|
import java.util.logging.Level;
|
||||||
import java.util.logging.LogRecord;
|
import java.util.logging.LogRecord;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
@ -43,6 +44,15 @@ import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class ProtocolLibrary extends JavaPlugin {
|
public class ProtocolLibrary extends JavaPlugin {
|
||||||
|
/**
|
||||||
|
* The minimum version ProtocolLib has been tested with.
|
||||||
|
*/
|
||||||
|
private static final String MINIMUM_MINECRAFT_VERSION = "1.0.0";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum version ProtocolLib has been tested with,
|
||||||
|
*/
|
||||||
|
private static final String MAXIMUM_MINECRAFT_VERSION = "1.4.5";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of milliseconds per second.
|
* The number of milliseconds per second.
|
||||||
@ -120,7 +130,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
commandPacket = new CommandPacket(detailedReporter, this, logger, protocolManager);
|
commandPacket = new CommandPacket(detailedReporter, this, logger, protocolManager);
|
||||||
|
|
||||||
// Send logging information to player listeners too
|
// Send logging information to player listeners too
|
||||||
broadcastUsers(PERMISSION_INFO);
|
setupBroadcastUsers(PERMISSION_INFO);
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
detailedReporter.reportDetailed(this, "Cannot load ProtocolLib.", e, protocolManager);
|
detailedReporter.reportDetailed(this, "Cannot load ProtocolLib.", e, protocolManager);
|
||||||
@ -142,7 +152,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void broadcastUsers(final String permission) {
|
private void setupBroadcastUsers(final String permission) {
|
||||||
// Guard against multiple calls
|
// Guard against multiple calls
|
||||||
if (redirectHandler != null)
|
if (redirectHandler != null)
|
||||||
return;
|
return;
|
||||||
@ -151,8 +161,11 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
redirectHandler = new Handler() {
|
redirectHandler = new Handler() {
|
||||||
@Override
|
@Override
|
||||||
public void publish(LogRecord record) {
|
public void publish(LogRecord record) {
|
||||||
|
// Only display warnings and above
|
||||||
|
if (record.getLevel().intValue() >= Level.WARNING.intValue()) {
|
||||||
commandPacket.broadcastMessageSilently(record.getMessage(), permission);
|
commandPacket.broadcastMessageSilently(record.getMessage(), permission);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() {
|
public void flush() {
|
||||||
@ -188,13 +201,13 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
logger.info("Structure compiler thread has been disabled.");
|
logger.info("Structure compiler thread has been disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle unexpected Minecraft versions
|
||||||
|
verifyMinecraftVersion();
|
||||||
|
|
||||||
// Set up command handlers
|
// Set up command handlers
|
||||||
registerCommand(CommandProtocol.NAME, commandProtocol);
|
registerCommand(CommandProtocol.NAME, commandProtocol);
|
||||||
registerCommand(CommandPacket.NAME, commandPacket);
|
registerCommand(CommandPacket.NAME, commandPacket);
|
||||||
|
|
||||||
// Notify server managers of incompatible plugins
|
|
||||||
checkForIncompatibility(manager);
|
|
||||||
|
|
||||||
// Player login and logout events
|
// Player login and logout events
|
||||||
protocolManager.registerEvents(manager, this);
|
protocolManager.registerEvents(manager, this);
|
||||||
|
|
||||||
@ -220,6 +233,26 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used to check Minecraft version
|
||||||
|
private void verifyMinecraftVersion() {
|
||||||
|
try {
|
||||||
|
MinecraftVersion minimum = new MinecraftVersion(MINIMUM_MINECRAFT_VERSION);
|
||||||
|
MinecraftVersion maximum = new MinecraftVersion(MAXIMUM_MINECRAFT_VERSION);
|
||||||
|
MinecraftVersion current = new MinecraftVersion(getServer());
|
||||||
|
|
||||||
|
// Skip certain versions
|
||||||
|
if (!config.getIgnoreVersionCheck().equals(current.getVersion())) {
|
||||||
|
// We'll just warn the user for now
|
||||||
|
if (current.compareTo(minimum) < 0)
|
||||||
|
logger.warning("Version " + current + " is lower than the minimum " + minimum);
|
||||||
|
if (current.compareTo(maximum) > 0)
|
||||||
|
logger.warning("Version " + current + " has not yet been tested! Proceed with caution.");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
reporter.reportWarning(this, "Unable to retrieve current Minecraft version.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void registerCommand(String name, CommandExecutor executor) {
|
private void registerCommand(String name, CommandExecutor executor) {
|
||||||
try {
|
try {
|
||||||
if (executor == null)
|
if (executor == null)
|
||||||
@ -296,18 +329,6 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkForIncompatibility(PluginManager manager) {
|
|
||||||
// Plugin authors: Notify me to remove these
|
|
||||||
String[] incompatiblePlugins = {};
|
|
||||||
|
|
||||||
for (String plugin : incompatiblePlugins) {
|
|
||||||
if (manager.getPlugin(plugin) != null) {
|
|
||||||
// Check for versions, ect.
|
|
||||||
reporter.reportWarning(this, "Detected incompatible plugin: " + plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
// Disable compiler
|
// Disable compiler
|
||||||
|
@ -242,7 +242,7 @@ public class AsyncListenerHandler {
|
|||||||
|
|
||||||
final AsyncRunnable listenerLoop = getListenerLoop();
|
final AsyncRunnable listenerLoop = getListenerLoop();
|
||||||
|
|
||||||
filterManager.getScheduler().scheduleAsyncDelayedTask(listener.getPlugin(), new Runnable() {
|
scheduleAsync(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Thread thread = Thread.currentThread();
|
Thread thread = Thread.currentThread();
|
||||||
@ -290,7 +290,7 @@ public class AsyncListenerHandler {
|
|||||||
final AsyncRunnable listenerLoop = getListenerLoop();
|
final AsyncRunnable listenerLoop = getListenerLoop();
|
||||||
final Function<AsyncRunnable, Void> delegateCopy = executor;
|
final Function<AsyncRunnable, Void> delegateCopy = executor;
|
||||||
|
|
||||||
filterManager.getScheduler().scheduleAsyncDelayedTask(listener.getPlugin(), new Runnable() {
|
scheduleAsync(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
delegateCopy.apply(listenerLoop);
|
delegateCopy.apply(listenerLoop);
|
||||||
@ -298,6 +298,11 @@ public class AsyncListenerHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
private void scheduleAsync(Runnable runnable) {
|
||||||
|
filterManager.getScheduler().scheduleAsyncDelayedTask(listener.getPlugin(), runnable);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a friendly thread name using the following convention:
|
* Create a friendly thread name using the following convention:
|
||||||
* <p><code>
|
* <p><code>
|
||||||
|
@ -25,13 +25,12 @@ import java.util.Iterator;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketStream;
|
import com.comphenix.protocol.PacketStream;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.injector.PrioritizedListener;
|
import com.comphenix.protocol.injector.PrioritizedListener;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -403,10 +402,10 @@ public class AsyncMarker implements Serializable, Comparable<AsyncMarker> {
|
|||||||
|
|
||||||
if (isMinecraftAsync == null && !alwaysSync) {
|
if (isMinecraftAsync == null && !alwaysSync) {
|
||||||
try {
|
try {
|
||||||
isMinecraftAsync = FuzzyReflection.fromClass(Packet.class).getMethodByName("a_.*");
|
isMinecraftAsync = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).getMethodByName("a_.*");
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
// This will occur in 1.2.5 (or possibly in later versions)
|
// This will occur in 1.2.5 (or possibly in later versions)
|
||||||
List<Method> methods = FuzzyReflection.fromClass(Packet.class).
|
List<Method> methods = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).
|
||||||
getMethodListByParameters(boolean.class, new Class[] {});
|
getMethodListByParameters(boolean.class, new Class[] {});
|
||||||
|
|
||||||
// Try to look for boolean methods
|
// Try to look for boolean methods
|
||||||
|
@ -95,6 +95,21 @@ public class DetailedErrorReporter implements ErrorReporter {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters) {
|
||||||
|
reportMinimal(sender, methodName, error);
|
||||||
|
|
||||||
|
// Print parameters, if they are given
|
||||||
|
if (parameters != null && parameters.length > 0) {
|
||||||
|
logger.log(Level.SEVERE, " Parameters:");
|
||||||
|
|
||||||
|
// Print each parameter
|
||||||
|
for (Object parameter : parameters) {
|
||||||
|
logger.log(Level.SEVERE, " " + getStringDescription(parameter));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
|
public void reportMinimal(Plugin sender, String methodName, Throwable error) {
|
||||||
logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception occured in " + methodName + " for " +
|
logger.log(Level.SEVERE, "[" + PLUGIN_NAME + "] Unhandled exception occured in " + methodName + " for " +
|
||||||
|
@ -12,6 +12,15 @@ public interface ErrorReporter {
|
|||||||
*/
|
*/
|
||||||
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error);
|
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints a small minimal error report about an exception from another plugin.
|
||||||
|
* @param sender - the other plugin.
|
||||||
|
* @param methodName - name of the caller method.
|
||||||
|
* @param error - the exception itself.
|
||||||
|
* @param parameters - any relevant parameters to print.
|
||||||
|
*/
|
||||||
|
public abstract void reportMinimal(Plugin sender, String methodName, Throwable error, Object... parameters);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prints a warning message from the current plugin.
|
* Prints a warning message from the current plugin.
|
||||||
* @param sender - the object containing the caller method.
|
* @param sender - the object containing the caller method.
|
||||||
|
@ -29,6 +29,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
@ -39,12 +40,12 @@ import com.comphenix.protocol.injector.StructureCache;
|
|||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||||
import com.comphenix.protocol.wrappers.ChunkPosition;
|
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a Minecraft packet indirectly.
|
* Represents a Minecraft packet indirectly.
|
||||||
@ -59,14 +60,14 @@ public class PacketContainer implements Serializable {
|
|||||||
private static final long serialVersionUID = 2074805748222377230L;
|
private static final long serialVersionUID = 2074805748222377230L;
|
||||||
|
|
||||||
protected int id;
|
protected int id;
|
||||||
protected transient Packet handle;
|
protected transient Object handle;
|
||||||
|
|
||||||
// Current structure modifier
|
// Current structure modifier
|
||||||
protected transient StructureModifier<Object> structureModifier;
|
protected transient StructureModifier<Object> structureModifier;
|
||||||
|
|
||||||
// Support for serialization
|
// Support for serialization
|
||||||
private static Method writeMethod;
|
private static ConcurrentMap<Class<?>, Method> writeMethods = Maps.newConcurrentMap();
|
||||||
private static Method readMethod;
|
private static ConcurrentMap<Class<?>, Method> readMethods = Maps.newConcurrentMap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a packet container for a new packet.
|
* Creates a packet container for a new packet.
|
||||||
@ -81,7 +82,7 @@ public class PacketContainer implements Serializable {
|
|||||||
* @param id - ID of the given packet.
|
* @param id - ID of the given packet.
|
||||||
* @param handle - contained packet.
|
* @param handle - contained packet.
|
||||||
*/
|
*/
|
||||||
public PacketContainer(int id, Packet handle) {
|
public PacketContainer(int id, Object handle) {
|
||||||
this(id, handle, StructureCache.getStructure(id).withTarget(handle));
|
this(id, handle, StructureCache.getStructure(id).withTarget(handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +92,7 @@ public class PacketContainer implements Serializable {
|
|||||||
* @param handle - contained packet.
|
* @param handle - contained packet.
|
||||||
* @param structure - structure modifier.
|
* @param structure - structure modifier.
|
||||||
*/
|
*/
|
||||||
public PacketContainer(int id, Packet handle, StructureModifier<Object> structure) {
|
public PacketContainer(int id, Object handle, StructureModifier<Object> structure) {
|
||||||
if (handle == null)
|
if (handle == null)
|
||||||
throw new IllegalArgumentException("handle cannot be null.");
|
throw new IllegalArgumentException("handle cannot be null.");
|
||||||
|
|
||||||
@ -100,11 +101,17 @@ public class PacketContainer implements Serializable {
|
|||||||
this.structureModifier = structure;
|
this.structureModifier = structure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For serialization.
|
||||||
|
*/
|
||||||
|
protected PacketContainer() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the underlying Minecraft packet.
|
* Retrieves the underlying Minecraft packet.
|
||||||
* @return Underlying Minecraft packet.
|
* @return Underlying Minecraft packet.
|
||||||
*/
|
*/
|
||||||
public Packet getHandle() {
|
public Object getHandle() {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +221,7 @@ public class PacketContainer implements Serializable {
|
|||||||
public StructureModifier<ItemStack> getItemModifier() {
|
public StructureModifier<ItemStack> getItemModifier() {
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.<ItemStack>withType(
|
return structureModifier.<ItemStack>withType(
|
||||||
net.minecraft.server.ItemStack.class, BukkitConverters.getItemStackConverter());
|
MinecraftReflection.getItemStackClass(), BukkitConverters.getItemStackConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -230,23 +237,23 @@ public class PacketContainer implements Serializable {
|
|||||||
|
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.<ItemStack[]>withType(
|
return structureModifier.<ItemStack[]>withType(
|
||||||
net.minecraft.server.ItemStack[].class,
|
MinecraftReflection.getItemStackArrayClass(),
|
||||||
BukkitConverters.getIgnoreNull(new EquivalentConverter<ItemStack[]>() {
|
BukkitConverters.getIgnoreNull(new EquivalentConverter<ItemStack[]>() {
|
||||||
|
|
||||||
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
|
public Object getGeneric(Class<?>genericType, ItemStack[] specific) {
|
||||||
net.minecraft.server.ItemStack[] result = new net.minecraft.server.ItemStack[specific.length];
|
Object[] result = new Object[specific.length];
|
||||||
|
|
||||||
// Unwrap every item
|
// Unwrap every item
|
||||||
for (int i = 0; i < result.length; i++) {
|
for (int i = 0; i < result.length; i++) {
|
||||||
result[i] = (net.minecraft.server.ItemStack) stackConverter.getGeneric(
|
result[i] = stackConverter.getGeneric(
|
||||||
net.minecraft.server.ItemStack.class, specific[i]);
|
MinecraftReflection.getItemStackClass(), specific[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack[] getSpecific(Object generic) {
|
public ItemStack[] getSpecific(Object generic) {
|
||||||
net.minecraft.server.ItemStack[] input = (net.minecraft.server.ItemStack[]) generic;
|
Object[] input = (Object[]) generic;
|
||||||
ItemStack[] result = new ItemStack[input.length];
|
ItemStack[] result = new ItemStack[input.length];
|
||||||
|
|
||||||
// Add the wrapper
|
// Add the wrapper
|
||||||
@ -273,7 +280,7 @@ public class PacketContainer implements Serializable {
|
|||||||
public StructureModifier<WorldType> getWorldTypeModifier() {
|
public StructureModifier<WorldType> getWorldTypeModifier() {
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.<WorldType>withType(
|
return structureModifier.<WorldType>withType(
|
||||||
net.minecraft.server.WorldType.class,
|
MinecraftReflection.getWorldTypeClass(),
|
||||||
BukkitConverters.getWorldTypeConverter());
|
BukkitConverters.getWorldTypeConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,7 +291,7 @@ public class PacketContainer implements Serializable {
|
|||||||
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
|
public StructureModifier<WrappedDataWatcher> getDataWatcherModifier() {
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.<WrappedDataWatcher>withType(
|
return structureModifier.<WrappedDataWatcher>withType(
|
||||||
net.minecraft.server.DataWatcher.class,
|
MinecraftReflection.getDataWatcherClass(),
|
||||||
BukkitConverters.getDataWatcherConverter());
|
BukkitConverters.getDataWatcherConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +318,7 @@ public class PacketContainer implements Serializable {
|
|||||||
public StructureModifier<ChunkPosition> getPositionModifier() {
|
public StructureModifier<ChunkPosition> getPositionModifier() {
|
||||||
// Convert to and from the Bukkit wrapper
|
// Convert to and from the Bukkit wrapper
|
||||||
return structureModifier.withType(
|
return structureModifier.withType(
|
||||||
net.minecraft.server.ChunkPosition.class,
|
MinecraftReflection.getChunkPositionClass(),
|
||||||
ChunkPosition.getConverter());
|
ChunkPosition.getConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,7 +334,7 @@ public class PacketContainer implements Serializable {
|
|||||||
return structureModifier.withType(
|
return structureModifier.withType(
|
||||||
Collection.class,
|
Collection.class,
|
||||||
BukkitConverters.getListConverter(
|
BukkitConverters.getListConverter(
|
||||||
net.minecraft.server.ChunkPosition.class,
|
MinecraftReflection.getChunkPositionClass(),
|
||||||
ChunkPosition.getConverter())
|
ChunkPosition.getConverter())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -344,7 +351,7 @@ public class PacketContainer implements Serializable {
|
|||||||
return structureModifier.withType(
|
return structureModifier.withType(
|
||||||
Collection.class,
|
Collection.class,
|
||||||
BukkitConverters.getListConverter(
|
BukkitConverters.getListConverter(
|
||||||
net.minecraft.server.WatchableObject.class,
|
MinecraftReflection.getWatchableObjectClass(),
|
||||||
BukkitConverters.getWatchableObjectConverter())
|
BukkitConverters.getWatchableObjectConverter())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -400,13 +407,11 @@ public class PacketContainer implements Serializable {
|
|||||||
// We'll take care of NULL packets as well
|
// We'll take care of NULL packets as well
|
||||||
output.writeBoolean(handle != null);
|
output.writeBoolean(handle != null);
|
||||||
|
|
||||||
// Retrieve the write method by reflection
|
|
||||||
if (writeMethod == null)
|
|
||||||
writeMethod = FuzzyReflection.fromObject(handle).getMethodByParameters("write", DataOutputStream.class);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Call the write-method
|
// Call the write-method
|
||||||
writeMethod.invoke(handle, new DataOutputStream(output));
|
getMethodLazily(writeMethods, handle.getClass(), "write", DataOutputStream.class).
|
||||||
|
invoke(handle, new DataOutputStream(output));
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new IOException("Minecraft packet doesn't support DataOutputStream", e);
|
throw new IOException("Minecraft packet doesn't support DataOutputStream", e);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
@ -429,13 +434,11 @@ public class PacketContainer implements Serializable {
|
|||||||
// Create a default instance of the packet
|
// Create a default instance of the packet
|
||||||
handle = StructureCache.newPacket(id);
|
handle = StructureCache.newPacket(id);
|
||||||
|
|
||||||
// Retrieve the read method by reflection
|
|
||||||
if (readMethod == null)
|
|
||||||
readMethod = FuzzyReflection.fromObject(handle).getMethodByParameters("read", DataInputStream.class);
|
|
||||||
|
|
||||||
// Call the read method
|
// Call the read method
|
||||||
try {
|
try {
|
||||||
readMethod.invoke(handle, new DataInputStream(input));
|
getMethodLazily(readMethods, handle.getClass(), "read", DataInputStream.class).
|
||||||
|
invoke(handle, new DataInputStream(input));
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
throw new IOException("Minecraft packet doesn't support DataInputStream", e);
|
throw new IOException("Minecraft packet doesn't support DataInputStream", e);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
@ -448,4 +451,30 @@ public class PacketContainer implements Serializable {
|
|||||||
structureModifier = structureModifier.withTarget(handle);
|
structureModifier = structureModifier.withTarget(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).getMethodByParameters(methodName, parameterClass);
|
||||||
|
method = lookup.putIfAbsent(handleClass, initialized);
|
||||||
|
|
||||||
|
// Use our version if we succeeded
|
||||||
|
if (method == null) {
|
||||||
|
method = initialized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,17 +28,14 @@ import java.util.HashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.minecraft.server.EntityPlayer;
|
|
||||||
import net.minecraft.server.EntityTrackerEntry;
|
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,6 +48,7 @@ class EntityUtilities {
|
|||||||
private static Field entityTrackerField;
|
private static Field entityTrackerField;
|
||||||
private static Field trackedEntitiesField;
|
private static Field trackedEntitiesField;
|
||||||
private static Field trackedPlayersField;
|
private static Field trackedPlayersField;
|
||||||
|
private static Field trackerField;
|
||||||
|
|
||||||
private static Method hashGetMethod;
|
private static Method hashGetMethod;
|
||||||
private static Method scanPlayersMethod;
|
private static Method scanPlayersMethod;
|
||||||
@ -142,9 +140,8 @@ class EntityUtilities {
|
|||||||
|
|
||||||
// Wrap every player - we also ensure that the underlying tracker list is immutable
|
// Wrap every player - we also ensure that the underlying tracker list is immutable
|
||||||
for (Object tracker : trackedPlayers) {
|
for (Object tracker : trackedPlayers) {
|
||||||
if (tracker instanceof EntityPlayer) {
|
if (MinecraftReflection.isMinecraftPlayer(tracker)) {
|
||||||
EntityPlayer nmsPlayer = (EntityPlayer) tracker;
|
result.add((Player) MinecraftReflection.getBukkitEntity(tracker));
|
||||||
result.add(nmsPlayer.getBukkitEntity());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -164,7 +161,8 @@ class EntityUtilities {
|
|||||||
* @throws FieldAccessException
|
* @throws FieldAccessException
|
||||||
*/
|
*/
|
||||||
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException, IllegalAccessException, InvocationTargetException {
|
||||||
Object worldServer = ((CraftWorld) world).getHandle();
|
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||||
|
Object worldServer = unwrapper.unwrapItem(world);
|
||||||
|
|
||||||
// We have to rely on the class naming here.
|
// We have to rely on the class naming here.
|
||||||
if (entityTrackerField == null)
|
if (entityTrackerField == null)
|
||||||
@ -193,7 +191,7 @@ class EntityUtilities {
|
|||||||
|
|
||||||
// The Minecraft field that's NOT filled in by the constructor
|
// The Minecraft field that's NOT filled in by the constructor
|
||||||
trackedEntitiesField = FuzzyReflection.fromObject(tracker, true).
|
trackedEntitiesField = FuzzyReflection.fromObject(tracker, true).
|
||||||
getFieldByType(FuzzyReflection.MINECRAFT_OBJECT, ignoredTypes);
|
getFieldByType(MinecraftReflection.MINECRAFT_OBJECT, ignoredTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the entity hashmap
|
// Read the entity hashmap
|
||||||
@ -247,17 +245,24 @@ class EntityUtilities {
|
|||||||
*/
|
*/
|
||||||
public static Entity getEntityFromID(World world, int entityID) throws FieldAccessException {
|
public static Entity getEntityFromID(World world, int entityID) throws FieldAccessException {
|
||||||
try {
|
try {
|
||||||
EntityTrackerEntry trackerEntry = (EntityTrackerEntry) getEntityTrackerEntry(world, entityID);
|
Object trackerEntry = getEntityTrackerEntry(world, entityID);
|
||||||
|
Object tracker = null;
|
||||||
|
|
||||||
// Handle NULL cases
|
// Handle NULL cases
|
||||||
if (trackerEntry != null && trackerEntry.tracker != null) {
|
if (trackerEntry != null) {
|
||||||
return trackerEntry.tracker.getBukkitEntity();
|
if (trackerField == null)
|
||||||
} else {
|
trackerField = trackerEntry.getClass().getField("tracker");
|
||||||
return null;
|
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) {
|
} catch (Exception e) {
|
||||||
throw new FieldAccessException("Cannot find entity from ID.", e);
|
throw new FieldAccessException("Cannot find entity from ID " + entityID + ".", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,6 @@
|
|||||||
|
|
||||||
package com.comphenix.protocol.injector;
|
package com.comphenix.protocol.injector;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,7 +43,7 @@ public interface ListenerInvoker {
|
|||||||
* @param packet - the packet.
|
* @param packet - the packet.
|
||||||
* @return The packet ID.
|
* @return The packet ID.
|
||||||
*/
|
*/
|
||||||
public abstract int getPacketID(Packet packet);
|
public abstract int getPacketID(Object packet);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Associate a given class with the given packet ID. Internal method.
|
* Associate a given class with the given packet ID. Internal method.
|
||||||
|
@ -23,11 +23,12 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
import net.sf.cglib.proxy.Factory;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ class MinecraftRegistry {
|
|||||||
*/
|
*/
|
||||||
private static FuzzyReflection getPacketRegistry() {
|
private static FuzzyReflection getPacketRegistry() {
|
||||||
if (packetRegistry == null)
|
if (packetRegistry == null)
|
||||||
packetRegistry = FuzzyReflection.fromClass(Packet.class, true);
|
packetRegistry = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true);
|
||||||
return packetRegistry;
|
return packetRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ class MinecraftRegistry {
|
|||||||
|
|
||||||
// Optimized lookup
|
// Optimized lookup
|
||||||
if (lookup.containsKey(packetID)) {
|
if (lookup.containsKey(packetID)) {
|
||||||
return lookup.get(packetID);
|
return removeEnhancer(lookup.get(packetID), forceVanilla);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will most likely not be used
|
// Will most likely not be used
|
||||||
@ -174,10 +175,27 @@ class MinecraftRegistry {
|
|||||||
if (Objects.equal(entry.getValue(), packetID)) {
|
if (Objects.equal(entry.getValue(), packetID)) {
|
||||||
// Attempt to get the vanilla class here too
|
// Attempt to get the vanilla class here too
|
||||||
if (!forceVanilla || entry.getKey().getName().startsWith("net.minecraft.server"))
|
if (!forceVanilla || entry.getKey().getName().startsWith("net.minecraft.server"))
|
||||||
return entry.getKey();
|
return removeEnhancer(entry.getKey(), forceVanilla);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IllegalArgumentException("The packet ID " + packetID + " is not registered.");
|
throw new IllegalArgumentException("The packet ID " + packetID + " is not registered.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first superclass that is not a CBLib proxy object.
|
||||||
|
* @param clazz - the class whose hierachy we're going to search through.
|
||||||
|
* @param remove - whether or not to skip enhanced (proxy) classes.
|
||||||
|
* @return If remove is TRUE, the first superclass that is not a proxy.
|
||||||
|
*/
|
||||||
|
private static Class removeEnhancer(Class clazz, boolean remove) {
|
||||||
|
if (remove) {
|
||||||
|
// Get the underlying vanilla class
|
||||||
|
while (Factory.class.isAssignableFrom(clazz) && !clazz.equals(Object.class)) {
|
||||||
|
clazz = clazz.getSuperclass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,6 @@ import java.lang.reflect.Constructor;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@ -157,7 +155,7 @@ public class PacketConstructor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Packet nmsPacket = (Packet) constructorMethod.newInstance(values);
|
Object nmsPacket = constructorMethod.newInstance(values);
|
||||||
return new PacketContainer(packetID, nmsPacket);
|
return new PacketContainer(packetID, nmsPacket);
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
|
@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.Enhancer;
|
import net.sf.cglib.proxy.Enhancer;
|
||||||
import net.sf.cglib.proxy.MethodInterceptor;
|
import net.sf.cglib.proxy.MethodInterceptor;
|
||||||
import net.sf.cglib.proxy.MethodProxy;
|
import net.sf.cglib.proxy.MethodProxy;
|
||||||
@ -55,6 +54,7 @@ import com.comphenix.protocol.events.*;
|
|||||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
@ -508,7 +508,7 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
if (packetCreation.compareAndSet(false, true))
|
if (packetCreation.compareAndSet(false, true))
|
||||||
incrementPhases(GamePhase.PLAYING);
|
incrementPhases(GamePhase.PLAYING);
|
||||||
|
|
||||||
Packet mcPacket = packet.getHandle();
|
Object mcPacket = packet.getHandle();
|
||||||
|
|
||||||
// Make sure the packet isn't cancelled
|
// Make sure the packet isn't cancelled
|
||||||
packetInjector.undoCancel(packet.getID(), mcPacket);
|
packetInjector.undoCancel(packet.getID(), mcPacket);
|
||||||
@ -686,9 +686,11 @@ public final class PacketFilterManager implements ProtocolManager, ListenerInvok
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getPacketID(Packet packet) {
|
public int getPacketID(Object packet) {
|
||||||
if (packet == null)
|
if (packet == null)
|
||||||
throw new IllegalArgumentException("Packet cannot be NULL.");
|
throw new IllegalArgumentException("Packet cannot be NULL.");
|
||||||
|
if (!MinecraftReflection.isPacketClass(packet))
|
||||||
|
throw new IllegalArgumentException("The given object " + packet + " is not a packet.");
|
||||||
|
|
||||||
return MinecraftRegistry.getPacketToID().get(packet.getClass());
|
return MinecraftRegistry.getPacketToID().get(packet.getClass());
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.Callback;
|
import net.sf.cglib.proxy.Callback;
|
||||||
import net.sf.cglib.proxy.Enhancer;
|
import net.sf.cglib.proxy.Enhancer;
|
||||||
|
|
||||||
@ -37,6 +36,7 @@ import com.comphenix.protocol.events.PacketEvent;
|
|||||||
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
import com.comphenix.protocol.injector.player.PlayerInjectionHandler;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class is responsible for adding or removing proxy objects that intercepts recieved packets.
|
* This class is responsible for adding or removing proxy objects that intercepts recieved packets.
|
||||||
@ -80,7 +80,7 @@ class PacketInjector {
|
|||||||
* @param id - the id of the packet.
|
* @param id - the id of the packet.
|
||||||
* @param packet - packet to uncancel.
|
* @param packet - packet to uncancel.
|
||||||
*/
|
*/
|
||||||
public void undoCancel(Integer id, Packet packet) {
|
public void undoCancel(Integer id, Object packet) {
|
||||||
ReadPacketModifier modifier = readModifier.get(id);
|
ReadPacketModifier modifier = readModifier.get(id);
|
||||||
|
|
||||||
// See if this packet has been cancelled before
|
// See if this packet has been cancelled before
|
||||||
@ -92,7 +92,8 @@ class PacketInjector {
|
|||||||
private void initialize() throws IllegalAccessException {
|
private void initialize() throws IllegalAccessException {
|
||||||
if (intHashMap == null) {
|
if (intHashMap == null) {
|
||||||
// We're looking for the first static field with a Minecraft-object. This should be a IntHashMap.
|
// We're looking for the first static field with a Minecraft-object. This should be a IntHashMap.
|
||||||
Field intHashMapField = FuzzyReflection.fromClass(Packet.class, true).getFieldByType(FuzzyReflection.MINECRAFT_OBJECT);
|
Field intHashMapField = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass(), true).
|
||||||
|
getFieldByType(MinecraftReflection.MINECRAFT_OBJECT);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true);
|
intHashMap = FieldUtils.readField(intHashMapField, (Object) null, true);
|
||||||
|
@ -29,7 +29,6 @@ import com.comphenix.protocol.error.ErrorReporter;
|
|||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.MethodInterceptor;
|
import net.sf.cglib.proxy.MethodInterceptor;
|
||||||
import net.sf.cglib.proxy.MethodProxy;
|
import net.sf.cglib.proxy.MethodProxy;
|
||||||
|
|
||||||
@ -61,7 +60,7 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
* Remove any packet overrides.
|
* Remove any packet overrides.
|
||||||
* @param packet - the packet to rever
|
* @param packet - the packet to rever
|
||||||
*/
|
*/
|
||||||
public void removeOverride(Packet packet) {
|
public void removeOverride(Object packet) {
|
||||||
override.remove(packet);
|
override.remove(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +69,7 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
* @param packet - the given packet.
|
* @param packet - the given packet.
|
||||||
* @return Overriden object.
|
* @return Overriden object.
|
||||||
*/
|
*/
|
||||||
public Object getOverride(Packet packet) {
|
public Object getOverride(Object packet) {
|
||||||
return override.get(packet);
|
return override.get(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +78,7 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
* @param packet - the packet to check.
|
* @param packet - the packet to check.
|
||||||
* @return TRUE if it has been cancelled, FALSE otherwise.
|
* @return TRUE if it has been cancelled, FALSE otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean hasCancelled(Packet packet) {
|
public boolean hasCancelled(Object packet) {
|
||||||
return getOverride(packet) == CANCEL_MARKER;
|
return getOverride(packet) == CANCEL_MARKER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,12 +120,12 @@ class ReadPacketModifier implements MethodInterceptor {
|
|||||||
DataInputStream input = (DataInputStream) args[0];
|
DataInputStream input = (DataInputStream) args[0];
|
||||||
|
|
||||||
// Let the people know
|
// Let the people know
|
||||||
PacketContainer container = new PacketContainer(packetID, (Packet) thisObj);
|
PacketContainer container = new PacketContainer(packetID, thisObj);
|
||||||
PacketEvent event = packetInjector.packetRecieved(container, input);
|
PacketEvent event = packetInjector.packetRecieved(container, input);
|
||||||
|
|
||||||
// Handle override
|
// Handle override
|
||||||
if (event != null) {
|
if (event != null) {
|
||||||
Packet result = event.getPacket().getHandle();
|
Object result = event.getPacket().getHandle();
|
||||||
|
|
||||||
if (event.isCancelled()) {
|
if (event.isCancelled()) {
|
||||||
override.put(thisObj, CANCEL_MARKER);
|
override.put(thisObj, CANCEL_MARKER);
|
||||||
|
@ -48,7 +48,8 @@ public final class SortedPacketListenerList extends AbstractConcurrentListenerMu
|
|||||||
element.getListener().onPacketReceiving(event);
|
element.getListener().onPacketReceiving(event);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Minecraft doesn't want your Exception.
|
// Minecraft doesn't want your Exception.
|
||||||
reporter.reportMinimal(element.getListener().getPlugin(), "onPacketReceiving()", e);
|
reporter.reportMinimal(element.getListener().getPlugin(), "onPacketReceiving(PacketEvent)", e,
|
||||||
|
event.getPacket().getHandle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +70,8 @@ public final class SortedPacketListenerList extends AbstractConcurrentListenerMu
|
|||||||
element.getListener().onPacketSending(event);
|
element.getListener().onPacketSending(event);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
// Minecraft doesn't want your Exception.
|
// Minecraft doesn't want your Exception.
|
||||||
reporter.reportMinimal(element.getListener().getPlugin(), "onPacketSending()", e);
|
reporter.reportMinimal(element.getListener().getPlugin(), "onPacketSending(PacketEvent)", e,
|
||||||
|
event.getPacket().getHandle());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,11 @@ import java.util.Set;
|
|||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
||||||
import com.comphenix.protocol.reflect.compiler.CompileListener;
|
import com.comphenix.protocol.reflect.compiler.CompileListener;
|
||||||
import com.comphenix.protocol.reflect.compiler.CompiledStructureModifier;
|
import com.comphenix.protocol.reflect.compiler.CompiledStructureModifier;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Caches structure modifiers.
|
* Caches structure modifiers.
|
||||||
@ -45,9 +44,9 @@ public class StructureCache {
|
|||||||
* @param id - packet ID.
|
* @param id - packet ID.
|
||||||
* @return Created packet.
|
* @return Created packet.
|
||||||
*/
|
*/
|
||||||
public static Packet newPacket(int id) {
|
public static Object newPacket(int id) {
|
||||||
try {
|
try {
|
||||||
return (Packet) MinecraftRegistry.getPacketClassFromID(id, true).newInstance();
|
return MinecraftRegistry.getPacketClassFromID(id, true).newInstance();
|
||||||
} catch (InstantiationException e) {
|
} catch (InstantiationException e) {
|
||||||
return null;
|
return null;
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
@ -79,7 +78,7 @@ public class StructureCache {
|
|||||||
if (result == null) {
|
if (result == null) {
|
||||||
// Use the vanilla class definition
|
// Use the vanilla class definition
|
||||||
final StructureModifier<Object> value = new StructureModifier<Object>(
|
final StructureModifier<Object> value = new StructureModifier<Object>(
|
||||||
MinecraftRegistry.getPacketClassFromID(id, true), Packet.class, true);
|
MinecraftRegistry.getPacketClassFromID(id, true), MinecraftReflection.getPacketClass(), true);
|
||||||
|
|
||||||
result = structureModifiers.putIfAbsent(id, value);
|
result = structureModifiers.putIfAbsent(id, value);
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import java.util.Set;
|
|||||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket;
|
import com.comphenix.protocol.injector.player.NetworkFieldInjector.FakePacket;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
import net.sf.cglib.proxy.Callback;
|
||||||
import net.sf.cglib.proxy.Enhancer;
|
import net.sf.cglib.proxy.Enhancer;
|
||||||
import net.sf.cglib.proxy.MethodInterceptor;
|
import net.sf.cglib.proxy.MethodInterceptor;
|
||||||
import net.sf.cglib.proxy.MethodProxy;
|
import net.sf.cglib.proxy.MethodProxy;
|
||||||
@ -35,7 +35,7 @@ import net.sf.cglib.proxy.MethodProxy;
|
|||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class InjectedArrayList extends ArrayList<Packet> {
|
class InjectedArrayList extends ArrayList<Object> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Silly Eclipse.
|
* Silly Eclipse.
|
||||||
@ -43,19 +43,22 @@ class InjectedArrayList extends ArrayList<Packet> {
|
|||||||
private static final long serialVersionUID = -1173865905404280990L;
|
private static final long serialVersionUID = -1173865905404280990L;
|
||||||
|
|
||||||
private transient PlayerInjector injector;
|
private transient PlayerInjector injector;
|
||||||
private transient Set<Packet> ignoredPackets;
|
private transient Set<Object> ignoredPackets;
|
||||||
private transient ClassLoader classLoader;
|
private transient ClassLoader classLoader;
|
||||||
|
|
||||||
public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set<Packet> ignoredPackets) {
|
private transient InvertedIntegerCallback callback;
|
||||||
|
|
||||||
|
public InjectedArrayList(ClassLoader classLoader, PlayerInjector injector, Set<Object> ignoredPackets) {
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.injector = injector;
|
this.injector = injector;
|
||||||
this.ignoredPackets = ignoredPackets;
|
this.ignoredPackets = ignoredPackets;
|
||||||
|
this.callback = new InvertedIntegerCallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(Packet packet) {
|
public boolean add(Object packet) {
|
||||||
|
|
||||||
Packet result = null;
|
Object result = null;
|
||||||
|
|
||||||
// Check for fake packets and ignored packets
|
// Check for fake packets and ignored packets
|
||||||
if (packet instanceof FakePacket) {
|
if (packet instanceof FakePacket) {
|
||||||
@ -90,12 +93,14 @@ class InjectedArrayList extends ArrayList<Packet> {
|
|||||||
* @param source - packet to invert.
|
* @param source - packet to invert.
|
||||||
* @return The inverted packet.
|
* @return The inverted packet.
|
||||||
*/
|
*/
|
||||||
Packet createNegativePacket(Packet source) {
|
Object createNegativePacket(Object source) {
|
||||||
ListenerInvoker invoker = injector.getInvoker();
|
ListenerInvoker invoker = injector.getInvoker();
|
||||||
|
|
||||||
int packetID = invoker.getPacketID(source);
|
int packetID = invoker.getPacketID(source);
|
||||||
Class<?> type = invoker.getPacketClassFromID(packetID, true);
|
Class<?> type = invoker.getPacketClassFromID(packetID, true);
|
||||||
|
|
||||||
|
System.out.println(type.getName());
|
||||||
|
|
||||||
// We want to subtract the byte amount that were added to the running
|
// We want to subtract the byte amount that were added to the running
|
||||||
// total of outstanding packets. Otherwise, cancelling too many packets
|
// total of outstanding packets. Otherwise, cancelling too many packets
|
||||||
// might cause a "disconnect.overflow" error.
|
// might cause a "disconnect.overflow" error.
|
||||||
@ -122,15 +127,20 @@ class InjectedArrayList extends ArrayList<Packet> {
|
|||||||
ex.setCallbackType(InvertedIntegerCallback.class);
|
ex.setCallbackType(InvertedIntegerCallback.class);
|
||||||
|
|
||||||
Class<?> proxyClass = ex.createClass();
|
Class<?> proxyClass = ex.createClass();
|
||||||
|
Enhancer.registerCallbacks(proxyClass, new Callback[] { callback });
|
||||||
|
|
||||||
|
try {
|
||||||
// Temporarily associate the fake packet class
|
// Temporarily associate the fake packet class
|
||||||
invoker.registerPacketClass(proxyClass, packetID);
|
invoker.registerPacketClass(proxyClass, packetID);
|
||||||
|
return proxyClass.newInstance();
|
||||||
|
|
||||||
Packet fake = (Packet) Enhancer.create(proxyClass, new InvertedIntegerCallback());
|
} catch (Exception e) {
|
||||||
|
// Don't pollute the throws tree
|
||||||
|
throw new RuntimeException("Cannot create fake class.", e);
|
||||||
|
} finally {
|
||||||
// Remove this association
|
// Remove this association
|
||||||
invoker.unregisterPacketClass(proxyClass);
|
invoker.unregisterPacketClass(proxyClass);
|
||||||
return fake;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,7 +22,6 @@ import java.lang.reflect.Method;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.minecraft.server.NetLoginHandler;
|
|
||||||
import net.sf.cglib.proxy.Factory;
|
import net.sf.cglib.proxy.Factory;
|
||||||
|
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
@ -32,6 +31,7 @@ import com.comphenix.protocol.reflect.FieldUtils;
|
|||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.ObjectCloner;
|
import com.comphenix.protocol.reflect.ObjectCloner;
|
||||||
import com.comphenix.protocol.reflect.VolatileField;
|
import com.comphenix.protocol.reflect.VolatileField;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to ensure that the 1.3 server is referencing the correct server handler.
|
* Used to ensure that the 1.3 server is referencing the correct server handler.
|
||||||
@ -229,7 +229,7 @@ class InjectedServerConnection {
|
|||||||
@Override
|
@Override
|
||||||
protected void onInserting(Object inserting) {
|
protected void onInserting(Object inserting) {
|
||||||
// Ready for some login handler injection?
|
// Ready for some login handler injection?
|
||||||
if (inserting instanceof NetLoginHandler) {
|
if (MinecraftReflection.isLoginHandler(inserting)) {
|
||||||
Object replaced = netLoginInjector.onNetLoginCreated(inserting);
|
Object replaced = netLoginInjector.onNetLoginCreated(inserting);
|
||||||
|
|
||||||
// Only replace if it has changed
|
// Only replace if it has changed
|
||||||
@ -241,7 +241,7 @@ class InjectedServerConnection {
|
|||||||
@Override
|
@Override
|
||||||
protected void onRemoved(Object removing) {
|
protected void onRemoved(Object removing) {
|
||||||
// Clean up?
|
// Clean up?
|
||||||
if (removing instanceof NetLoginHandler) {
|
if (MinecraftReflection.isLoginHandler(removing)) {
|
||||||
netLoginInjector.cleanup(removing);
|
netLoginInjector.cleanup(removing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,6 @@ import com.comphenix.protocol.reflect.StructureModifier;
|
|||||||
import com.comphenix.protocol.reflect.VolatileField;
|
import com.comphenix.protocol.reflect.VolatileField;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injection hook that overrides the packet queue lists in NetworkHandler.
|
* Injection hook that overrides the packet queue lists in NetworkHandler.
|
||||||
*
|
*
|
||||||
@ -58,7 +56,7 @@ class NetworkFieldInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Packets to ignore
|
// Packets to ignore
|
||||||
private Set<Packet> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Packet, Boolean>());
|
private Set<Object> ignoredPackets = Sets.newSetFromMap(new ConcurrentHashMap<Object, Boolean>());
|
||||||
|
|
||||||
// Overridden fields
|
// Overridden fields
|
||||||
private List<VolatileField> overridenLists = new ArrayList<VolatileField>();
|
private List<VolatileField> overridenLists = new ArrayList<VolatileField>();
|
||||||
@ -99,7 +97,7 @@ class NetworkFieldInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||||
|
|
||||||
if (networkManager != null) {
|
if (networkManager != null) {
|
||||||
try {
|
try {
|
||||||
@ -147,14 +145,14 @@ class NetworkFieldInjector extends PlayerInjector {
|
|||||||
VolatileField overwriter = new VolatileField(field, networkManager, true);
|
VolatileField overwriter = new VolatileField(field, networkManager, true);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
List<Packet> minecraftList = (List<Packet>) overwriter.getOldValue();
|
List<Object> minecraftList = (List<Object>) overwriter.getOldValue();
|
||||||
|
|
||||||
synchronized(syncObject) {
|
synchronized(syncObject) {
|
||||||
// The list we'll be inserting
|
// The list we'll be inserting
|
||||||
List<Packet> hackedList = new InjectedArrayList(classLoader, this, ignoredPackets);
|
List<Object> hackedList = new InjectedArrayList(classLoader, this, ignoredPackets);
|
||||||
|
|
||||||
// Add every previously stored packet
|
// Add every previously stored packet
|
||||||
for (Packet packet : minecraftList) {
|
for (Object packet : minecraftList) {
|
||||||
hackedList.add(packet);
|
hackedList.add(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,8 +170,8 @@ class NetworkFieldInjector extends PlayerInjector {
|
|||||||
protected void cleanHook() {
|
protected void cleanHook() {
|
||||||
// Clean up
|
// Clean up
|
||||||
for (VolatileField overriden : overridenLists) {
|
for (VolatileField overriden : overridenLists) {
|
||||||
List<Packet> minecraftList = (List<Packet>) overriden.getOldValue();
|
List<Object> minecraftList = (List<Object>) overriden.getOldValue();
|
||||||
List<Packet> hacketList = (List<Packet>) overriden.getValue();
|
List<Object> hacketList = (List<Object>) overriden.getValue();
|
||||||
|
|
||||||
if (minecraftList == hacketList) {
|
if (minecraftList == hacketList) {
|
||||||
return;
|
return;
|
||||||
@ -183,7 +181,7 @@ class NetworkFieldInjector extends PlayerInjector {
|
|||||||
synchronized(syncObject) {
|
synchronized(syncObject) {
|
||||||
try {
|
try {
|
||||||
// Copy over current packets
|
// Copy over current packets
|
||||||
for (Packet packet : (List<Packet>) overriden.getValue()) {
|
for (Object packet : (List<Object>) overriden.getValue()) {
|
||||||
minecraftList.add(packet);
|
minecraftList.add(packet);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -19,7 +19,6 @@ package com.comphenix.protocol.injector.player;
|
|||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.Callback;
|
import net.sf.cglib.proxy.Callback;
|
||||||
import net.sf.cglib.proxy.CallbackFilter;
|
import net.sf.cglib.proxy.CallbackFilter;
|
||||||
import net.sf.cglib.proxy.Enhancer;
|
import net.sf.cglib.proxy.Enhancer;
|
||||||
@ -67,7 +66,7 @@ class NetworkObjectInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||||
Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue();
|
Object networkDelegate = filtered ? networkManagerRef.getValue() : networkManagerRef.getOldValue();
|
||||||
|
|
||||||
if (networkDelegate != null) {
|
if (networkDelegate != null) {
|
||||||
@ -114,7 +113,7 @@ class NetworkObjectInjector extends PlayerInjector {
|
|||||||
Callback queueFilter = new MethodInterceptor() {
|
Callback queueFilter = new MethodInterceptor() {
|
||||||
@Override
|
@Override
|
||||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||||
Packet packet = (Packet) args[0];
|
Object packet = args[0];
|
||||||
|
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
packet = handlePacketSending(packet);
|
packet = handlePacketSending(packet);
|
||||||
|
@ -21,7 +21,6 @@ import java.lang.reflect.Field;
|
|||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.Callback;
|
import net.sf.cglib.proxy.Callback;
|
||||||
import net.sf.cglib.proxy.CallbackFilter;
|
import net.sf.cglib.proxy.CallbackFilter;
|
||||||
import net.sf.cglib.proxy.Enhancer;
|
import net.sf.cglib.proxy.Enhancer;
|
||||||
@ -43,6 +42,7 @@ import com.comphenix.protocol.reflect.ObjectCloner;
|
|||||||
import com.comphenix.protocol.reflect.VolatileField;
|
import com.comphenix.protocol.reflect.VolatileField;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
import com.comphenix.protocol.reflect.instances.ExistingGenerator;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a player hook into the NetServerHandler class.
|
* Represents a player hook into the NetServerHandler class.
|
||||||
@ -94,7 +94,7 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException {
|
public void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException {
|
||||||
Object serverDeleage = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
|
Object serverDeleage = filtered ? serverHandlerRef.getValue() : serverHandlerRef.getOldValue();
|
||||||
|
|
||||||
if (serverDeleage != null) {
|
if (serverDeleage != null) {
|
||||||
@ -152,8 +152,7 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
Callback sendPacketCallback = new MethodInterceptor() {
|
Callback sendPacketCallback = new MethodInterceptor() {
|
||||||
@Override
|
@Override
|
||||||
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
|
||||||
|
Object packet = args[0];
|
||||||
Packet packet = (Packet) args[0];
|
|
||||||
|
|
||||||
if (packet != null) {
|
if (packet != null) {
|
||||||
packet = handlePacketSending(packet);
|
packet = handlePacketSending(packet);
|
||||||
@ -237,7 +236,7 @@ public class NetworkServerInjector extends PlayerInjector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
private Class<?> getFirstMinecraftSuperClass(Class<?> clazz) {
|
||||||
if (clazz.getName().startsWith("net.minecraft.server."))
|
if (clazz.getName().startsWith(MinecraftReflection.getMinecraftPackage()))
|
||||||
return clazz;
|
return clazz;
|
||||||
else if (clazz.equals(Object.class))
|
else if (clazz.equals(Object.class))
|
||||||
return clazz;
|
return clazz;
|
||||||
|
@ -26,8 +26,6 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
|
|
||||||
import org.bukkit.Server;
|
import org.bukkit.Server;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
@ -501,7 +499,7 @@ public class PlayerInjectionHandler {
|
|||||||
* @throws IllegalAccessException If the reflection machinery failed.
|
* @throws IllegalAccessException If the reflection machinery failed.
|
||||||
* @throws InvocationTargetException If the underlying method caused an error.
|
* @throws InvocationTargetException If the underlying method caused an error.
|
||||||
*/
|
*/
|
||||||
public void processPacket(Player player, Packet mcPacket) throws IllegalAccessException, InvocationTargetException {
|
public void processPacket(Player player, Object mcPacket) throws IllegalAccessException, InvocationTargetException {
|
||||||
|
|
||||||
PlayerInjector injector = getInjector(player);
|
PlayerInjector injector = getInjector(player);
|
||||||
|
|
||||||
|
@ -25,12 +25,8 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
|
|
||||||
import net.minecraft.server.EntityPlayer;
|
|
||||||
import net.minecraft.server.NetLoginHandler;
|
|
||||||
import net.minecraft.server.Packet;
|
|
||||||
import net.sf.cglib.proxy.Factory;
|
import net.sf.cglib.proxy.Factory;
|
||||||
|
|
||||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import com.comphenix.protocol.Packets;
|
import com.comphenix.protocol.Packets;
|
||||||
@ -38,6 +34,7 @@ import com.comphenix.protocol.error.ErrorReporter;
|
|||||||
import com.comphenix.protocol.events.PacketContainer;
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
|
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||||
import com.comphenix.protocol.injector.GamePhase;
|
import com.comphenix.protocol.injector.GamePhase;
|
||||||
import com.comphenix.protocol.injector.ListenerInvoker;
|
import com.comphenix.protocol.injector.ListenerInvoker;
|
||||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||||
@ -45,6 +42,7 @@ import com.comphenix.protocol.reflect.FieldUtils;
|
|||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.VolatileField;
|
import com.comphenix.protocol.reflect.VolatileField;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
abstract class PlayerInjector {
|
abstract class PlayerInjector {
|
||||||
|
|
||||||
@ -122,9 +120,9 @@ abstract class PlayerInjector {
|
|||||||
* @param player - the player to retrieve.
|
* @param player - the player to retrieve.
|
||||||
* @return Notch player object.
|
* @return Notch player object.
|
||||||
*/
|
*/
|
||||||
protected EntityPlayer getEntityPlayer(Player player) {
|
protected Object getEntityPlayer(Player player) {
|
||||||
CraftPlayer craft = (CraftPlayer) player;
|
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||||
return craft.getHandle();
|
return unwrapper.unwrapItem(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -138,7 +136,7 @@ abstract class PlayerInjector {
|
|||||||
//Dispatch to the correct injection method
|
//Dispatch to the correct injection method
|
||||||
if (injectionSource instanceof Player)
|
if (injectionSource instanceof Player)
|
||||||
initializePlayer(injectionSource);
|
initializePlayer(injectionSource);
|
||||||
else if (injectionSource instanceof NetLoginHandler)
|
else if (MinecraftReflection.isLoginHandler(injectionSource))
|
||||||
initializeLogin(injectionSource);
|
initializeLogin(injectionSource);
|
||||||
else
|
else
|
||||||
throw new IllegalArgumentException("Cannot initialize a player hook using a " + injectionSource.getClass().getName());
|
throw new IllegalArgumentException("Cannot initialize a player hook using a " + injectionSource.getClass().getName());
|
||||||
@ -150,7 +148,7 @@ abstract class PlayerInjector {
|
|||||||
*/
|
*/
|
||||||
public void initializePlayer(Object player) {
|
public void initializePlayer(Object player) {
|
||||||
|
|
||||||
EntityPlayer notchEntity = getEntityPlayer((Player) player);
|
Object notchEntity = getEntityPlayer((Player) player);
|
||||||
|
|
||||||
if (!hasInitialized) {
|
if (!hasInitialized) {
|
||||||
// Do this first, in case we encounter an exception
|
// Do this first, in case we encounter an exception
|
||||||
@ -204,7 +202,7 @@ abstract class PlayerInjector {
|
|||||||
// And the queue method
|
// And the queue method
|
||||||
if (queueMethod == null)
|
if (queueMethod == null)
|
||||||
queueMethod = FuzzyReflection.fromClass(reference.getType()).
|
queueMethod = FuzzyReflection.fromClass(reference.getType()).
|
||||||
getMethodByParameters("queue", Packet.class );
|
getMethodByParameters("queue", MinecraftReflection.getPacketClass());
|
||||||
|
|
||||||
// And the data input stream that we'll use to identify a player
|
// And the data input stream that we'll use to identify a player
|
||||||
if (inputField == null)
|
if (inputField == null)
|
||||||
@ -323,7 +321,7 @@ abstract class PlayerInjector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Field getProxyField(EntityPlayer notchEntity, Field serverField) {
|
private Field getProxyField(Object notchEntity, Field serverField) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Object handler = FieldUtils.readField(serverHandlerField, notchEntity, true);
|
Object handler = FieldUtils.readField(serverHandlerField, notchEntity, true);
|
||||||
@ -379,7 +377,7 @@ abstract class PlayerInjector {
|
|||||||
try {
|
try {
|
||||||
// Well, that sucks. Try just Minecraft objects then.
|
// Well, that sucks. Try just Minecraft objects then.
|
||||||
netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true).
|
netHandlerField = FuzzyReflection.fromClass(networkManager.getClass(), true).
|
||||||
getFieldByType(FuzzyReflection.MINECRAFT_OBJECT);
|
getFieldByType(MinecraftReflection.MINECRAFT_OBJECT);
|
||||||
|
|
||||||
} catch (RuntimeException e2) {
|
} catch (RuntimeException e2) {
|
||||||
throw new IllegalAccessException("Cannot locate net handler. " + e2.getMessage());
|
throw new IllegalAccessException("Cannot locate net handler. " + e2.getMessage());
|
||||||
@ -398,10 +396,10 @@ abstract class PlayerInjector {
|
|||||||
* @return The stored entity player.
|
* @return The stored entity player.
|
||||||
* @throws IllegalAccessException If the reflection failed.
|
* @throws IllegalAccessException If the reflection failed.
|
||||||
*/
|
*/
|
||||||
private EntityPlayer getEntityPlayer(Object netHandler) throws IllegalAccessException {
|
private Object getEntityPlayer(Object netHandler) throws IllegalAccessException {
|
||||||
if (entityPlayerField == null)
|
if (entityPlayerField == null)
|
||||||
entityPlayerField = FuzzyReflection.fromObject(netHandler).getFieldByType(".*EntityPlayer");
|
entityPlayerField = FuzzyReflection.fromObject(netHandler).getFieldByType(".*EntityPlayer");
|
||||||
return (EntityPlayer) FieldUtils.readField(entityPlayerField, netHandler);
|
return FieldUtils.readField(entityPlayerField, netHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -410,14 +408,14 @@ abstract class PlayerInjector {
|
|||||||
* @throws IllegalAccessException If the reflection machinery failed.
|
* @throws IllegalAccessException If the reflection machinery failed.
|
||||||
* @throws InvocationTargetException If the underlying method caused an error.
|
* @throws InvocationTargetException If the underlying method caused an error.
|
||||||
*/
|
*/
|
||||||
public void processPacket(Packet packet) throws IllegalAccessException, InvocationTargetException {
|
public void processPacket(Object packet) throws IllegalAccessException, InvocationTargetException {
|
||||||
|
|
||||||
Object netHandler = getNetHandler();
|
Object netHandler = getNetHandler();
|
||||||
|
|
||||||
// Get the process method
|
// Get the process method
|
||||||
if (processMethod == null) {
|
if (processMethod == null) {
|
||||||
try {
|
try {
|
||||||
processMethod = FuzzyReflection.fromClass(Packet.class).
|
processMethod = FuzzyReflection.fromClass(MinecraftReflection.getPacketClass()).
|
||||||
getMethodByParameters("processPacket", netHandlerField.getType());
|
getMethodByParameters("processPacket", netHandlerField.getType());
|
||||||
} catch (RuntimeException e) {
|
} catch (RuntimeException e) {
|
||||||
throw new IllegalArgumentException("Cannot locate process packet method: " + e.getMessage());
|
throw new IllegalArgumentException("Cannot locate process packet method: " + e.getMessage());
|
||||||
@ -440,7 +438,7 @@ abstract class PlayerInjector {
|
|||||||
* @param filtered - whether or not the packet will be filtered by our listeners.
|
* @param filtered - whether or not the packet will be filtered by our listeners.
|
||||||
* @param InvocationTargetException If an error occured when sending the packet.
|
* @param InvocationTargetException If an error occured when sending the packet.
|
||||||
*/
|
*/
|
||||||
public abstract void sendServerPacket(Packet packet, boolean filtered) throws InvocationTargetException;
|
public abstract void sendServerPacket(Object packet, boolean filtered) throws InvocationTargetException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inject a hook to catch packets sent to the current player.
|
* Inject a hook to catch packets sent to the current player.
|
||||||
@ -501,7 +499,7 @@ abstract class PlayerInjector {
|
|||||||
* @param packet - packet to sent.
|
* @param packet - packet to sent.
|
||||||
* @return The given packet, or the packet replaced by the listeners.
|
* @return The given packet, or the packet replaced by the listeners.
|
||||||
*/
|
*/
|
||||||
public Packet handlePacketSending(Packet packet) {
|
public Object handlePacketSending(Object packet) {
|
||||||
try {
|
try {
|
||||||
// Get the packet ID too
|
// Get the packet ID too
|
||||||
Integer id = invoker.getPacketID(packet);
|
Integer id = invoker.getPacketID(packet);
|
||||||
@ -516,7 +514,7 @@ abstract class PlayerInjector {
|
|||||||
if (updateOnLogin) {
|
if (updateOnLogin) {
|
||||||
if (id == Packets.Server.LOGIN) {
|
if (id == Packets.Server.LOGIN) {
|
||||||
try {
|
try {
|
||||||
updatedPlayer = getEntityPlayer(getNetHandler()).getBukkitEntity();
|
updatedPlayer = (Player) MinecraftReflection.getBukkitEntity(getEntityPlayer(getNetHandler()));
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
reporter.reportDetailed(this, "Cannot update player in PlayerEvent.", e, packet);
|
reporter.reportDetailed(this, "Cannot update player in PlayerEvent.", e, packet);
|
||||||
}
|
}
|
||||||
|
@ -234,6 +234,7 @@ class Metrics {
|
|||||||
*
|
*
|
||||||
* @return True if statistics measuring is running, otherwise false.
|
* @return True if statistics measuring is running, otherwise false.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public boolean start() {
|
public boolean start() {
|
||||||
synchronized (optOutLock) {
|
synchronized (optOutLock) {
|
||||||
// Did we opt out?
|
// Did we opt out?
|
||||||
|
@ -33,11 +33,6 @@ import java.util.regex.Pattern;
|
|||||||
*/
|
*/
|
||||||
public class FuzzyReflection {
|
public class FuzzyReflection {
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches a Minecraft object.
|
|
||||||
*/
|
|
||||||
public static final String MINECRAFT_OBJECT = "net\\.minecraft(\\.\\w+)+";
|
|
||||||
|
|
||||||
// The class we're actually representing
|
// The class we're actually representing
|
||||||
private Class<?> source;
|
private Class<?> source;
|
||||||
|
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.comphenix.protocol.utility;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a dynamic package and an arbitrary number of cached classes.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
class CachedPackage {
|
||||||
|
private Map<String, Class<?>> cache;
|
||||||
|
private String packageName;
|
||||||
|
|
||||||
|
public CachedPackage(String packageName) {
|
||||||
|
this.packageName = packageName;
|
||||||
|
this.cache = Maps.newConcurrentMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the class object of a specific class in the current package.
|
||||||
|
* @param className - the specific class.
|
||||||
|
* @return Class object.
|
||||||
|
* @throws RuntimeException If we are unable to find the given class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public Class getPackageClass(String className) {
|
||||||
|
try {
|
||||||
|
Class result = cache.get(className);
|
||||||
|
|
||||||
|
// Concurrency is not a problem - we don't care if we look up a class twice
|
||||||
|
if (result == null) {
|
||||||
|
// Look up the class dynamically
|
||||||
|
result = CachedPackage.class.getClassLoader().
|
||||||
|
loadClass(packageName + "." + className);
|
||||||
|
cache.put(className, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
throw new RuntimeException("Cannot find class " + className, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,463 @@
|
|||||||
|
package com.comphenix.protocol.utility;
|
||||||
|
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Methods and constants specifically used in conjuction with reflecting Minecraft object.
|
||||||
|
*
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
public class MinecraftReflection {
|
||||||
|
/**
|
||||||
|
* Regular expression that matches a Minecraft object.
|
||||||
|
*/
|
||||||
|
public static final String MINECRAFT_OBJECT = "net\\.minecraft(\\.\\w+)+";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The package name of all the classes that belongs to the native code in Minecraft.
|
||||||
|
*/
|
||||||
|
private static String MINECRAFT_PREFIX_PACKAGE = "net.minecraft.server";
|
||||||
|
|
||||||
|
private static String MINECRAFT_FULL_PACKAGE = null;
|
||||||
|
private static String CRAFTBUKKIT_PACKAGE = null;
|
||||||
|
|
||||||
|
private static CachedPackage minecraftPackage;
|
||||||
|
private static CachedPackage craftbukkitPackage;
|
||||||
|
|
||||||
|
// org.bukkit.craftbukkit
|
||||||
|
private static Class<?> craftItemStackClass;
|
||||||
|
private static Constructor<?> craftNMSConstructor;
|
||||||
|
private static Constructor<?> craftBukkitConstructor;
|
||||||
|
|
||||||
|
// net.minecraft.server
|
||||||
|
private static Class<?> itemStackArrayClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the name of the Minecraft server package.
|
||||||
|
* @return Full canonical name of the Minecraft server package.
|
||||||
|
*/
|
||||||
|
public static String getMinecraftPackage() {
|
||||||
|
// Speed things up
|
||||||
|
if (MINECRAFT_FULL_PACKAGE != null)
|
||||||
|
return MINECRAFT_FULL_PACKAGE;
|
||||||
|
|
||||||
|
Server craftServer = Bukkit.getServer();
|
||||||
|
|
||||||
|
// This server should have a "getHandle" method that we can use
|
||||||
|
if (craftServer != null) {
|
||||||
|
try {
|
||||||
|
Class<?> craftClass = craftServer.getClass();
|
||||||
|
Method getHandle = craftClass.getMethod("getHandle");
|
||||||
|
|
||||||
|
Class<?> returnType = getHandle.getReturnType();
|
||||||
|
String returnName = returnType.getCanonicalName();
|
||||||
|
|
||||||
|
// The return type will tell us the full package, regardless of formating
|
||||||
|
CRAFTBUKKIT_PACKAGE = getPackage(craftClass.getCanonicalName());
|
||||||
|
MINECRAFT_FULL_PACKAGE = getPackage(returnName);
|
||||||
|
return MINECRAFT_FULL_PACKAGE;
|
||||||
|
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
throw new RuntimeException("Security violation. Cannot get handle method.", e);
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new IllegalStateException("Cannot find getHandle() method on server. Is this a modified CraftBukkit version?", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Could not find Bukkit. Is it running?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used during debugging and testing.
|
||||||
|
* @param minecraftPackage - the current Minecraft package.
|
||||||
|
* @param craftBukkitPackage - the current CraftBukkit package.
|
||||||
|
*/
|
||||||
|
public static void setMinecraftPackage(String minecraftPackage, String craftBukkitPackage) {
|
||||||
|
MINECRAFT_FULL_PACKAGE = minecraftPackage;
|
||||||
|
CRAFTBUKKIT_PACKAGE = craftBukkitPackage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the name of the root CraftBukkit package.
|
||||||
|
* @return Full canonical name of the root CraftBukkit package.
|
||||||
|
*/
|
||||||
|
public static String getCraftBukkitPackage() {
|
||||||
|
// Ensure it has been initialized
|
||||||
|
getMinecraftPackage();
|
||||||
|
return CRAFTBUKKIT_PACKAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the package name from a given canonical Java class name.
|
||||||
|
* @param fullName - full Java class name.
|
||||||
|
* @return The package name.
|
||||||
|
*/
|
||||||
|
private static String getPackage(String fullName) {
|
||||||
|
return fullName.substring(0, fullName.lastIndexOf("."));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a given object can be found within the package net.minecraft.server.
|
||||||
|
* @param obj - the object to test.
|
||||||
|
* @return TRUE if it can, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isMinecraftObject(@Nonnull Object obj) {
|
||||||
|
if (obj == null)
|
||||||
|
throw new IllegalArgumentException("Cannot determine the type of a null object.");
|
||||||
|
|
||||||
|
// Doesn't matter if we don't check for the version here
|
||||||
|
return obj.getClass().getName().startsWith(MINECRAFT_PREFIX_PACKAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a given object is found in net.minecraft.server, and has the given name.
|
||||||
|
* @param obj - the object to test.
|
||||||
|
* @param className - the class name to test.
|
||||||
|
* @return TRUE if it can, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isMinecraftObject(@Nonnull Object obj, String className) {
|
||||||
|
if (obj == null)
|
||||||
|
throw new IllegalArgumentException("Cannot determine the type of a null object.");
|
||||||
|
|
||||||
|
String javaName = obj.getClass().getName();
|
||||||
|
return javaName.startsWith(MINECRAFT_PREFIX_PACKAGE) && javaName.endsWith(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamically retrieve the Bukkit entity from a given entity.
|
||||||
|
* @param nmsObject - the NMS entity.
|
||||||
|
* @return A bukkit entity.
|
||||||
|
* @throws RuntimeException If we were unable to retrieve the Bukkit entity.
|
||||||
|
*/
|
||||||
|
public static Object getBukkitEntity(Object nmsObject) {
|
||||||
|
if (nmsObject == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// We will have to do this dynamically, unfortunately
|
||||||
|
try {
|
||||||
|
return nmsObject.getClass().getMethod("getBukkitEntity").invoke(nmsObject);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot get Bukkit entity from " + nmsObject, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a given object is a ChunkPosition.
|
||||||
|
* @param obj - the object to test.
|
||||||
|
* @return TRUE if it can, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isChunkPosition(Object obj) {
|
||||||
|
return getChunkPositionClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a given object is a ChunkCoordinate.
|
||||||
|
* @param obj - the object to test.
|
||||||
|
* @return TRUE if it can, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isChunkCoordinates(Object obj) {
|
||||||
|
return getChunkCoordinatesClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is actually a Minecraft packet.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isPacketClass(Object obj) {
|
||||||
|
return getPacketClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is a NetLoginHandler.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isLoginHandler(Object obj) {
|
||||||
|
return getNetLoginHandlerClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is actually a Minecraft packet.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isMinecraftEntity(Object obj) {
|
||||||
|
return getEntityClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is a NMS ItemStack.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isItemStack(Object value) {
|
||||||
|
return getItemStackClass().isAssignableFrom(value.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is a Minecraft player entity.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isMinecraftPlayer(Object obj) {
|
||||||
|
return getEntityPlayerClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is a watchable object.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isWatchableObject(Object obj) {
|
||||||
|
return getWatchableObjectClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is a data watcher object.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isDataWatcher(Object obj) {
|
||||||
|
return getDataWatcherClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the given object is a CraftItemStack instancey.
|
||||||
|
* @param obj - the given object.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static boolean isCraftItemStack(Object obj) {
|
||||||
|
return getCraftItemStackClass().isAssignableFrom(obj.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the EntityPlayer (NMS) class.
|
||||||
|
* @return The entity class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getEntityPlayerClass() {
|
||||||
|
return getMinecraftClass("EntityPlayer");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the entity (NMS) class.
|
||||||
|
* @return The entity class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getEntityClass() {
|
||||||
|
return getMinecraftClass("Entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the packet class.
|
||||||
|
* @return The packet class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getPacketClass() {
|
||||||
|
return getMinecraftClass("Packet");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the NetLoginHandler class.
|
||||||
|
* @return The NetLoginHandler class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getNetLoginHandlerClass() {
|
||||||
|
return getMinecraftClass("NetLoginHandler");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the NetLoginHandler class.
|
||||||
|
* @return The NetLoginHandler class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getItemStackClass() {
|
||||||
|
return getMinecraftClass("ItemStack");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the WorldType class.
|
||||||
|
* @return The WorldType class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getWorldTypeClass() {
|
||||||
|
return getMinecraftClass("WorldType");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the DataWatcher class.
|
||||||
|
* @return The DataWatcher class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getDataWatcherClass() {
|
||||||
|
return getMinecraftClass("DataWatcher");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the ChunkPosition class.
|
||||||
|
* @return The ChunkPosition class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getChunkPositionClass() {
|
||||||
|
return getMinecraftClass("ChunkPosition");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the ChunkPosition class.
|
||||||
|
* @return The ChunkPosition class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getChunkCoordinatesClass() {
|
||||||
|
return getMinecraftClass("ChunkCoordinates");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the WatchableObject class.
|
||||||
|
* @return The WatchableObject class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getWatchableObjectClass() {
|
||||||
|
return getMinecraftClass("WatchableObject");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the ItemStack[] class.
|
||||||
|
* @return The ItemStack[] class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getItemStackArrayClass() {
|
||||||
|
if (itemStackArrayClass == null)
|
||||||
|
itemStackArrayClass = getArrayClass(getItemStackClass());
|
||||||
|
return itemStackArrayClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the array class of a given component type.
|
||||||
|
* @param componentType - type of each element in the array.
|
||||||
|
* @return The class of the array.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getArrayClass(Class componentType) {
|
||||||
|
// Bit of a hack, but it works
|
||||||
|
return Array.newInstance(componentType, 0).getClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the CraftItemStack class.
|
||||||
|
* @return The CraftItemStack class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getCraftItemStackClass() {
|
||||||
|
if (craftItemStackClass == null)
|
||||||
|
craftItemStackClass = getCraftBukkitClass("inventory.CraftItemStack");
|
||||||
|
return craftItemStackClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a CraftItemStack from a given ItemStack.
|
||||||
|
* @param bukkitItemStack - the Bukkit ItemStack to convert.
|
||||||
|
* @return A CraftItemStack as an ItemStack.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static ItemStack getBukkitItemStack(ItemStack bukkitItemStack) {
|
||||||
|
if (craftBukkitConstructor == null) {
|
||||||
|
try {
|
||||||
|
craftBukkitConstructor = getCraftItemStackClass().getConstructor(ItemStack.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot find CraftItemStack(org.bukkit.inventory.ItemStack).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to create the CraftItemStack
|
||||||
|
try {
|
||||||
|
return (ItemStack) craftBukkitConstructor.newInstance(bukkitItemStack);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct CraftItemStack.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the Bukkit ItemStack from a given net.minecraft.server ItemStack.
|
||||||
|
* @param minecraftItemStack - the NMS ItemStack to wrap.
|
||||||
|
* @return The wrapped ItemStack.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static ItemStack getBukkitItemStack(Object minecraftItemStack) {
|
||||||
|
if (craftNMSConstructor == null) {
|
||||||
|
try {
|
||||||
|
craftNMSConstructor = getCraftItemStackClass().getConstructor(minecraftItemStack.getClass());
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot find CraftItemStack(net.mineraft.server.ItemStack).", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to create the CraftItemStack
|
||||||
|
try {
|
||||||
|
return (ItemStack) craftNMSConstructor.newInstance(minecraftItemStack);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct CraftItemStack.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the net.minecraft.server ItemStack from a Bukkit ItemStack.
|
||||||
|
* @param stack - the Bukkit ItemStack to convert.
|
||||||
|
* @return The NMS ItemStack.
|
||||||
|
*/
|
||||||
|
public static Object getMinecraftItemStack(ItemStack stack) {
|
||||||
|
// Make sure this is a CraftItemStack
|
||||||
|
if (!isCraftItemStack(stack))
|
||||||
|
stack = getBukkitItemStack(stack);
|
||||||
|
|
||||||
|
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||||
|
return unwrapper.unwrapItem(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the class object of a specific CraftBukkit class.
|
||||||
|
* @param className - the specific CraftBukkit class.
|
||||||
|
* @return Class object.
|
||||||
|
* @throws RuntimeException If we are unable to find the given class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getCraftBukkitClass(String className) {
|
||||||
|
if (craftbukkitPackage == null)
|
||||||
|
craftbukkitPackage = new CachedPackage(getCraftBukkitPackage());
|
||||||
|
return craftbukkitPackage.getPackageClass(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the class object of a specific Minecraft class.
|
||||||
|
* @param className - the specific Minecraft class.
|
||||||
|
* @return Class object.
|
||||||
|
* @throws RuntimeException If we are unable to find the given class.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static Class getMinecraftClass(String className) {
|
||||||
|
if (minecraftPackage == null)
|
||||||
|
minecraftPackage = new CachedPackage(getMinecraftPackage());
|
||||||
|
return minecraftPackage.getPackageClass(className);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,13 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import net.minecraft.server.DataWatcher;
|
|
||||||
import net.minecraft.server.WatchableObject;
|
|
||||||
|
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.WorldType;
|
import org.bukkit.WorldType;
|
||||||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
@ -19,6 +16,7 @@ import com.comphenix.protocol.ProtocolManager;
|
|||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains several useful equivalent converters for normal Bukkit types.
|
* Contains several useful equivalent converters for normal Bukkit types.
|
||||||
@ -29,9 +27,13 @@ public class BukkitConverters {
|
|||||||
// Check whether or not certain classes exists
|
// Check whether or not certain classes exists
|
||||||
private static boolean hasWorldType = false;
|
private static boolean hasWorldType = false;
|
||||||
|
|
||||||
|
// Used to access the world type
|
||||||
|
private static Method worldTypeName;
|
||||||
|
private static Method worldTypeGetType;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
Class.forName("net.minecraft.server.WorldType");
|
Class.forName(MinecraftReflection.getMinecraftPackage() + ".WorldType");
|
||||||
hasWorldType = true;
|
hasWorldType = true;
|
||||||
} catch (ClassNotFoundException e) {
|
} catch (ClassNotFoundException e) {
|
||||||
}
|
}
|
||||||
@ -100,8 +102,8 @@ public class BukkitConverters {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public WrappedWatchableObject getSpecific(Object generic) {
|
public WrappedWatchableObject getSpecific(Object generic) {
|
||||||
if (generic instanceof WatchableObject)
|
if (MinecraftReflection.isWatchableObject(generic))
|
||||||
return new WrappedWatchableObject((WatchableObject) generic);
|
return new WrappedWatchableObject(generic);
|
||||||
else if (generic instanceof WrappedWatchableObject)
|
else if (generic instanceof WrappedWatchableObject)
|
||||||
return (WrappedWatchableObject) generic;
|
return (WrappedWatchableObject) generic;
|
||||||
else
|
else
|
||||||
@ -128,8 +130,8 @@ public class BukkitConverters {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WrappedDataWatcher getSpecific(Object generic) {
|
public WrappedDataWatcher getSpecific(Object generic) {
|
||||||
if (generic instanceof DataWatcher)
|
if (MinecraftReflection.isDataWatcher(generic))
|
||||||
return new WrappedDataWatcher((DataWatcher) generic);
|
return new WrappedDataWatcher(generic);
|
||||||
else if (generic instanceof WrappedDataWatcher)
|
else if (generic instanceof WrappedDataWatcher)
|
||||||
return (WrappedDataWatcher) generic;
|
return (WrappedDataWatcher) generic;
|
||||||
else
|
else
|
||||||
@ -153,15 +155,35 @@ public class BukkitConverters {
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
return getIgnoreNull(new EquivalentConverter<WorldType>() {
|
return getIgnoreNull(new EquivalentConverter<WorldType>() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object getGeneric(Class<?> genericType, WorldType specific) {
|
public Object getGeneric(Class<?> genericType, WorldType specific) {
|
||||||
return net.minecraft.server.WorldType.getType(specific.getName());
|
try {
|
||||||
|
if (worldTypeGetType == null)
|
||||||
|
worldTypeGetType = MinecraftReflection.getWorldTypeClass().getMethod("getType", String.class);
|
||||||
|
|
||||||
|
// Convert to the Bukkit world type
|
||||||
|
return worldTypeGetType.invoke(this, specific.getName());
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new FieldAccessException("Cannot find the WorldType.getType() method.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public WorldType getSpecific(Object generic) {
|
public WorldType getSpecific(Object generic) {
|
||||||
net.minecraft.server.WorldType type = (net.minecraft.server.WorldType) generic;
|
try {
|
||||||
return WorldType.getByName(type.name());
|
if (worldTypeName == null)
|
||||||
|
worldTypeName = MinecraftReflection.getWorldTypeClass().getMethod("name");
|
||||||
|
|
||||||
|
// Dynamically call the namne method
|
||||||
|
String name = (String) worldTypeName.invoke(generic);
|
||||||
|
return WorldType.getByName(name);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new FieldAccessException("Cannot call the name method in WorldType.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -221,12 +243,12 @@ public class BukkitConverters {
|
|||||||
public static EquivalentConverter<ItemStack> getItemStackConverter() {
|
public static EquivalentConverter<ItemStack> getItemStackConverter() {
|
||||||
return getIgnoreNull(new EquivalentConverter<ItemStack>() {
|
return getIgnoreNull(new EquivalentConverter<ItemStack>() {
|
||||||
public Object getGeneric(Class<?> genericType, ItemStack specific) {
|
public Object getGeneric(Class<?> genericType, ItemStack specific) {
|
||||||
return toStackNMS(specific);
|
return MinecraftReflection.getMinecraftItemStack(specific);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ItemStack getSpecific(Object generic) {
|
public ItemStack getSpecific(Object generic) {
|
||||||
return new CraftItemStack((net.minecraft.server.ItemStack) generic);
|
return MinecraftReflection.getBukkitItemStack(generic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -236,20 +258,6 @@ public class BukkitConverters {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert an item stack to the NMS equivalent.
|
|
||||||
* @param stack - Bukkit stack to convert.
|
|
||||||
* @return A bukkit stack.
|
|
||||||
*/
|
|
||||||
private static net.minecraft.server.ItemStack toStackNMS(ItemStack stack) {
|
|
||||||
// We must be prepared for an object that simply implements ItemStcak
|
|
||||||
if (stack instanceof CraftItemStack) {
|
|
||||||
return ((CraftItemStack) stack).getHandle();
|
|
||||||
} else {
|
|
||||||
return (new CraftItemStack(stack)).getHandle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a given equivalent converter in NULL checks, ensuring that such values are ignored.
|
* Wraps a given equivalent converter in NULL checks, ensuring that such values are ignored.
|
||||||
* @param delegate - the underlying equivalent converter.
|
* @param delegate - the underlying equivalent converter.
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
import org.bukkit.util.Vector;
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,6 +22,8 @@ public class ChunkPosition {
|
|||||||
*/
|
*/
|
||||||
public static ChunkPosition ORIGIN = new ChunkPosition(0, 0, 0);
|
public static ChunkPosition ORIGIN = new ChunkPosition(0, 0, 0);
|
||||||
|
|
||||||
|
private static Constructor<?> chunkPositionConstructor;
|
||||||
|
|
||||||
// Use protected members, like Bukkit
|
// Use protected members, like Bukkit
|
||||||
protected final int x;
|
protected final int x;
|
||||||
protected final int y;
|
protected final int y;
|
||||||
@ -128,27 +133,35 @@ public class ChunkPosition {
|
|||||||
*/
|
*/
|
||||||
public static EquivalentConverter<ChunkPosition> getConverter() {
|
public static EquivalentConverter<ChunkPosition> getConverter() {
|
||||||
return new EquivalentConverter<ChunkPosition>() {
|
return new EquivalentConverter<ChunkPosition>() {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public Object getGeneric(Class<?> genericType, ChunkPosition specific) {
|
public Object getGeneric(Class<?> genericType, ChunkPosition specific) {
|
||||||
return new net.minecraft.server.ChunkPosition(specific.x, specific.y, specific.z);
|
if (chunkPositionConstructor == null) {
|
||||||
|
try {
|
||||||
|
chunkPositionConstructor = MinecraftReflection.getChunkPositionClass().
|
||||||
|
getConstructor(int.class, int.class, int.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot find chunk position constructor.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the underlying ChunkPosition
|
||||||
|
try {
|
||||||
|
return chunkPositionConstructor.newInstance(specific.x, specific.y, specific.z);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct ChunkPosition.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkPosition getSpecific(Object generic) {
|
public ChunkPosition getSpecific(Object generic) {
|
||||||
if (generic instanceof net.minecraft.server.ChunkPosition) {
|
if (MinecraftReflection.isChunkPosition(generic)) {
|
||||||
net.minecraft.server.ChunkPosition other = (net.minecraft.server.ChunkPosition) generic;
|
// Use a structure modifier
|
||||||
|
intModifier = new StructureModifier<Object>(generic.getClass(), null, false).withType(int.class);
|
||||||
try {
|
|
||||||
if (intModifier == null)
|
|
||||||
return new ChunkPosition(other.x, other.y, other.z);
|
|
||||||
} catch (LinkageError e) {
|
|
||||||
// It could happen. If it does, use a structure modifier instead
|
|
||||||
intModifier = new StructureModifier<Object>(other.getClass(), null, false).withType(int.class);
|
|
||||||
|
|
||||||
// Damn it all
|
// Damn it all
|
||||||
if (intModifier.size() < 3) {
|
if (intModifier.size() < 3) {
|
||||||
throw new IllegalStateException("Cannot read class " + other.getClass() + " for its integer fields.");
|
throw new IllegalStateException("Cannot read class " + generic.getClass() + " for its integer fields.");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (intModifier.size() >= 3) {
|
if (intModifier.size() >= 3) {
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
import net.minecraft.server.ChunkCoordinates;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows access to a chunk coordinate.
|
* Allows access to a chunk coordinate.
|
||||||
*
|
*
|
||||||
@ -16,23 +16,42 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
*/
|
*/
|
||||||
private static final boolean LARGER_THAN_NULL = true;
|
private static final boolean LARGER_THAN_NULL = true;
|
||||||
|
|
||||||
protected ChunkCoordinates handle;
|
@SuppressWarnings("rawtypes")
|
||||||
|
protected Comparable handle;
|
||||||
|
|
||||||
|
// Used to access a ChunkCoordinate
|
||||||
|
private static StructureModifier<Integer> intModifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new empty wrapper.
|
* Create a new empty wrapper.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public WrappedChunkCoordinate() {
|
public WrappedChunkCoordinate() {
|
||||||
this(new ChunkCoordinates());
|
try {
|
||||||
|
this.handle = (Comparable) MinecraftReflection.getChunkCoordinatesClass().newInstance();
|
||||||
|
initializeModifier();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct chunk coordinate.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a wrapper for a specific chunk coordinates.
|
* Create a wrapper for a specific chunk coordinates.
|
||||||
* @param handle - the NMS chunk coordinates.
|
* @param handle - the NMS chunk coordinates.
|
||||||
*/
|
*/
|
||||||
public WrappedChunkCoordinate(ChunkCoordinates handle) {
|
@SuppressWarnings("rawtypes")
|
||||||
|
public WrappedChunkCoordinate(Comparable handle) {
|
||||||
if (handle == null)
|
if (handle == null)
|
||||||
throw new IllegalArgumentException("handle cannot be NULL");
|
throw new IllegalArgumentException("handle cannot be NULL");
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
initializeModifier();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that the structure modifier is initialized
|
||||||
|
private void initializeModifier() {
|
||||||
|
if (intModifier == null) {
|
||||||
|
intModifier = new StructureModifier<Object>(handle.getClass(), null, false).withType(int.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,7 +75,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
this(position.getX(), position.getY(), position.getZ());
|
this(position.getX(), position.getY(), position.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChunkCoordinates getHandle() {
|
public Object getHandle() {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +84,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
* @return The x coordinate.
|
* @return The x coordinate.
|
||||||
*/
|
*/
|
||||||
public int getX() {
|
public int getX() {
|
||||||
return handle.x;
|
return intModifier.read(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,7 +92,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
* @param newX - the new x coordinate.
|
* @param newX - the new x coordinate.
|
||||||
*/
|
*/
|
||||||
public void setX(int newX) {
|
public void setX(int newX) {
|
||||||
handle.x = newX;
|
intModifier.write(0, newX);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,7 +100,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
* @return The y coordinate.
|
* @return The y coordinate.
|
||||||
*/
|
*/
|
||||||
public int getY() {
|
public int getY() {
|
||||||
return handle.y;
|
return intModifier.read(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -89,7 +108,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
* @param newY - the new y coordinate.
|
* @param newY - the new y coordinate.
|
||||||
*/
|
*/
|
||||||
public void setY(int newY) {
|
public void setY(int newY) {
|
||||||
handle.y = newY;
|
intModifier.write(1, newY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -97,7 +116,15 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
* @return The z coordinate.
|
* @return The z coordinate.
|
||||||
*/
|
*/
|
||||||
public int getZ() {
|
public int getZ() {
|
||||||
return handle.z;
|
return intModifier.read(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the z coordinate of the underlying coordiate.
|
||||||
|
* @param newZ - the new z coordinate.
|
||||||
|
*/
|
||||||
|
public void setZ(int newZ) {
|
||||||
|
intModifier.write(2, newZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,14 +135,7 @@ public class WrappedChunkCoordinate implements Comparable<WrappedChunkCoordinate
|
|||||||
return new ChunkPosition(getX(), getY(), getZ());
|
return new ChunkPosition(getX(), getY(), getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@SuppressWarnings("unchecked")
|
||||||
* Set the z coordinate of the underlying coordiate.
|
|
||||||
* @param newZ - the new z coordinate.
|
|
||||||
*/
|
|
||||||
public void setZ(int newZ) {
|
|
||||||
handle.z = newZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(WrappedChunkCoordinate other) {
|
public int compareTo(WrappedChunkCoordinate other) {
|
||||||
// We'll handle NULL objects too, unlike ChunkCoordinates
|
// We'll handle NULL objects too, unlike ChunkCoordinates
|
||||||
|
@ -6,6 +6,7 @@ import java.lang.reflect.Method;
|
|||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -13,6 +14,8 @@ import java.util.concurrent.locks.Lock;
|
|||||||
import java.util.concurrent.locks.ReadWriteLock;
|
import java.util.concurrent.locks.ReadWriteLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
@ -20,17 +23,17 @@ import com.comphenix.protocol.injector.BukkitUnwrapper;
|
|||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.FieldUtils;
|
import com.comphenix.protocol.reflect.FieldUtils;
|
||||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.collect.Iterators;
|
||||||
import net.minecraft.server.DataWatcher;
|
|
||||||
import net.minecraft.server.WatchableObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a DataWatcher that is used to transmit arbitrary key-value pairs with a given entity.
|
* Wraps a DataWatcher that is used to transmit arbitrary key-value pairs with a given entity.
|
||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class WrappedDataWatcher {
|
public class WrappedDataWatcher implements Iterable<WrappedWatchableObject> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to assign integer IDs to given types.
|
* Used to assign integer IDs to given types.
|
||||||
@ -55,7 +58,7 @@ public class WrappedDataWatcher {
|
|||||||
private static boolean hasInitialized;
|
private static boolean hasInitialized;
|
||||||
|
|
||||||
// The underlying DataWatcher we're modifying
|
// The underlying DataWatcher we're modifying
|
||||||
protected DataWatcher handle;
|
protected Object handle;
|
||||||
|
|
||||||
// Lock
|
// Lock
|
||||||
private ReadWriteLock readWriteLock;
|
private ReadWriteLock readWriteLock;
|
||||||
@ -69,7 +72,13 @@ public class WrappedDataWatcher {
|
|||||||
*/
|
*/
|
||||||
public WrappedDataWatcher() {
|
public WrappedDataWatcher() {
|
||||||
// Just create a new watcher
|
// Just create a new watcher
|
||||||
this(new DataWatcher());
|
try {
|
||||||
|
this.handle = MinecraftReflection.getDataWatcherClass().newInstance();
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Unable to construct DataWatcher.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,27 +86,42 @@ public class WrappedDataWatcher {
|
|||||||
* @param handle - the data watcher to wrap.
|
* @param handle - the data watcher to wrap.
|
||||||
* @throws FieldAccessException If we're unable to wrap a DataWatcher.
|
* @throws FieldAccessException If we're unable to wrap a DataWatcher.
|
||||||
*/
|
*/
|
||||||
public WrappedDataWatcher(DataWatcher handle) {
|
public WrappedDataWatcher(Object handle) {
|
||||||
this.handle = handle;
|
if (handle == null)
|
||||||
|
throw new IllegalArgumentException("Handle cannot be NULL.");
|
||||||
|
if (!MinecraftReflection.isDataWatcher(handle))
|
||||||
|
throw new IllegalArgumentException("The value " + handle + " is not a DataWatcher.");
|
||||||
|
|
||||||
try {
|
this.handle = handle;
|
||||||
initialize();
|
initialize();
|
||||||
} catch (FieldAccessException e) {
|
|
||||||
throw new RuntimeException("Cannot initialize wrapper.", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new data watcher from a list of watchable objects.
|
* Create a new data watcher for a list of watchable objects.
|
||||||
|
* <p>
|
||||||
|
* Note that the watchable objects are not cloned, and will be modified in place. Use "deepClone" if
|
||||||
|
* that is not desirable.
|
||||||
|
* <p>
|
||||||
|
* The {@link #removeObject(int)} method will not modify the given list, however.
|
||||||
|
*
|
||||||
* @param watchableObjects - list of watchable objects that will be copied.
|
* @param watchableObjects - list of watchable objects that will be copied.
|
||||||
* @throws FieldAccessException Unable to read watchable objects.
|
* @throws FieldAccessException Unable to read watchable objects.
|
||||||
*/
|
*/
|
||||||
public WrappedDataWatcher(List<WrappedWatchableObject> watchableObjects) throws FieldAccessException {
|
public WrappedDataWatcher(List<WrappedWatchableObject> watchableObjects) throws FieldAccessException {
|
||||||
this();
|
this();
|
||||||
|
|
||||||
// Fill the underlying map
|
Lock writeLock = getReadWriteLock().writeLock();
|
||||||
|
Map<Integer, Object> map = getWatchableObjectMap();
|
||||||
|
|
||||||
|
writeLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Add the watchable objects by reference
|
||||||
for (WrappedWatchableObject watched : watchableObjects) {
|
for (WrappedWatchableObject watched : watchableObjects) {
|
||||||
setObject(watched.getIndex(), watched.getValue());
|
map.put(watched.getIndex(), watched.handle);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +129,7 @@ public class WrappedDataWatcher {
|
|||||||
* Retrieves the underlying data watcher.
|
* Retrieves the underlying data watcher.
|
||||||
* @return The underlying data watcher.
|
* @return The underlying data watcher.
|
||||||
*/
|
*/
|
||||||
public DataWatcher getHandle() {
|
public Object getHandle() {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +239,7 @@ public class WrappedDataWatcher {
|
|||||||
*/
|
*/
|
||||||
public Object getObject(int index) throws FieldAccessException {
|
public Object getObject(int index) throws FieldAccessException {
|
||||||
// The get method will take care of concurrency
|
// The get method will take care of concurrency
|
||||||
WatchableObject watchable = getWatchedObject(index);
|
Object watchable = getWatchedObject(index);
|
||||||
|
|
||||||
if (watchable != null) {
|
if (watchable != null) {
|
||||||
return new WrappedWatchableObject(watchable).getValue();
|
return new WrappedWatchableObject(watchable).getValue();
|
||||||
@ -230,15 +254,16 @@ public class WrappedDataWatcher {
|
|||||||
* @throws FieldAccessException If reflection failed.
|
* @throws FieldAccessException If reflection failed.
|
||||||
*/
|
*/
|
||||||
public List<WrappedWatchableObject> getWatchableObjects() throws FieldAccessException {
|
public List<WrappedWatchableObject> getWatchableObjects() throws FieldAccessException {
|
||||||
try {
|
Lock readLock = getReadWriteLock().readLock();
|
||||||
getReadWriteLock().readLock().lock();
|
readLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
List<WrappedWatchableObject> result = new ArrayList<WrappedWatchableObject>();
|
List<WrappedWatchableObject> result = new ArrayList<WrappedWatchableObject>();
|
||||||
|
|
||||||
// Add each watchable object to the list
|
// Add each watchable object to the list
|
||||||
for (Object watchable : getWatchableObjectMap().values()) {
|
for (Object watchable : getWatchableObjectMap().values()) {
|
||||||
if (watchable != null) {
|
if (watchable != null) {
|
||||||
result.add(new WrappedWatchableObject((WatchableObject) watchable));
|
result.add(new WrappedWatchableObject(watchable));
|
||||||
} else {
|
} else {
|
||||||
result.add(null);
|
result.add(null);
|
||||||
}
|
}
|
||||||
@ -246,7 +271,7 @@ public class WrappedDataWatcher {
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
getReadWriteLock().readLock().unlock();
|
readLock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -266,6 +291,20 @@ public class WrappedDataWatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone the content of the current DataWatcher.
|
||||||
|
* @return A cloned data watcher.
|
||||||
|
*/
|
||||||
|
public WrappedDataWatcher deepClone() {
|
||||||
|
WrappedDataWatcher clone = new WrappedDataWatcher();
|
||||||
|
|
||||||
|
// Make a new copy instead
|
||||||
|
for (WrappedWatchableObject watchable : this) {
|
||||||
|
clone.setObject(watchable.getIndex(), watchable.getClonedValue());
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the number of watched objects.
|
* Retrieve the number of watched objects.
|
||||||
* @return Watched object count.
|
* @return Watched object count.
|
||||||
@ -282,6 +321,23 @@ public class WrappedDataWatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a given object from the underlying DataWatcher.
|
||||||
|
* @param index - index of the object to remove.
|
||||||
|
* @return The watchable object that was removed, or NULL If none could be found.
|
||||||
|
*/
|
||||||
|
public WrappedWatchableObject removeObject(int index) {
|
||||||
|
Lock writeLock = getReadWriteLock().writeLock();
|
||||||
|
writeLock.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Object removed = getWatchableObjectMap().remove(index);
|
||||||
|
return removed != null ? new WrappedWatchableObject(removed) : null;
|
||||||
|
} finally {
|
||||||
|
writeLock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a watched byte.
|
* Set a watched byte.
|
||||||
* @param index - index of the watched byte.
|
* @param index - index of the watched byte.
|
||||||
@ -305,7 +361,7 @@ public class WrappedDataWatcher {
|
|||||||
writeLock.lock();
|
writeLock.lock();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
WatchableObject watchable = getWatchedObject(index);
|
Object watchable = getWatchedObject(index);
|
||||||
|
|
||||||
if (watchable != null) {
|
if (watchable != null) {
|
||||||
new WrappedWatchableObject(watchable).setValue(newValue, update);
|
new WrappedWatchableObject(watchable).setValue(newValue, update);
|
||||||
@ -325,18 +381,18 @@ public class WrappedDataWatcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private WatchableObject getWatchedObject(int index) throws FieldAccessException {
|
private Object getWatchedObject(int index) throws FieldAccessException {
|
||||||
// We use the get-method first and foremost
|
// We use the get-method first and foremost
|
||||||
if (getKeyValueMethod != null) {
|
if (getKeyValueMethod != null) {
|
||||||
try {
|
try {
|
||||||
return (WatchableObject) getKeyValueMethod.invoke(handle, index);
|
return getKeyValueMethod.invoke(handle, index);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FieldAccessException("Cannot invoke get key method for index " + index, e);
|
throw new FieldAccessException("Cannot invoke get key method for index " + index, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
getReadWriteLock().readLock().lock();
|
getReadWriteLock().readLock().lock();
|
||||||
return (WatchableObject) getWatchableObjectMap().get(index);
|
return getWatchableObjectMap().get(index);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
getReadWriteLock().readLock().unlock();
|
getReadWriteLock().readLock().unlock();
|
||||||
@ -388,8 +444,8 @@ public class WrappedDataWatcher {
|
|||||||
*/
|
*/
|
||||||
public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException {
|
public static WrappedDataWatcher getEntityWatcher(Entity entity) throws FieldAccessException {
|
||||||
if (entityDataField == null)
|
if (entityDataField == null)
|
||||||
entityDataField = FuzzyReflection.fromClass(net.minecraft.server.Entity.class, true).
|
entityDataField = FuzzyReflection.fromClass(MinecraftReflection.getEntityClass(), true).
|
||||||
getFieldByType("datawatcher", DataWatcher.class);
|
getFieldByType("datawatcher", MinecraftReflection.getDataWatcherClass());
|
||||||
|
|
||||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||||
|
|
||||||
@ -397,7 +453,7 @@ public class WrappedDataWatcher {
|
|||||||
Object nsmWatcher = FieldUtils.readField(entityDataField, unwrapper.unwrapItem(entity), true);
|
Object nsmWatcher = FieldUtils.readField(entityDataField, unwrapper.unwrapItem(entity), true);
|
||||||
|
|
||||||
if (nsmWatcher != null)
|
if (nsmWatcher != null)
|
||||||
return new WrappedDataWatcher((DataWatcher) nsmWatcher);
|
return new WrappedDataWatcher(nsmWatcher);
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -417,7 +473,7 @@ public class WrappedDataWatcher {
|
|||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(DataWatcher.class, true);
|
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getDataWatcherClass(), true);
|
||||||
|
|
||||||
for (Field lookup : fuzzy.getFieldListByType(Map.class)) {
|
for (Field lookup : fuzzy.getFieldListByType(Map.class)) {
|
||||||
if (Modifier.isStatic(lookup.getModifiers())) {
|
if (Modifier.isStatic(lookup.getModifiers())) {
|
||||||
@ -476,4 +532,20 @@ public class WrappedDataWatcher {
|
|||||||
// Use fallback method
|
// Use fallback method
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<WrappedWatchableObject> iterator() {
|
||||||
|
// We'll wrap the iterator instead of creating a new list every time
|
||||||
|
return Iterators.transform(getWatchableObjectMap().values().iterator(),
|
||||||
|
new Function<Object, WrappedWatchableObject>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WrappedWatchableObject apply(@Nullable Object item) {
|
||||||
|
if (item != null)
|
||||||
|
return new WrappedWatchableObject(item);
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package com.comphenix.protocol.wrappers;
|
package com.comphenix.protocol.wrappers;
|
||||||
|
|
||||||
|
import java.lang.reflect.Constructor;
|
||||||
|
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
import net.minecraft.server.ChunkCoordinates;
|
import com.google.common.base.Objects;
|
||||||
import net.minecraft.server.ItemStack;
|
|
||||||
import net.minecraft.server.WatchableObject;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a watchable object.
|
* Represents a watchable object.
|
||||||
@ -22,7 +24,13 @@ public class WrappedWatchableObject {
|
|||||||
// The field containing the value itself
|
// The field containing the value itself
|
||||||
private static StructureModifier<Object> baseModifier;
|
private static StructureModifier<Object> baseModifier;
|
||||||
|
|
||||||
protected WatchableObject handle;
|
// Used to create new watchable objects
|
||||||
|
private static Constructor<?> watchableConstructor;
|
||||||
|
|
||||||
|
// The watchable object class type
|
||||||
|
private static Class<?> watchableObjectClass;
|
||||||
|
|
||||||
|
protected Object handle;
|
||||||
protected StructureModifier<Object> modifier;
|
protected StructureModifier<Object> modifier;
|
||||||
|
|
||||||
// Type of the stored value
|
// Type of the stored value
|
||||||
@ -32,7 +40,7 @@ public class WrappedWatchableObject {
|
|||||||
* Wrap a given raw Minecraft watchable object.
|
* Wrap a given raw Minecraft watchable object.
|
||||||
* @param handle - the raw watchable object to wrap.
|
* @param handle - the raw watchable object to wrap.
|
||||||
*/
|
*/
|
||||||
public WrappedWatchableObject(WatchableObject handle) {
|
public WrappedWatchableObject(Object handle) {
|
||||||
load(handle);
|
load(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +49,7 @@ public class WrappedWatchableObject {
|
|||||||
* @param index - the index.
|
* @param index - the index.
|
||||||
* @param value - non-null value of specific types.
|
* @param value - non-null value of specific types.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public WrappedWatchableObject(int index, Object value) {
|
public WrappedWatchableObject(int index, Object value) {
|
||||||
if (value == null)
|
if (value == null)
|
||||||
throw new IllegalArgumentException("Value cannot be NULL.");
|
throw new IllegalArgumentException("Value cannot be NULL.");
|
||||||
@ -49,24 +58,44 @@ public class WrappedWatchableObject {
|
|||||||
Integer typeID = WrappedDataWatcher.getTypeID(value.getClass());
|
Integer typeID = WrappedDataWatcher.getTypeID(value.getClass());
|
||||||
|
|
||||||
if (typeID != null) {
|
if (typeID != null) {
|
||||||
load(new WatchableObject(typeID, index, getUnwrapped(value)));
|
if (watchableConstructor == null) {
|
||||||
|
try {
|
||||||
|
watchableConstructor = MinecraftReflection.getWatchableObjectClass().
|
||||||
|
getConstructor(int.class, int.class, Object.class);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot get the WatchableObject(int, int, Object) constructor.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the object
|
||||||
|
try {
|
||||||
|
load(watchableConstructor.newInstance(typeID, index, getUnwrapped(value)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Cannot construct underlying WatchableObject.", e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Cannot watch the type " + value.getClass());
|
throw new IllegalArgumentException("Cannot watch the type " + value.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap a NMS object
|
// Wrap a NMS object
|
||||||
private void load(WatchableObject handle) {
|
private void load(Object handle) {
|
||||||
initialize();
|
initialize();
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
this.modifier = baseModifier.withTarget(handle);
|
this.modifier = baseModifier.withTarget(handle);
|
||||||
|
|
||||||
|
// Make sure the type is correct
|
||||||
|
if (!watchableObjectClass.isAssignableFrom(handle.getClass())) {
|
||||||
|
throw new ClassCastException("Cannot cast the class " + handle.getClass().getName() +
|
||||||
|
" to " + watchableObjectClass.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves the underlying watchable object.
|
* Retrieves the underlying watchable object.
|
||||||
* @return The underlying watchable object.
|
* @return The underlying watchable object.
|
||||||
*/
|
*/
|
||||||
public WatchableObject getHandle() {
|
public Object getHandle() {
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +105,8 @@ public class WrappedWatchableObject {
|
|||||||
private static void initialize() {
|
private static void initialize() {
|
||||||
if (!hasInitialized) {
|
if (!hasInitialized) {
|
||||||
hasInitialized = true;
|
hasInitialized = true;
|
||||||
baseModifier = new StructureModifier<Object>(WatchableObject.class, null, false);
|
watchableObjectClass = MinecraftReflection.getWatchableObjectClass();
|
||||||
|
baseModifier = new StructureModifier<Object>(watchableObjectClass, null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,12 +234,13 @@ public class WrappedWatchableObject {
|
|||||||
* @param value - the raw NMS object to wrap.
|
* @param value - the raw NMS object to wrap.
|
||||||
* @return The wrapped object.
|
* @return The wrapped object.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
static Object getWrapped(Object value) {
|
static Object getWrapped(Object value) {
|
||||||
// Handle the special cases
|
// Handle the special cases
|
||||||
if (value instanceof net.minecraft.server.ItemStack) {
|
if (MinecraftReflection.isItemStack(value)) {
|
||||||
return BukkitConverters.getItemStackConverter().getSpecific(value);
|
return BukkitConverters.getItemStackConverter().getSpecific(value);
|
||||||
} else if (value instanceof ChunkCoordinates) {
|
} else if (MinecraftReflection.isChunkCoordinates(value)) {
|
||||||
return new WrappedChunkCoordinate((ChunkCoordinates) value);
|
return new WrappedChunkCoordinate((Comparable) value);
|
||||||
} else {
|
} else {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -221,9 +252,9 @@ public class WrappedWatchableObject {
|
|||||||
* @return The wrapped class type.
|
* @return The wrapped class type.
|
||||||
*/
|
*/
|
||||||
static Class<?> getWrappedType(Class<?> unwrapped) {
|
static Class<?> getWrappedType(Class<?> unwrapped) {
|
||||||
if (unwrapped.equals(net.minecraft.server.ChunkPosition.class))
|
if (unwrapped.equals(MinecraftReflection.getChunkPositionClass()))
|
||||||
return ChunkPosition.class;
|
return ChunkPosition.class;
|
||||||
else if (unwrapped.equals(ChunkCoordinates.class))
|
else if (unwrapped.equals(MinecraftReflection.getChunkCoordinatesClass()))
|
||||||
return WrappedChunkCoordinate.class;
|
return WrappedChunkCoordinate.class;
|
||||||
else
|
else
|
||||||
return unwrapped;
|
return unwrapped;
|
||||||
@ -240,7 +271,7 @@ public class WrappedWatchableObject {
|
|||||||
return ((WrappedChunkCoordinate) wrapped).getHandle();
|
return ((WrappedChunkCoordinate) wrapped).getHandle();
|
||||||
else if (wrapped instanceof ItemStack)
|
else if (wrapped instanceof ItemStack)
|
||||||
return BukkitConverters.getItemStackConverter().getGeneric(
|
return BukkitConverters.getItemStackConverter().getGeneric(
|
||||||
net.minecraft.server.ItemStack.class, (org.bukkit.inventory.ItemStack) wrapped);
|
MinecraftReflection.getItemStackClass(), (ItemStack) wrapped);
|
||||||
else
|
else
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
@ -252,9 +283,9 @@ public class WrappedWatchableObject {
|
|||||||
*/
|
*/
|
||||||
static Class<?> getUnwrappedType(Class<?> wrapped) {
|
static Class<?> getUnwrappedType(Class<?> wrapped) {
|
||||||
if (wrapped.equals(ChunkPosition.class))
|
if (wrapped.equals(ChunkPosition.class))
|
||||||
return net.minecraft.server.ChunkPosition.class;
|
return MinecraftReflection.getChunkPositionClass();
|
||||||
else if (wrapped.equals(WrappedChunkCoordinate.class))
|
else if (wrapped.equals(WrappedChunkCoordinate.class))
|
||||||
return ChunkCoordinates.class;
|
return MinecraftReflection.getChunkCoordinatesClass();
|
||||||
else
|
else
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
@ -265,7 +296,8 @@ public class WrappedWatchableObject {
|
|||||||
* @throws FieldAccessException If we're unable to use reflection.
|
* @throws FieldAccessException If we're unable to use reflection.
|
||||||
*/
|
*/
|
||||||
public WrappedWatchableObject deepClone() throws FieldAccessException {
|
public WrappedWatchableObject deepClone() throws FieldAccessException {
|
||||||
WrappedWatchableObject clone = new WrappedWatchableObject(DefaultInstances.DEFAULT.getDefault(WatchableObject.class));
|
@SuppressWarnings("unchecked")
|
||||||
|
WrappedWatchableObject clone = new WrappedWatchableObject(DefaultInstances.DEFAULT.getDefault(MinecraftReflection.getWatchableObjectClass()));
|
||||||
|
|
||||||
clone.setDirtyState(getDirtyState());
|
clone.setDirtyState(getDirtyState());
|
||||||
clone.setIndex(getIndex());
|
clone.setIndex(getIndex());
|
||||||
@ -275,18 +307,48 @@ public class WrappedWatchableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper
|
// Helper
|
||||||
private Object getClonedValue() throws FieldAccessException {
|
Object getClonedValue() throws FieldAccessException {
|
||||||
Object value = getValue();
|
Object value = getValue();
|
||||||
|
|
||||||
// Only a limited set of references types are supported
|
// Only a limited set of references types are supported
|
||||||
if (value instanceof net.minecraft.server.ChunkPosition) {
|
if (MinecraftReflection.isChunkPosition(value)) {
|
||||||
EquivalentConverter<ChunkPosition> converter = ChunkPosition.getConverter();
|
EquivalentConverter<ChunkPosition> converter = ChunkPosition.getConverter();
|
||||||
return converter.getGeneric(net.minecraft.server.ChunkPosition.class, converter.getSpecific(value));
|
return converter.getGeneric(MinecraftReflection.getChunkPositionClass(), converter.getSpecific(value));
|
||||||
} else if (value instanceof ItemStack) {
|
} else if (MinecraftReflection.isItemStack(value)) {
|
||||||
return ((ItemStack) value).cloneItemStack();
|
return MinecraftReflection.getMinecraftItemStack(MinecraftReflection.getBukkitItemStack(value).clone());
|
||||||
} else {
|
} else {
|
||||||
// A string or primitive wrapper, which are all immutable.
|
// A string or primitive wrapper, which are all immutable.
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
// Quick checks
|
||||||
|
if (obj == this)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (obj instanceof WrappedWatchableObject) {
|
||||||
|
WrappedWatchableObject other = (WrappedWatchableObject) obj;
|
||||||
|
|
||||||
|
return Objects.equal(getIndex(), other.getIndex()) &&
|
||||||
|
Objects.equal(getTypeID(), other.getTypeID()) &&
|
||||||
|
Objects.equal(getValue(), other.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// No, this is not equivalent
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(getIndex(), getTypeID(), getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("[%s: %s (%s)]", getIndex(), getValue(), getType().getSimpleName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,3 +13,6 @@ global:
|
|||||||
|
|
||||||
# Automatically compile structure modifiers
|
# Automatically compile structure modifiers
|
||||||
background compiler: true
|
background compiler: true
|
||||||
|
|
||||||
|
# Disable version checking for the given Minecraft version. Backup your world first!
|
||||||
|
ignore version check:
|
@ -1,9 +1,9 @@
|
|||||||
name: ProtocolLib
|
name: ProtocolLib
|
||||||
version: 1.7.1
|
version: 1.8.0
|
||||||
description: Provides read/write access to the Minecraft protocol.
|
description: Provides read/write access to the Minecraft protocol.
|
||||||
author: Comphenix
|
author: Comphenix
|
||||||
website: http://www.comphenix.net/ProtocolLib
|
website: http://www.comphenix.net/ProtocolLib
|
||||||
|
load: startup
|
||||||
main: com.comphenix.protocol.ProtocolLibrary
|
main: com.comphenix.protocol.ProtocolLibrary
|
||||||
database: false
|
database: false
|
||||||
|
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.comphenix.protocol;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class MinecraftVersionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testComparision() {
|
||||||
|
MinecraftVersion within = new MinecraftVersion(1, 2, 5);
|
||||||
|
MinecraftVersion outside = new MinecraftVersion(1, 7, 0);
|
||||||
|
|
||||||
|
MinecraftVersion lower = new MinecraftVersion(1, 0, 0);
|
||||||
|
MinecraftVersion highest = new MinecraftVersion(1, 4, 5);
|
||||||
|
|
||||||
|
// Make sure this is valid
|
||||||
|
assertTrue(lower.compareTo(within) < 0 && within.compareTo(highest) < 0);
|
||||||
|
assertFalse(outside.compareTo(within) < 0 && outside.compareTo(highest) < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testParsing() {
|
||||||
|
assertEquals(MinecraftVersion.extractVersion("CraftBukkit R3.0 (MC: 1.4.3)"), "1.4.3");
|
||||||
|
assertEquals(MinecraftVersion.extractVersion("CraftBukkit Test Beta 1 (MC: 1.10.01 )"), "1.10.01");
|
||||||
|
assertEquals(MinecraftVersion.extractVersion("Hello (MC: 2.3.4 ) "), "2.3.4");
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +0,0 @@
|
|||||||
package com.comphenix.protocol.reflect;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import net.minecraft.server.Packet103SetSlot;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
|
||||||
|
|
||||||
public class StructureModifierTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void test() throws FieldAccessException {
|
|
||||||
|
|
||||||
Packet103SetSlot move = new Packet103SetSlot();
|
|
||||||
StructureModifier<Object> modifier = new StructureModifier<Object>(
|
|
||||||
Packet103SetSlot.class, Packet.class, true);
|
|
||||||
|
|
||||||
move.a = 1;
|
|
||||||
int value = (Integer) modifier.withTarget(move).withType(int.class).read(0);
|
|
||||||
|
|
||||||
assertEquals(1, value);
|
|
||||||
}
|
|
||||||
}
|
|
In neuem Issue referenzieren
Einen Benutzer sperren