Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c3127dee1 | ||
|
|
5ec87c9d76 | ||
|
|
2205ce639e | ||
|
|
2844d75607 | ||
|
|
a6810ea874 | ||
|
|
aaf1af8e41 | ||
|
|
b8dd43aeed | ||
|
|
e959efc5af | ||
|
|
73ce01bbde | ||
|
|
b30628f6db | ||
|
|
9289825d87 | ||
|
|
57cfbc4f81 | ||
|
|
3ab2026d62 | ||
|
|
e439c778a6 | ||
|
|
98413c917e | ||
|
|
540a5e53c4 | ||
|
|
27047f83a5 | ||
|
|
222b535c15 | ||
|
|
3f31af6b70 | ||
|
|
b6a054b766 | ||
|
|
3b7b692e80 | ||
|
|
c6788addeb | ||
|
|
5b38bc7f38 | ||
|
|
33bb12713d | ||
|
|
d175a7655e | ||
|
|
4afb38aae1 | ||
|
|
36b5670b3d | ||
|
|
7b61796506 | ||
|
|
684b687e42 | ||
|
|
7a9b9afe2e | ||
|
|
7d382279ad | ||
|
|
b4f5f18283 | ||
|
|
17e150393a | ||
|
|
b5ecfb9c5f | ||
|
|
31a0c9b10c | ||
|
|
e4d95e09cf | ||
|
|
d173be0db5 | ||
|
|
051989a396 | ||
|
|
795c77e943 | ||
|
|
1de6bbc9dc | ||
|
|
474c74b1f9 | ||
|
|
caaa57c915 | ||
|
|
588f736348 | ||
|
|
828302150a | ||
|
|
144723af18 | ||
|
|
087913ab3a | ||
|
|
64942cbb5e | ||
|
|
97430a8e42 | ||
|
|
1bdd200794 | ||
|
|
679035c3bf | ||
|
|
bd4352f041 | ||
|
|
05ffeb8e7f | ||
|
|
6c982a83f0 | ||
|
|
9860fbaec6 | ||
|
|
26c29d9c85 | ||
|
|
242b25eb1e | ||
|
|
c13b8d4fc6 | ||
|
|
12e9c08a1a | ||
|
|
98a0528806 | ||
|
|
015a6067fd | ||
|
|
e34105e754 | ||
|
|
a995866d5b | ||
|
|
a88347dfe6 | ||
|
|
4f404a41c6 | ||
|
|
88444dcf74 | ||
|
|
4f5ab9eb8c | ||
|
|
f51427b63c | ||
|
|
cdcb6a6007 |
No files matched your search
@@ -47,7 +47,7 @@ You can also add ProtocolLib as a Maven dependency:
|
||||
<url>http://repo.dmulloy2.net/content/groups/public/</url>
|
||||
</repository>
|
||||
...
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
|
||||
+11
-4
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ProtocolLib-API</artifactId>
|
||||
<name>ProtocolLib-API</name>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
<version>4.2.1</version>
|
||||
|
||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||
<url>http://www.spigotmc.org/resources/protocollib.1997/</url>
|
||||
@@ -19,6 +19,7 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.number></project.build.number>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -54,7 +55,7 @@
|
||||
<manifestEntries>
|
||||
<Main-Class>com.comphenix.protocol.Application</Main-Class>
|
||||
<Implementation-Title>ProtocolLib</Implementation-Title>
|
||||
<Implementation-Version>${project.version}${project.build.number}</Implementation-Version>
|
||||
<Implementation-Version>${project.fullVersion}</Implementation-Version>
|
||||
<Implementation-Vendor>dmulloy2</Implementation-Vendor>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
@@ -88,6 +89,7 @@
|
||||
</activation>
|
||||
<properties>
|
||||
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
|
||||
<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
@@ -99,6 +101,9 @@
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -129,6 +134,7 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- TODO: Look into signing releases
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
@@ -143,6 +149,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
@@ -196,13 +203,13 @@
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.9.4-R0.1-SNAPSHOT</version>
|
||||
<version>1.11.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.9.4-R0.1-SNAPSHOT</version>
|
||||
<version>1.11.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
@@ -31,7 +32,7 @@ import com.google.common.util.concurrent.Futures;
|
||||
* Note that vanilla Minecraft reuses packet IDs per protocol (ping, game, login) and IDs are subject to change, so they are not reliable.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
public class PacketType implements Serializable, Cloneable, Comparable<PacketType> {
|
||||
// Increment whenever the type changes
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@@ -175,38 +176,68 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
public static final PacketType SPAWN_POSITION = new PacketType(PROTOCOL, SENDER, 0x43, 0x05, "SpawnPosition");
|
||||
public static final PacketType UPDATE_TIME = new PacketType(PROTOCOL, SENDER, 0x44, 0x03, "UpdateTime");
|
||||
public static final PacketType TITLE = new PacketType(PROTOCOL, SENDER, 0x45, 0x45, "Title");
|
||||
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x47, 0x29, "NamedSoundEffect");
|
||||
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x48, 0x47, "PlayerListHeaderFooter");
|
||||
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x49, 0x0D, "Collect");
|
||||
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x4A, 0x18, "EntityTeleport");
|
||||
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x4B, 0x20, "UpdateAttributes");
|
||||
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x4C, 0x1D, "EntityEffect");
|
||||
public static final PacketType NAMED_SOUND_EFFECT = new PacketType(PROTOCOL, SENDER, 0x46, 0x47, "NamedSoundEffect");
|
||||
public static final PacketType PLAYER_LIST_HEADER_FOOTER = new PacketType(PROTOCOL, SENDER, 0x47, 0x48, "PlayerListHeaderFooter");
|
||||
public static final PacketType COLLECT = new PacketType(PROTOCOL, SENDER, 0x48, 0x49, "Collect");
|
||||
public static final PacketType ENTITY_TELEPORT = new PacketType(PROTOCOL, SENDER, 0x49, 0x4A, "EntityTeleport");
|
||||
public static final PacketType UPDATE_ATTRIBUTES = new PacketType(PROTOCOL, SENDER, 0x4A, 0x4B, "UpdateAttributes");
|
||||
public static final PacketType ENTITY_EFFECT = new PacketType(PROTOCOL, SENDER, 0x4B, 0x4C, "EntityEffect");
|
||||
|
||||
// ---- Removed in 1.9
|
||||
|
||||
/**
|
||||
* @deprecated Replaced by {@link WINDOW_DATA}
|
||||
* @deprecated Removed in 1.9
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType CRAFT_PROGRESS_BAR = WINDOW_DATA;
|
||||
public static final PacketType MAP_CHUNK_BULK = new PacketType(PROTOCOL, SENDER, 255, 255, "MapChunkBulk").deprecatedIn(MinecraftVersion.COMBAT_UPDATE);
|
||||
|
||||
/**
|
||||
* @deprecated Replaced by {@link REL_ENTITY_MOVE_LOOK}
|
||||
* @deprecated Removed in 1.9
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType ENTITY_MOVE_LOOK = REL_ENTITY_MOVE_LOOK;
|
||||
public static final PacketType SET_COMPRESSION = new PacketType(PROTOCOL, SENDER, 254, 254, "SetCompression").deprecatedIn(MinecraftVersion.COMBAT_UPDATE);
|
||||
|
||||
/**
|
||||
* @deprecated Replaced by {@link STATISTIC}
|
||||
* @deprecated Removed in 1.9
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType STATISTICS = STATISTIC;
|
||||
public static final PacketType UPDATE_ENTITY_NBT = new PacketType(PROTOCOL, SENDER, 253, 253, "UpdateEntityNBT").deprecatedIn(MinecraftVersion.COMBAT_UPDATE);
|
||||
|
||||
// ----- Renamed packets
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link WINDOW_DATA}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType CRAFT_PROGRESS_BAR = WINDOW_DATA.deprecated();
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link REL_ENTITY_MOVE_LOOK}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType ENTITY_MOVE_LOOK = REL_ENTITY_MOVE_LOOK.deprecated();
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link STATISTIC}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType STATISTICS = STATISTIC.deprecated();
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link OPEN_SIGN_EDITOR}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType OPEN_SIGN_ENTITY = OPEN_SIGN_EDITOR.deprecated();
|
||||
|
||||
// ----- Replaced in 1.9.4
|
||||
|
||||
/**
|
||||
* @deprecated Replaced by {@link TILE_ENTITY_DATA}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType UPDATE_SIGN = TILE_ENTITY_DATA;
|
||||
public static final PacketType UPDATE_SIGN = MinecraftReflection.signUpdateExists() ? new PacketType(PROTOCOL, SENDER, 252, 252, "UpdateSign") :
|
||||
TILE_ENTITY_DATA.deprecated();
|
||||
|
||||
// The instance must
|
||||
private final static Server INSTANCE = new Server();
|
||||
|
||||
// Prevent accidental construction
|
||||
@@ -297,7 +328,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
* @deprecated Replaced by {@link SERVER_INFO}
|
||||
*/
|
||||
@Deprecated
|
||||
public static final PacketType OUT_SERVER_INFO = SERVER_INFO;
|
||||
public static final PacketType OUT_SERVER_INFO = SERVER_INFO.deprecated();
|
||||
|
||||
private final static Server INSTANCE = new Server();
|
||||
|
||||
@@ -512,7 +543,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
}
|
||||
|
||||
public String getPacketName() {
|
||||
return WordUtils.capitalize(name().toLowerCase());
|
||||
return WordUtils.capitalize(name().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -551,7 +582,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
/**
|
||||
* Protocol version of all the current IDs.
|
||||
*/
|
||||
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.BOUNTIFUL_UPDATE;
|
||||
private static final MinecraftVersion PROTOCOL_VERSION = MinecraftVersion.EXPLORATION_UPDATE;
|
||||
|
||||
private final Protocol protocol;
|
||||
private final Sender sender;
|
||||
@@ -562,6 +593,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
|
||||
private boolean forceAsync;
|
||||
private boolean dynamic;
|
||||
private boolean deprecated;
|
||||
|
||||
/**
|
||||
* Retrieve the current packet/legacy lookup.
|
||||
@@ -683,11 +715,11 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
}
|
||||
}
|
||||
|
||||
private static String format(Protocol protocol, Sender sender, String name) {
|
||||
public static String format(Protocol protocol, Sender sender, String name) {
|
||||
if (name.contains("Packet"))
|
||||
return name;
|
||||
|
||||
return String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), name);
|
||||
return String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), WordUtils.capitalize(name));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -765,24 +797,11 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
Map<String, PacketType> map = lookup.getMap(protocol, sender);
|
||||
|
||||
// Check the map first
|
||||
String className = packetClass.getSimpleName();
|
||||
PacketType type = map.get(className);
|
||||
String clazz = packetClass.getSimpleName();
|
||||
PacketType type = find(map, clazz);
|
||||
if (type == null) {
|
||||
// Then check any aliases
|
||||
for (PacketType check : map.values()) {
|
||||
String[] aliases = check.getClassNames();
|
||||
if (aliases.length > 1) {
|
||||
for (String alias : aliases) {
|
||||
if (alias.equals(className)) {
|
||||
// We have a match!
|
||||
type = check;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Guess we don't support this packet :/
|
||||
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, className);
|
||||
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, clazz);
|
||||
type.dynamic = true;
|
||||
|
||||
// Many may be scheduled, but only the first will be executed
|
||||
@@ -792,6 +811,28 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
return type;
|
||||
}
|
||||
|
||||
private static PacketType find(Map<String, PacketType> map, String clazz) {
|
||||
PacketType ret = map.get(clazz);
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Check any aliases
|
||||
for (PacketType check : map.values()) {
|
||||
String[] aliases = check.getClassNames();
|
||||
if (aliases.length > 1) {
|
||||
for (String alias : aliases) {
|
||||
if (alias.equals(clazz)) {
|
||||
// We have a match!
|
||||
return check;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup a packet type from a packet class.
|
||||
* @param packetClass - the packet class.
|
||||
@@ -1043,6 +1084,24 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
return forceAsync;
|
||||
}
|
||||
|
||||
private PacketType deprecatedIn(MinecraftVersion version) {
|
||||
try {
|
||||
return MinecraftVersion.getCurrentVersion().isAtLeast(version) ? deprecated() : this;
|
||||
} catch (Throwable ex) {
|
||||
return deprecated();
|
||||
}
|
||||
}
|
||||
|
||||
private PacketType deprecated() {
|
||||
PacketType ret = clone();
|
||||
ret.deprecated = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public boolean isDeprecated() {
|
||||
return deprecated;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(protocol, sender, currentId, legacyId);
|
||||
@@ -1078,8 +1137,17 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
||||
Class<?> clazz = getPacketClass();
|
||||
|
||||
if (clazz == null)
|
||||
return "UNREGISTERED[" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + ", classNames: " + Arrays.toString(classNames) + "]";
|
||||
return name() + "[" + protocol + ", " + sender + ", " + currentId + ", legacy: " + legacyId + ", classNames: " + Arrays.toString(classNames) + " (unregistered)]";
|
||||
else
|
||||
return clazz.getSimpleName() + "[" + currentId + ", legacy: " + legacyId + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public PacketType clone() {
|
||||
try {
|
||||
return (PacketType) super.clone();
|
||||
} catch (CloneNotSupportedException ex) {
|
||||
throw new Error("This shouldn't happen", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.bukkit.configuration.Configuration;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
@@ -464,7 +465,7 @@ public class ProtocolConfig {
|
||||
PlayerInjectHooks hook = getDefaultMethod();
|
||||
|
||||
if (text != null)
|
||||
hook = PlayerInjectHooks.valueOf(text.toUpperCase().replace(" ", "_"));
|
||||
hook = PlayerInjectHooks.valueOf(text.toUpperCase(Locale.ENGLISH).replace(" ", "_"));
|
||||
return hook;
|
||||
}
|
||||
|
||||
|
||||
@@ -34,17 +34,17 @@ public class ProtocolLibrary {
|
||||
/**
|
||||
* The minimum version ProtocolLib has been tested with.
|
||||
*/
|
||||
public static final String MINIMUM_MINECRAFT_VERSION = "1.9";
|
||||
public static final String MINIMUM_MINECRAFT_VERSION = "1.8";
|
||||
|
||||
/**
|
||||
* The maximum version ProtocolLib has been tested with.
|
||||
*/
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.9.4";
|
||||
public static final String MAXIMUM_MINECRAFT_VERSION = "1.11.2";
|
||||
|
||||
/**
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.9.4) was released.
|
||||
* The date (with ISO 8601 or YYYY-MM-DD) when the most recent version (1.11) was released.
|
||||
*/
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2016-05-10";
|
||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2016-12-21";
|
||||
|
||||
/**
|
||||
* Plugins that are currently incompatible with ProtocolLib.
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
|
||||
package com.comphenix.protocol.events;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
@@ -36,6 +33,7 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
@@ -80,6 +78,7 @@ import com.comphenix.protocol.wrappers.EnumWrappers.ChatVisibility;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.ClientCommand;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.CombatEventType;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Difficulty;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EnumConverter;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||
@@ -105,11 +104,16 @@ import com.comphenix.protocol.wrappers.WrappedServerPing;
|
||||
import com.comphenix.protocol.wrappers.WrappedStatistic;
|
||||
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtBase;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.UnpooledByteBufAllocator;
|
||||
|
||||
/**
|
||||
* Represents a Minecraft packet indirectly.
|
||||
*
|
||||
@@ -330,7 +334,15 @@ public class PacketContainer implements Serializable {
|
||||
public StructureModifier<String> getStrings() {
|
||||
return structureModifier.withType(String.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every UUID field.
|
||||
* @return A modifier for every UUID field.
|
||||
*/
|
||||
public StructureModifier<UUID> getUUIDs() {
|
||||
return structureModifier.withType(UUID.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for every String array field.
|
||||
* @return A modifier for every String array field.
|
||||
@@ -366,7 +378,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for ItemStack.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the Bukkit ItemStack and the
|
||||
* This modifier will automatically marshal between the Bukkit ItemStack and the
|
||||
* internal Minecraft ItemStack.
|
||||
* @return A modifier for ItemStack fields.
|
||||
*/
|
||||
@@ -379,7 +391,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for arrays of ItemStacks.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the Bukkit ItemStack and the
|
||||
* This modifier will automatically marshal between the Bukkit ItemStack and the
|
||||
* internal Minecraft ItemStack.
|
||||
* @return A modifier for ItemStack array fields.
|
||||
*/
|
||||
@@ -389,7 +401,25 @@ public class PacketContainer implements Serializable {
|
||||
MinecraftReflection.getItemStackArrayClass(),
|
||||
BukkitConverters.getIgnoreNull(new ItemStackArrayConverter()));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for lists of ItemStacks.
|
||||
* <p>
|
||||
* This modifier will automatically marshal between the Bukkit ItemStack and the
|
||||
* internal Minecraft ItemStack.
|
||||
* @return A modifier for ItemStack list fields.
|
||||
*/
|
||||
public StructureModifier<List<ItemStack>> getItemListModifier() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.withType(
|
||||
List.class,
|
||||
BukkitConverters.getListConverter(
|
||||
MinecraftReflection.getItemStackClass(),
|
||||
BukkitConverters.getItemStackConverter()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for maps of statistics.
|
||||
* <p>
|
||||
@@ -408,7 +438,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for the world type enum.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the Bukkit world type and the
|
||||
* This modifier will automatically marshal between the Bukkit world type and the
|
||||
* internal Minecraft world type.
|
||||
* @return A modifier for world type fields.
|
||||
*/
|
||||
@@ -508,6 +538,21 @@ public class PacketContainer implements Serializable {
|
||||
BukkitConverters.getNbtConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for lists of NBT classes.
|
||||
* @return A modifier for lists of NBT classes.
|
||||
*/
|
||||
public StructureModifier<List<NbtBase<?>>> getListNbtModifier() {
|
||||
// Convert to and from the ProtocolLib wrapper
|
||||
return structureModifier.withType(
|
||||
Collection.class,
|
||||
BukkitConverters.getListConverter(
|
||||
MinecraftReflection.getNBTBaseClass(),
|
||||
BukkitConverters.getNbtConverter()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a read/write structure for Vectors.
|
||||
* @return A modifier for Vectors.
|
||||
@@ -522,7 +567,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of attribute snapshots.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the visible ProtocolLib WrappedAttribute and the
|
||||
* This modifier will automatically marshal between the visible ProtocolLib WrappedAttribute and the
|
||||
* internal Minecraft AttributeSnapshot.
|
||||
* @return A modifier for AttributeSnapshot collection fields.
|
||||
*/
|
||||
@@ -539,7 +584,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of chunk positions.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the visible ProtocolLib ChunkPosition and the
|
||||
* This modifier will automatically marshal between the visible ProtocolLib ChunkPosition and the
|
||||
* internal Minecraft ChunkPosition.
|
||||
*
|
||||
* @return A modifier for ChunkPosition list fields.
|
||||
@@ -557,7 +602,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of chunk positions.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the visible ProtocolLib BlockPosition and the
|
||||
* This modifier will automatically marshal between the visible ProtocolLib BlockPosition and the
|
||||
* internal Minecraft BlockPosition.
|
||||
*
|
||||
* @return A modifier for ChunkPosition list fields.
|
||||
@@ -575,7 +620,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for collections of watchable objects.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between the visible WrappedWatchableObject and the
|
||||
* This modifier will automatically marshal between the visible WrappedWatchableObject and the
|
||||
* internal Minecraft WatchableObject.
|
||||
* @return A modifier for watchable object list fields.
|
||||
*/
|
||||
@@ -592,7 +637,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for block fields.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between Material and the
|
||||
* This modifier will automatically marshal between Material and the
|
||||
* internal Minecraft Block.
|
||||
* @return A modifier for GameProfile fields.
|
||||
*/
|
||||
@@ -605,7 +650,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for game profiles in Minecraft 1.7.2.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between WrappedGameProfile and the
|
||||
* This modifier will automatically marshal between WrappedGameProfile and the
|
||||
* internal Minecraft GameProfile.
|
||||
* @return A modifier for GameProfile fields.
|
||||
*/
|
||||
@@ -618,7 +663,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for BlockData in Minecraft 1.8.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between WrappedBlockData and the
|
||||
* This modifier will automatically marshal between WrappedBlockData and the
|
||||
* internal Minecraft IBlockData.
|
||||
* @return A modifier for BlockData fields.
|
||||
*/
|
||||
@@ -631,7 +676,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for MultiBlockChangeInfo arrays in Minecraft 1.8.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between MultiBlockChangeInfo and the
|
||||
* This modifier will automatically marshal between MultiBlockChangeInfo and the
|
||||
* internal Minecraft MultiBlockChangeInfo.
|
||||
* @return A modifier for BlockData fields.
|
||||
*/
|
||||
@@ -646,7 +691,7 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for chat components in Minecraft 1.7.2.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between WrappedChatComponent and the
|
||||
* This modifier will automatically marshal between WrappedChatComponent and the
|
||||
* internal Minecraft IChatBaseComponent.
|
||||
* @return A modifier for ChatComponent fields.
|
||||
*/
|
||||
@@ -659,15 +704,19 @@ public class PacketContainer implements Serializable {
|
||||
/**
|
||||
* Retrieves a read/write structure for arrays of chat components.
|
||||
* <p>
|
||||
* This modifier will automatically marshall between WrappedChatComponent and the
|
||||
* internal Minecraft IChatBaseComponent.
|
||||
* This modifier will automatically marshal between WrappedChatComponent and the
|
||||
* internal Minecraft IChatBaseComponent (1.9.2 and below) or the internal
|
||||
* NBTCompound (1.9.4 and up).
|
||||
* <p>
|
||||
* Note that in 1.9.4 and up this modifier only works properly with sign
|
||||
* tile entities.
|
||||
* @return A modifier for ChatComponent array fields.
|
||||
*/
|
||||
public StructureModifier<WrappedChatComponent[]> getChatComponentArrays() {
|
||||
// Convert to and from the Bukkit wrapper
|
||||
return structureModifier.<WrappedChatComponent[]>withType(
|
||||
MinecraftReflection.getIChatBaseComponentArrayClass(),
|
||||
BukkitConverters.getIgnoreNull(new WrappedChatComponentArrayConverter()));
|
||||
ComponentArrayConverter.getGenericType(),
|
||||
BukkitConverters.getIgnoreNull(new ComponentArrayConverter()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -881,7 +930,7 @@ public class PacketContainer implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive a read/write structure for the ItemSlot enum in 1.9.
|
||||
* Retrieve a read/write structure for the ItemSlot enum in 1.9.
|
||||
* @return A modifier for ItemSlot enum fields.
|
||||
*/
|
||||
public StructureModifier<ItemSlot> getItemSlots() {
|
||||
@@ -890,7 +939,7 @@ public class PacketContainer implements Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive a read/write structure for the Hand enum in 1.9.
|
||||
* Retrieve a read/write structure for the Hand enum in 1.9.
|
||||
* @return A modifier for Hand enum fields.
|
||||
*/
|
||||
public StructureModifier<Hand> getHands() {
|
||||
@@ -898,6 +947,15 @@ public class PacketContainer implements Serializable {
|
||||
EnumWrappers.getHandClass(), EnumWrappers.getHandConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the Direction enum in 1.10.
|
||||
* @return A modifier for Direction enum fields.
|
||||
*/
|
||||
public StructureModifier<Direction> getDirections() {
|
||||
return structureModifier.<Direction>withType(
|
||||
EnumWrappers.getDirectionClass(), EnumWrappers.getDirectionConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for an enum. This allows for the use of
|
||||
* user-created enums that may not exist in ProtocolLib. The specific (user
|
||||
@@ -923,7 +981,7 @@ public class PacketContainer implements Serializable {
|
||||
*/
|
||||
public <T extends Enum<T>> StructureModifier<T> getEnumModifier(Class<T> enumClass, int index) {
|
||||
return getEnumModifier(enumClass, structureModifier.getField(index).getType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the ID of this packet.
|
||||
@@ -1076,7 +1134,7 @@ public class PacketContainer implements Serializable {
|
||||
* Construct a new packet data serializer.
|
||||
* @return The packet data serializer.
|
||||
*/
|
||||
private ByteBuf createPacketBuffer() {
|
||||
public static ByteBuf createPacketBuffer() {
|
||||
ByteBuf buffer = UnpooledByteBufAllocator.DEFAULT.buffer();
|
||||
Class<?> packetSerializer = MinecraftReflection.getPacketDataSerializerClass();
|
||||
|
||||
@@ -1224,11 +1282,11 @@ public class PacketContainer implements Serializable {
|
||||
* Represents an equivalent converter for ChatComponent arrays.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
private static class WrappedChatComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||
private static class LegacyComponentConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||
final EquivalentConverter<WrappedChatComponent> componentConverter = BukkitConverters.getWrappedChatComponentConverter();
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Class<?>genericType, WrappedChatComponent[] specific) {
|
||||
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
|
||||
Class<?> nmsComponent = MinecraftReflection.getIChatBaseComponentClass();
|
||||
Object[] result = (Object[]) Array.newInstance(nmsComponent, specific.length);
|
||||
|
||||
@@ -1257,6 +1315,93 @@ public class PacketContainer implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from NBT to WrappedChatComponent arrays
|
||||
* @author dmulloy2
|
||||
*/
|
||||
private static class NBTComponentConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||
private EquivalentConverter<NbtBase<?>> nbtConverter = BukkitConverters.getNbtConverter();
|
||||
private final int lines = 4;
|
||||
|
||||
@Override
|
||||
public WrappedChatComponent[] getSpecific(Object generic) {
|
||||
NbtBase<?> nbtBase = nbtConverter.getSpecific(generic);
|
||||
NbtCompound compound = (NbtCompound) nbtBase;
|
||||
|
||||
WrappedChatComponent[] components = new WrappedChatComponent[lines];
|
||||
for (int i = 0; i < lines; i++) {
|
||||
if (compound.containsKey("Text" + (i + 1))) {
|
||||
components[i] = WrappedChatComponent.fromJson(compound.getString("Text" + (i + 1)));
|
||||
} else {
|
||||
components[i] = WrappedChatComponent.fromText("");
|
||||
}
|
||||
}
|
||||
|
||||
return components;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
|
||||
NbtCompound compound = NbtFactory.ofCompound("");
|
||||
|
||||
for (int i = 0; i < lines; i++) {
|
||||
WrappedChatComponent component;
|
||||
if (i < specific.length && specific[i] != null) {
|
||||
component = specific[i];
|
||||
} else {
|
||||
component = WrappedChatComponent.fromText("");
|
||||
}
|
||||
|
||||
compound.put("Text" + (i + 1), component.getJson());
|
||||
}
|
||||
|
||||
return nbtConverter.getGeneric(genericType, compound);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedChatComponent[]> getSpecificType() {
|
||||
return WrappedChatComponent[].class;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A delegated converter that supports NBT to Component Array and regular Component Array
|
||||
* @author dmulloy2
|
||||
*/
|
||||
private static class ComponentArrayConverter implements EquivalentConverter<WrappedChatComponent[]> {
|
||||
private static final EquivalentConverter<WrappedChatComponent[]> DELEGATE;
|
||||
static {
|
||||
if (!PacketType.Play.Server.UPDATE_SIGN.isDeprecated()) {
|
||||
DELEGATE = new LegacyComponentConverter();
|
||||
} else {
|
||||
DELEGATE = new NBTComponentConverter();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedChatComponent[] getSpecific(Object generic) {
|
||||
return DELEGATE.getSpecific(generic);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Class<?> genericType, WrappedChatComponent[] specific) {
|
||||
return DELEGATE.getGeneric(genericType, specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WrappedChatComponent[]> getSpecificType() {
|
||||
return DELEGATE.getSpecificType();
|
||||
}
|
||||
|
||||
public static Class<?> getGenericType() {
|
||||
if (DELEGATE instanceof NBTComponentConverter) {
|
||||
return MinecraftReflection.getNBTCompoundClass();
|
||||
} else {
|
||||
return MinecraftReflection.getIChatBaseComponentArrayClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PacketContainer[type=" + type + ", structureModifier=" + structureModifier + "]";
|
||||
|
||||
@@ -24,6 +24,9 @@ import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.error.ErrorReporter;
|
||||
import com.comphenix.protocol.error.Report;
|
||||
@@ -31,6 +34,7 @@ import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.PacketConstructor.Unwrapper;
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.instances.DefaultInstances;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.primitives.Primitives;
|
||||
|
||||
/**
|
||||
@@ -182,20 +186,55 @@ public class BukkitUnwrapper implements Unwrapper {
|
||||
Report.newBuilder(REPORT_SECURITY_LIMITATION).error(e).callerParam(type)
|
||||
);
|
||||
} catch (NoSuchMethodException e) {
|
||||
// Maybe it's a proxy?
|
||||
Unwrapper proxyUnwrapper = getProxyUnwrapper(type);
|
||||
if (proxyUnwrapper != null)
|
||||
return proxyUnwrapper;
|
||||
|
||||
// Try getting the field unwrapper too
|
||||
Unwrapper fieldUnwrapper = getFieldUnwrapper(type);
|
||||
|
||||
if (fieldUnwrapper != null)
|
||||
return fieldUnwrapper;
|
||||
else
|
||||
reporter.reportDetailed(this,
|
||||
Report.newBuilder(REPORT_CANNOT_FIND_UNWRAP_METHOD).error(e).callerParam(type));
|
||||
}
|
||||
|
||||
|
||||
// Default method
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Players should /always/ be able to be unwrapped
|
||||
// We should only get here if the 'Player' is a proxy
|
||||
private Unwrapper getProxyUnwrapper(final Class<?> type) {
|
||||
try {
|
||||
if (Player.class.isAssignableFrom(type)) {
|
||||
final Method getHandle = MinecraftReflection.getCraftPlayerClass().getMethod("getHandle");
|
||||
|
||||
Unwrapper unwrapper = new Unwrapper() {
|
||||
@Override
|
||||
public Object unwrapItem(Object wrapped) {
|
||||
try {
|
||||
return getHandle.invoke(((Player) wrapped).getPlayer());
|
||||
} catch (Throwable ex) {
|
||||
try {
|
||||
return getHandle.invoke(Bukkit.getPlayer(((Player) wrapped).getUniqueId()));
|
||||
} catch (ReflectiveOperationException ex1) {
|
||||
throw new RuntimeException("Failed to unwrap proxy " + wrapped, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
unwrapperCache.put(type, unwrapper);
|
||||
return unwrapper;
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a cached unwrapper using the handle field.
|
||||
* @param type - a cached field unwrapper.
|
||||
|
||||
@@ -16,31 +16,216 @@
|
||||
*/
|
||||
package com.comphenix.protocol.injector.netty;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
/**
|
||||
* A packet represented only by its id and bytes.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public class WirePacket {
|
||||
private final int id;
|
||||
private final byte[] bytes;
|
||||
|
||||
/**
|
||||
* Constructs a new WirePacket with a given type and contents
|
||||
* @param type Type of the packet
|
||||
* @param bytes Contents of the packet
|
||||
*/
|
||||
public WirePacket(PacketType type, byte[] bytes) {
|
||||
this.id = checkNotNull(type, "type cannot be null").getCurrentId();
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new WirePacket with a given id and contents
|
||||
* @param id ID of the packet
|
||||
* @param bytes Contents of the packet
|
||||
*/
|
||||
public WirePacket(int id, byte[] bytes) {
|
||||
this.id = id;
|
||||
this.bytes = bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this packet's ID
|
||||
* @return The ID
|
||||
*/
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this packet's contents as a byte array
|
||||
* @return The contents
|
||||
*/
|
||||
public byte[] getBytes() {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the id of this packet to a given output
|
||||
* @param output Output to write to
|
||||
*/
|
||||
public void writeId(ByteBuf output) {
|
||||
int i = id;
|
||||
writeVarInt(output, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the contents of this packet to a given output
|
||||
* @param output Output to write to
|
||||
*/
|
||||
public void writeBytes(ByteBuf output) {
|
||||
checkNotNull(output, "output cannot be null!");
|
||||
output.writeBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully writes the ID and contents of this packet to a given output
|
||||
* @param output Output to write to
|
||||
*/
|
||||
public void writeFully(ByteBuf output) {
|
||||
writeId(output);
|
||||
writeBytes(output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes this packet into a byte buffer
|
||||
* @return The buffer
|
||||
*/
|
||||
public ByteBuf serialize() {
|
||||
ByteBuf buffer = Unpooled.buffer();
|
||||
writeFully(buffer);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
||||
if (obj instanceof WirePacket) {
|
||||
WirePacket that = (WirePacket) obj;
|
||||
return this.id == that.id &&
|
||||
Arrays.equals(this.bytes, that.bytes);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(bytes);
|
||||
result = prime * result + id;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WirePacket[id=" + id + ", bytes=" + Arrays.toString(bytes) + "]";
|
||||
}
|
||||
|
||||
private static byte[] getBytes(ByteBuf buffer) {
|
||||
byte[] array = new byte[buffer.readableBytes()];
|
||||
buffer.readBytes(array);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WirePacket from an existing PacketContainer
|
||||
* @param packet Existing packet
|
||||
* @return The resulting WirePacket
|
||||
*/
|
||||
public static WirePacket fromPacket(PacketContainer packet) {
|
||||
int id = packet.getType().getCurrentId();
|
||||
return new WirePacket(id, bytesFromPacket(packet));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a byte array from an existing PacketContainer containing all the
|
||||
* bytes from that packet
|
||||
*
|
||||
* @param packet Existing packet
|
||||
* @return The ByteBuf
|
||||
*/
|
||||
public static byte[] bytesFromPacket(PacketContainer packet) {
|
||||
checkNotNull(packet, "packet cannot be null!");
|
||||
|
||||
ByteBuf buffer = PacketContainer.createPacketBuffer();
|
||||
ByteBuf store = PacketContainer.createPacketBuffer();
|
||||
|
||||
// Read the bytes once
|
||||
Method write = MinecraftMethods.getPacketWriteByteBufMethod();
|
||||
|
||||
try {
|
||||
write.invoke(packet.getHandle(), buffer);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to read packet contents.", ex);
|
||||
}
|
||||
|
||||
byte[] bytes = getBytes(buffer);
|
||||
|
||||
// Rewrite them to the packet to avoid issues with certain packets
|
||||
if (packet.getType() == PacketType.Play.Server.CUSTOM_PAYLOAD
|
||||
|| packet.getType() == PacketType.Play.Client.CUSTOM_PAYLOAD) {
|
||||
// Make a copy of the array before writing
|
||||
byte[] ret = Arrays.copyOf(bytes, bytes.length);
|
||||
store.writeBytes(bytes);
|
||||
|
||||
Method read = MinecraftMethods.getPacketReadByteBufMethod();
|
||||
|
||||
try {
|
||||
read.invoke(packet.getHandle(), store);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to rewrite packet contents.", ex);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a WirePacket from an existing Minecraft packet
|
||||
* @param packet Existing Minecraft packet
|
||||
* @return The resulting WirePacket
|
||||
* @throws IllegalArgumentException If the packet is null or not a Minecraft packet
|
||||
*/
|
||||
public static WirePacket fromPacket(Object packet) {
|
||||
checkNotNull(packet, "packet cannot be null!");
|
||||
checkArgument(MinecraftReflection.isPacketClass(packet), "packet must be a Minecraft packet");
|
||||
|
||||
PacketType type = PacketType.fromClass(packet.getClass());
|
||||
int id = type.getCurrentId();
|
||||
|
||||
ByteBuf buffer = PacketContainer.createPacketBuffer();
|
||||
Method write = MinecraftMethods.getPacketWriteByteBufMethod();
|
||||
|
||||
try {
|
||||
write.invoke(packet, buffer);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to serialize packet contents.", ex);
|
||||
}
|
||||
|
||||
return new WirePacket(id, getBytes(buffer));
|
||||
}
|
||||
|
||||
public static void writeVarInt(ByteBuf output, int i) {
|
||||
checkNotNull(output, "output cannot be null!");
|
||||
|
||||
while ((i & -128) != 0) {
|
||||
output.writeByte(i & 127 | 128);
|
||||
i >>>= 7;
|
||||
@@ -49,7 +234,22 @@ public class WirePacket {
|
||||
output.writeByte(i);
|
||||
}
|
||||
|
||||
public void writeBytes(ByteBuf output) {
|
||||
output.writeBytes(bytes);
|
||||
public static int readVarInt(ByteBuf input) {
|
||||
checkNotNull(input, "input cannot be null!");
|
||||
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
byte b0;
|
||||
|
||||
do {
|
||||
b0 = input.readByte();
|
||||
i |= (b0 & 127) << j++ * 7;
|
||||
if (j > 5) {
|
||||
throw new RuntimeException("VarInt too big");
|
||||
}
|
||||
} while ((b0 & 128) == 128);
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
+46
-11
@@ -18,6 +18,7 @@
|
||||
package com.comphenix.protocol.injector.packet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
@@ -28,6 +29,7 @@ import com.comphenix.protocol.error.ReportType;
|
||||
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
|
||||
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -154,11 +156,10 @@ public class PacketRegistry {
|
||||
*/
|
||||
@Deprecated
|
||||
public static Set<Integer> getServerPackets() throws FieldAccessException {
|
||||
initialize();
|
||||
|
||||
if (LEGACY_SERVER_PACKETS == null) {
|
||||
LEGACY_SERVER_PACKETS = toLegacy(NETTY.getServerPackets());
|
||||
LEGACY_SERVER_PACKETS = toLegacy(getServerPacketTypes());
|
||||
}
|
||||
|
||||
return LEGACY_SERVER_PACKETS;
|
||||
}
|
||||
|
||||
@@ -168,9 +169,18 @@ public class PacketRegistry {
|
||||
*/
|
||||
public static Set<PacketType> getServerPacketTypes() {
|
||||
initialize();
|
||||
|
||||
NETTY.synchronize();
|
||||
return NETTY.getServerPackets();
|
||||
|
||||
Set<PacketType> types = new HashSet<>();
|
||||
|
||||
// Filter out unsupported packets
|
||||
for (PacketType type : NETTY.getServerPackets()) {
|
||||
if (!type.isDeprecated()) {
|
||||
types.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,11 +192,10 @@ public class PacketRegistry {
|
||||
*/
|
||||
@Deprecated
|
||||
public static Set<Integer> getClientPackets() throws FieldAccessException {
|
||||
initialize();
|
||||
|
||||
if (LEGACY_CLIENT_PACKETS == null) {
|
||||
LEGACY_CLIENT_PACKETS = toLegacy(NETTY.getClientPackets());
|
||||
LEGACY_CLIENT_PACKETS = toLegacy(getClientPacketTypes());
|
||||
}
|
||||
|
||||
return LEGACY_CLIENT_PACKETS;
|
||||
}
|
||||
|
||||
@@ -196,9 +205,18 @@ public class PacketRegistry {
|
||||
*/
|
||||
public static Set<PacketType> getClientPacketTypes() {
|
||||
initialize();
|
||||
|
||||
NETTY.synchronize();
|
||||
return NETTY.getClientPackets();
|
||||
|
||||
Set<PacketType> types = new HashSet<>();
|
||||
|
||||
// Filter out unsupported packets
|
||||
for (PacketType type : NETTY.getClientPackets()) {
|
||||
if (!type.isDeprecated()) {
|
||||
types.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,7 +287,24 @@ public class PacketRegistry {
|
||||
*/
|
||||
public static Class getPacketClassFromType(PacketType type, boolean forceVanilla) {
|
||||
initialize();
|
||||
return NETTY.getPacketTypeLookup().get(type);
|
||||
|
||||
// Try the lookup first
|
||||
Class<?> clazz = NETTY.getPacketTypeLookup().get(type);
|
||||
if (clazz != null) {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
// Then try looking up the class names
|
||||
for (String name : type.getClassNames()) {
|
||||
try {
|
||||
clazz = MinecraftReflection.getMinecraftClass(name);
|
||||
break;
|
||||
} catch (Exception ex) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Cache the result?
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ObjectEnum<T> implements Iterable<T> {
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void registerAll(Class<T> fieldType) {
|
||||
try {
|
||||
// Register every int field
|
||||
// Register every non-deprecated field
|
||||
for (Field entry : this.getClass().getFields()) {
|
||||
if (Modifier.isStatic(entry.getModifiers()) && fieldType.isAssignableFrom(entry.getType())) {
|
||||
T value = (T) entry.get(null);
|
||||
@@ -63,7 +63,6 @@ public class ObjectEnum<T> implements Iterable<T> {
|
||||
registerMember(value, entry.getName());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
|
||||
@@ -16,15 +16,20 @@
|
||||
*/
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.ChunkPosition;
|
||||
import com.comphenix.protocol.wrappers.MinecraftKey;
|
||||
import com.comphenix.protocol.wrappers.WrappedBlockData;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher;
|
||||
import com.comphenix.protocol.wrappers.WrappedServerPing;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -61,6 +66,16 @@ public class BukkitCloner implements Cloner {
|
||||
addClass(5, MinecraftReflection.getDataWatcherSerializerClass());
|
||||
addClass(6, MinecraftReflection.getMinecraftKeyClass());
|
||||
}
|
||||
|
||||
try {
|
||||
addClass(7, MinecraftReflection.getIBlockDataClass());
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
addClass(8, MinecraftReflection.getNonNullListClass());
|
||||
} catch (Throwable ex) {
|
||||
}
|
||||
}
|
||||
|
||||
private void addClass(int id, Class<?> clazz) {
|
||||
@@ -112,9 +127,47 @@ public class BukkitCloner implements Cloner {
|
||||
return source;
|
||||
case 6:
|
||||
EquivalentConverter<MinecraftKey> keyConverter = MinecraftKey.getConverter();
|
||||
return keyConverter.getGeneric(clonableClasses.get(5), keyConverter.getSpecific(source));
|
||||
return keyConverter.getGeneric(clonableClasses.get(6), keyConverter.getSpecific(source));
|
||||
case 7:
|
||||
EquivalentConverter<WrappedBlockData> blockDataConverter = BukkitConverters.getWrappedBlockDataConverter();
|
||||
return blockDataConverter.getGeneric(clonableClasses.get(7), blockDataConverter.getSpecific(source).deepClone());
|
||||
case 8:
|
||||
return nonNullListCloner().clone(source);
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot clone objects of type " + source.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
private static Constructor<?> nonNullList = null;
|
||||
|
||||
private static final Cloner nonNullListCloner() {
|
||||
return new Cloner() {
|
||||
@Override
|
||||
public boolean canClone(Object source) {
|
||||
return MinecraftReflection.is(MinecraftReflection.getNonNullListClass(), source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone(Object source) {
|
||||
StructureModifier<Object> modifier = new StructureModifier<>(source.getClass(), true).withTarget(source);
|
||||
List<?> list = (List<?>) modifier.read(0);
|
||||
Object empty = modifier.read(1);
|
||||
|
||||
if (nonNullList == null) {
|
||||
try {
|
||||
nonNullList = source.getClass().getDeclaredConstructor(List.class, Object.class);
|
||||
nonNullList.setAccessible(true);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Could not find NonNullList constructor", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return nonNullList.newInstance(new ArrayList<>(list), empty);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Could not create new NonNullList", ex);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
/*
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol.utility;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -29,10 +29,10 @@ import com.google.common.collect.Maps;
|
||||
* @author Kristian
|
||||
*/
|
||||
class CachedPackage {
|
||||
private final Map<String, Class<?>> cache;
|
||||
private final Map<String, Optional<Class<?>>> cache;
|
||||
private final String packageName;
|
||||
private final ClassSource source;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new cached package.
|
||||
* @param packageName - the name of the current package.
|
||||
@@ -43,16 +43,20 @@ class CachedPackage {
|
||||
this.cache = Maps.newConcurrentMap();
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Associate a given class with a class name.
|
||||
* @param className - class name.
|
||||
* @param clazz - type of class.
|
||||
*/
|
||||
public void setPackageClass(String className, Class<?> clazz) {
|
||||
cache.put(className, clazz);
|
||||
if (clazz != null) {
|
||||
cache.put(className, Optional.<Class<?>> of(clazz));
|
||||
} else {
|
||||
cache.remove(className);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the class object of a specific class in the current package.
|
||||
* @param className - the specific class.
|
||||
@@ -60,25 +64,33 @@ class CachedPackage {
|
||||
* @throws RuntimeException If we are unable to find the given class.
|
||||
*/
|
||||
public Class<?> getPackageClass(String className) {
|
||||
try {
|
||||
Class<?> result = cache.get(Preconditions.checkNotNull(className, "className cannot be NULL"));
|
||||
|
||||
// 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 = source.loadClass(combine(packageName, className));
|
||||
if (result == null)
|
||||
throw new IllegalArgumentException("Source " + source + " returned NULL for " + className);
|
||||
Preconditions.checkNotNull(className, "className cannot be null!");
|
||||
|
||||
cache.put(className, result);
|
||||
// See if we've already looked it up
|
||||
if (cache.containsKey(className)) {
|
||||
Optional<Class<?>> result = cache.get(className);
|
||||
if (!result.isPresent()) {
|
||||
throw new RuntimeException("Cannot find class " + className);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new RuntimeException("Cannot find class " + combine(packageName, className), e);
|
||||
return result.get();
|
||||
}
|
||||
|
||||
try {
|
||||
// Try looking it up
|
||||
Class<?> clazz = source.loadClass(combine(packageName, className));
|
||||
if (clazz == null) {
|
||||
throw new IllegalArgumentException("Source " + source + " returned null for " + className);
|
||||
}
|
||||
|
||||
cache.put(className, Optional.<Class<?>> of(clazz));
|
||||
return clazz;
|
||||
} catch (ClassNotFoundException ex) {
|
||||
cache.put(className, Optional.<Class<?>> absent());
|
||||
throw new RuntimeException("Cannot find class " + className, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Correctly combine a package name and the child class we're looking for.
|
||||
* @param packageName - name of the package, or an empty string for the default package.
|
||||
|
||||
@@ -21,7 +21,7 @@ package com.comphenix.protocol.utility;
|
||||
*/
|
||||
|
||||
public final class Constants {
|
||||
public static final String PACKAGE_VERSION = "v1_9_R2";
|
||||
public static final String PACKAGE_VERSION = "v1_11_R1";
|
||||
public static final String NMS = "net.minecraft.server." + PACKAGE_VERSION;
|
||||
public static final String OBC = "org.bukkit.craftbukkit." + PACKAGE_VERSION;
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public class MinecraftFields {
|
||||
* @return The player connection.
|
||||
*/
|
||||
public static Object getPlayerConnection(Player player) {
|
||||
Preconditions.checkNotNull(player, "player cannot be null!");
|
||||
return getPlayerConnection(BukkitUnwrapper.getInstance().unwrapItem(player));
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -4,7 +4,6 @@ import java.util.Map.Entry;
|
||||
import java.util.NavigableMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
/**
|
||||
@@ -42,6 +41,9 @@ public class MinecraftProtocolVersion {
|
||||
map.put(new MinecraftVersion(1, 9, 0), 107);
|
||||
map.put(new MinecraftVersion(1, 9, 2), 109);
|
||||
map.put(new MinecraftVersion(1, 9, 4), 110);
|
||||
map.put(new MinecraftVersion(1, 10, 0), 210);
|
||||
map.put(new MinecraftVersion(1, 11, 0), 315);
|
||||
map.put(new MinecraftVersion(1, 11, 1), 316);
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -50,7 +52,7 @@ public class MinecraftProtocolVersion {
|
||||
* @return The version number.
|
||||
*/
|
||||
public static int getCurrentVersion() {
|
||||
return getVersion(ProtocolLibrary.getProtocolManager().getMinecraftVersion());
|
||||
return getVersion(MinecraftVersion.getCurrentVersion());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+171
-154
@@ -41,6 +41,7 @@ import java.util.regex.Pattern;
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@@ -62,8 +63,8 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyClassContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMatchers;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavaibleException;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavaibleException.Reason;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException.Reason;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
|
||||
import com.comphenix.protocol.wrappers.nbt.NbtType;
|
||||
import com.google.common.base.Joiner;
|
||||
@@ -128,13 +129,13 @@ public class MinecraftReflection {
|
||||
private static String packageVersion;
|
||||
|
||||
// Item stacks
|
||||
private static Method craftNMSMethod;
|
||||
/* private static Method craftNMSMethod;
|
||||
private static Method craftBukkitNMS;
|
||||
private static Method craftBukkitOBC;
|
||||
private static boolean craftItemStackFailed;
|
||||
|
||||
private static Constructor<?> craftNMSConstructor;
|
||||
private static Constructor<?> craftBukkitConstructor;
|
||||
private static Constructor<?> craftBukkitConstructor; */
|
||||
|
||||
// net.minecraft.server
|
||||
private static Class<?> itemStackArrayClass;
|
||||
@@ -152,6 +153,7 @@ public class MinecraftReflection {
|
||||
|
||||
// Whether or not we are using netty
|
||||
private static Boolean cachedNetty;
|
||||
private static Boolean cachedWatcherObject;
|
||||
|
||||
private MinecraftReflection() {
|
||||
// No need to make this constructable.
|
||||
@@ -408,14 +410,31 @@ public class MinecraftReflection {
|
||||
return javaName.startsWith(MINECRAFT_PREFIX_PACKAGE) && javaName.endsWith(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given Object is compatible with a given Class. That is,
|
||||
* whether or not the Object is an instance of that Class or one of its
|
||||
* subclasses. If either is null, false is returned.
|
||||
*
|
||||
* @param clazz Class to test for, may be null
|
||||
* @param object the Object to test, may be null
|
||||
* @return True if it is, false if not
|
||||
* @see Class#isAssignableFrom(Class)
|
||||
*/
|
||||
public static boolean is(Class<?> clazz, Object object) {
|
||||
if (clazz == null || object == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return clazz.isAssignableFrom(object.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a given object is a ChunkPosition.
|
||||
* @param obj - the object to test.
|
||||
* @return TRUE if it can, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isChunkPosition(Object obj) {
|
||||
Class<?> chunkPosition = getChunkPositionClass();
|
||||
return obj != null && chunkPosition != null && chunkPosition.isAssignableFrom(obj.getClass());
|
||||
return is(getChunkPositionClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -424,8 +443,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it can, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isBlockPosition(Object obj) {
|
||||
Class<?> blockPosition = getBlockPositionClass();
|
||||
return obj != null && blockPosition != null && blockPosition.isAssignableFrom(obj.getClass());
|
||||
return is(getBlockPositionClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -434,7 +452,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it can, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isChunkCoordIntPair(Object obj) {
|
||||
return obj != null && getChunkCoordIntPair().isAssignableFrom(obj.getClass());
|
||||
return is(getChunkCoordIntPair(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -443,8 +461,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it can, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isChunkCoordinates(Object obj) {
|
||||
Class<?> chunkCoordinates = getChunkCoordinatesClass();
|
||||
return obj != null && chunkCoordinates != null && chunkCoordinates.isAssignableFrom(obj.getClass());
|
||||
return is(getChunkCoordinatesClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -453,7 +470,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isPacketClass(Object obj) {
|
||||
return obj != null && getPacketClass().isAssignableFrom(obj.getClass());
|
||||
return is(getPacketClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,7 +479,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isLoginHandler(Object obj) {
|
||||
return obj != null && getNetLoginHandlerClass().isAssignableFrom(obj.getClass());
|
||||
return is(getNetLoginHandlerClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -471,7 +488,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isServerHandler(Object obj) {
|
||||
return obj != null && getPlayerConnectionClass().isAssignableFrom(obj.getClass());
|
||||
return is(getPlayerConnectionClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -480,7 +497,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isMinecraftEntity(Object obj) {
|
||||
return obj != null && getEntityClass().isAssignableFrom(obj.getClass());
|
||||
return is(getEntityClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -489,7 +506,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isItemStack(Object value) {
|
||||
return value != null && getItemStackClass().isAssignableFrom(value.getClass());
|
||||
return is(getItemStackClass(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -498,7 +515,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isCraftPlayer(Object value) {
|
||||
return value != null && getCraftPlayerClass().isAssignableFrom(value.getClass());
|
||||
return is(getCraftPlayerClass(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -507,7 +524,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isMinecraftPlayer(Object obj) {
|
||||
return obj != null && getEntityPlayerClass().isAssignableFrom(obj.getClass());
|
||||
return is(getEntityPlayerClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -516,7 +533,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isWatchableObject(Object obj) {
|
||||
return obj != null && getWatchableObjectClass().isAssignableFrom(obj.getClass());
|
||||
return is(getWatchableObjectClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,7 +542,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isDataWatcher(Object obj) {
|
||||
return obj != null && getDataWatcherClass().isAssignableFrom(obj.getClass());
|
||||
return is(getDataWatcherClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,7 +551,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isIntHashMap(Object obj) {
|
||||
return obj != null && getIntHashMapClass().isAssignableFrom(obj.getClass());
|
||||
return is(getIntHashMapClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -543,7 +560,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isCraftItemStack(Object obj) {
|
||||
return obj != null && getCraftItemStackClass().isAssignableFrom(obj.getClass());
|
||||
return is(getCraftItemStackClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -917,6 +934,9 @@ public class MinecraftReflection {
|
||||
return getMinecraftClass("MinecraftServer");
|
||||
} catch (RuntimeException e) {
|
||||
useFallbackServer();
|
||||
|
||||
// Reset cache and try again
|
||||
setMinecraftClass("MinecraftServer", null);
|
||||
return getMinecraftClass("MinecraftServer");
|
||||
}
|
||||
}
|
||||
@@ -965,8 +985,10 @@ public class MinecraftReflection {
|
||||
try {
|
||||
return getMinecraftClass("ServerConfigurationManager", "PlayerList");
|
||||
} catch (RuntimeException e) {
|
||||
// Try again
|
||||
useFallbackServer();
|
||||
|
||||
// Reset cache and try again
|
||||
setMinecraftClass("ServerConfigurationManager", null);
|
||||
return getMinecraftClass("ServerConfigurationManager");
|
||||
}
|
||||
}
|
||||
@@ -1180,24 +1202,7 @@ public class MinecraftReflection {
|
||||
try {
|
||||
return getMinecraftClass("ChunkPosition");
|
||||
} catch (RuntimeException e) {
|
||||
try {
|
||||
Class<?> normalChunkGenerator = getCraftBukkitClass("generator.NormalChunkGenerator");
|
||||
|
||||
// ChunkPosition a(net.minecraft.server.World world, String string, int i, int i1, int i2) {
|
||||
FuzzyMethodContract selected = FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.parameterMatches(getMinecraftObjectMatcher(), 0)
|
||||
.parameterExactType(String.class, 1)
|
||||
.parameterExactType(int.class, 2)
|
||||
.parameterExactType(int.class, 3)
|
||||
.parameterExactType(int.class, 4)
|
||||
.build();
|
||||
|
||||
return setMinecraftClass("ChunkPosition",
|
||||
FuzzyReflection.fromClass(normalChunkGenerator).getMethod(selected).getReturnType());
|
||||
} catch (Throwable ex) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1315,16 +1320,23 @@ public class MinecraftReflection {
|
||||
}
|
||||
|
||||
public static Class<?> getDataWatcherObjectClass() {
|
||||
// TODO Implement a fallback
|
||||
return getMinecraftClass("DataWatcherObject");
|
||||
try {
|
||||
return getMinecraftClass("DataWatcherObject");
|
||||
} catch (RuntimeException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean watcherObjectExists() {
|
||||
try {
|
||||
return getDataWatcherObjectClass() != null;
|
||||
} catch (RuntimeException e) {
|
||||
return false;
|
||||
if (cachedWatcherObject == null) {
|
||||
try {
|
||||
return cachedWatcherObject = getDataWatcherObjectClass() != null;
|
||||
} catch (Throwable ex) {
|
||||
return cachedWatcherObject = false;
|
||||
}
|
||||
}
|
||||
|
||||
return cachedWatcherObject;
|
||||
}
|
||||
|
||||
public static Class<?> getDataWatcherSerializerClass() {
|
||||
@@ -1621,8 +1633,10 @@ public class MinecraftReflection {
|
||||
try {
|
||||
return getMinecraftClass("AttributeModifier");
|
||||
} catch (RuntimeException e) {
|
||||
// Initialize first
|
||||
getAttributeSnapshotClass();
|
||||
|
||||
// Reset cache and try again
|
||||
setMinecraftClass("AttributeModifier", null);
|
||||
return getMinecraftClass("AttributeModifier");
|
||||
}
|
||||
}
|
||||
@@ -1794,8 +1808,7 @@ public class MinecraftReflection {
|
||||
* @return TRUE if it is, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isPlayerInfoData(Object obj) {
|
||||
Class<?> clazz = getPlayerInfoDataClass();
|
||||
return clazz != null && obj.getClass().equals(clazz);
|
||||
return is(getPlayerInfoDataClass(), obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1822,119 +1835,123 @@ public class MinecraftReflection {
|
||||
return getArrayClass(getMultiBlockChangeInfoClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a CraftItemStack from a given ItemStack.
|
||||
* @param bukkitItemStack - the Bukkit ItemStack to convert.
|
||||
* @return A CraftItemStack as an ItemStack.
|
||||
*/
|
||||
public static ItemStack getBukkitItemStack(ItemStack bukkitItemStack) {
|
||||
// Delegate this task to the method that can execute it
|
||||
if (craftBukkitNMS != null)
|
||||
return getBukkitItemByMethod(bukkitItemStack);
|
||||
|
||||
if (craftBukkitConstructor == null) {
|
||||
try {
|
||||
craftBukkitConstructor = getCraftItemStackClass().getConstructor(ItemStack.class);
|
||||
} catch (Exception e) {
|
||||
// See if this method works
|
||||
if (!craftItemStackFailed)
|
||||
return getBukkitItemByMethod(bukkitItemStack);
|
||||
|
||||
throw new RuntimeException("Cannot find CraftItemStack(org.bukkit.inventory.ItemStack).", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to create the CraftItemStack
|
||||
public static boolean signUpdateExists() {
|
||||
try {
|
||||
return (ItemStack) craftBukkitConstructor.newInstance(bukkitItemStack);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot construct CraftItemStack.", e);
|
||||
return getMinecraftClass("PacketPlayOutUpdateSign") != null;
|
||||
} catch (RuntimeException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static ItemStack getBukkitItemByMethod(ItemStack bukkitItemStack) {
|
||||
if (craftBukkitNMS == null) {
|
||||
try {
|
||||
craftBukkitNMS = getCraftItemStackClass().getMethod("asNMSCopy", ItemStack.class);
|
||||
craftBukkitOBC = getCraftItemStackClass().getMethod("asCraftMirror", MinecraftReflection.getItemStackClass());
|
||||
} catch (Exception e) {
|
||||
craftItemStackFailed = true;
|
||||
throw new RuntimeException("Cannot find CraftItemStack.asCraftCopy(org.bukkit.inventory.ItemStack).", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Next, construct it
|
||||
try {
|
||||
Object nmsItemStack = craftBukkitNMS.invoke(null, bukkitItemStack);
|
||||
return (ItemStack) craftBukkitOBC.invoke(null, nmsItemStack);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot construct CraftItemStack.", e);
|
||||
}
|
||||
public static Class<?> getNonNullListClass() {
|
||||
return getMinecraftClass("NonNullList");
|
||||
}
|
||||
|
||||
public static Class<?> getCraftSoundClass() {
|
||||
return getCraftBukkitClass("CraftSound");
|
||||
}
|
||||
|
||||
// ---- ItemStack conversions
|
||||
|
||||
private static Method asNMSCopy = null;
|
||||
private static Method asCraftMirror = null;
|
||||
|
||||
private static Boolean nullEnforced = null;
|
||||
private static Method isEmpty = null;
|
||||
|
||||
/**
|
||||
* Retrieve the Bukkit ItemStack from a given net.minecraft.server ItemStack.
|
||||
* @param minecraftItemStack - the NMS ItemStack to wrap.
|
||||
* @return The wrapped ItemStack.
|
||||
*/
|
||||
public static ItemStack getBukkitItemStack(Object minecraftItemStack) {
|
||||
// Delegate this task to the method that can execute it
|
||||
if (craftNMSMethod != null)
|
||||
return getBukkitItemByMethod(minecraftItemStack);
|
||||
|
||||
if (craftNMSConstructor == null) {
|
||||
try {
|
||||
craftNMSConstructor = getCraftItemStackClass().getConstructor(minecraftItemStack.getClass());
|
||||
} catch (Exception e) {
|
||||
// Give it a try
|
||||
if (!craftItemStackFailed)
|
||||
return getBukkitItemByMethod(minecraftItemStack);
|
||||
|
||||
throw new RuntimeException("Cannot find CraftItemStack(net.minecraft.server.ItemStack).", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Try to create the CraftItemStack
|
||||
try {
|
||||
return (ItemStack) craftNMSConstructor.newInstance(minecraftItemStack);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot construct CraftItemStack.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private static ItemStack getBukkitItemByMethod(Object minecraftItemStack) {
|
||||
if (craftNMSMethod == null) {
|
||||
try {
|
||||
craftNMSMethod = getCraftItemStackClass().getMethod("asCraftMirror", minecraftItemStack.getClass());
|
||||
} catch (Exception e) {
|
||||
craftItemStackFailed = true;
|
||||
throw new RuntimeException("Cannot find CraftItemStack.asCraftMirror(net.minecraft.server.ItemStack).", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Next, construct it
|
||||
try {
|
||||
return (ItemStack) craftNMSMethod.invoke(null, minecraftItemStack);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Cannot construct CraftItemStack.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the net.minecraft.server ItemStack from a Bukkit ItemStack.
|
||||
* <p>
|
||||
* By convention, item stacks that contain air are usually represented as NULL.
|
||||
* Retrieves the Bukkit equivalent of a NMS ItemStack. This method should
|
||||
* preserve NBT data and will never return null when supplied with a valid
|
||||
* ItemStack. Empty ItemStacks are treated as AIR.
|
||||
*
|
||||
* @param stack - the Bukkit ItemStack to convert.
|
||||
* @return The NMS ItemStack, or NULL if the stack represents air.
|
||||
* @param generic NMS ItemStack
|
||||
* @return The Bukkit equivalent
|
||||
*/
|
||||
public static Object getMinecraftItemStack(ItemStack stack) {
|
||||
// Make sure this is a CraftItemStack
|
||||
if (!isCraftItemStack(stack))
|
||||
stack = getBukkitItemStack(stack);
|
||||
public static ItemStack getBukkitItemStack(Object generic) {
|
||||
if (generic == null) {
|
||||
// Convert null to AIR - 1.11 behavior
|
||||
return new ItemStack(Material.AIR);
|
||||
}
|
||||
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
return unwrapper.unwrapItem(stack);
|
||||
if (generic instanceof ItemStack) {
|
||||
ItemStack bukkit = (ItemStack) generic;
|
||||
|
||||
// They're probably looking for the CraftItemStack
|
||||
// If it's one already our work is done
|
||||
if (is(getCraftItemStackClass(), generic)) {
|
||||
return bukkit;
|
||||
}
|
||||
|
||||
// If not, convert it to one
|
||||
Object nmsStack = getMinecraftItemStack((ItemStack) generic);
|
||||
return getBukkitItemStack(nmsStack);
|
||||
}
|
||||
|
||||
if (!is(getItemStackClass(), generic)) {
|
||||
// We can't do anything with non-ItemStacks
|
||||
throw new IllegalArgumentException(generic + " is not an ItemStack!");
|
||||
}
|
||||
|
||||
try {
|
||||
// Check null enforcement - 1.11 behavior
|
||||
if (nullEnforced == null) {
|
||||
isEmpty = getItemStackClass().getMethod("isEmpty");
|
||||
nullEnforced = true;
|
||||
}
|
||||
|
||||
if (nullEnforced) {
|
||||
if ((boolean) isEmpty.invoke(generic)) {
|
||||
return new ItemStack(Material.AIR);
|
||||
}
|
||||
}
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
nullEnforced = false;
|
||||
}
|
||||
|
||||
if (asCraftMirror == null) {
|
||||
try {
|
||||
asCraftMirror = getCraftItemStackClass().getMethod("asCraftMirror", getItemStackClass());
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to obtain CraftItemStack.asCraftMirror", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Convert to a craft mirror to preserve NBT data
|
||||
return (ItemStack) asCraftMirror.invoke(nullEnforced, generic);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to obtain craft mirror of " + generic, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the NMS equivalent of a Bukkit ItemStack. This method will
|
||||
* never return null and should preserve NBT data. Null inputs are treated
|
||||
* as empty (AIR) ItemStacks.
|
||||
*
|
||||
* @param specific Bukkit ItemStack
|
||||
* @return The NMS equivalent
|
||||
*/
|
||||
public static Object getMinecraftItemStack(ItemStack specific) {
|
||||
if (asNMSCopy == null) {
|
||||
try {
|
||||
asNMSCopy = getCraftItemStackClass().getMethod("asNMSCopy", ItemStack.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to obtain CraftItemStack.asNMSCopy", ex);
|
||||
}
|
||||
}
|
||||
|
||||
if (is(getCraftItemStackClass(), specific)) {
|
||||
// If it's already a CraftItemStack, use its handle
|
||||
return new BukkitUnwrapper().unwrapItem(specific);
|
||||
}
|
||||
|
||||
try {
|
||||
// If not, grab a NMS copy
|
||||
return asNMSCopy.invoke(null, specific);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to make NMS copy of " + specific, ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1999,7 +2016,7 @@ public class MinecraftReflection {
|
||||
// Attempt to use MCPC
|
||||
try {
|
||||
return classSource = new RemappedClassSource().initialize();
|
||||
} catch (RemapperUnavaibleException e) {
|
||||
} catch (RemapperUnavailableException e) {
|
||||
if (e.getReason() != Reason.MCPC_NOT_PRESENT)
|
||||
reporter.reportWarning(MinecraftReflection.class, Report.newBuilder(REPORT_CANNOT_FIND_MCPC_REMAPPER));
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -44,6 +44,16 @@ public class MinecraftVersion implements Comparable<MinecraftVersion>, Serializa
|
||||
*/
|
||||
private static final Pattern VERSION_PATTERN = Pattern.compile(".*\\(.*MC.\\s*([a-zA-z0-9\\-\\.]+)\\s*\\)");
|
||||
|
||||
/**
|
||||
* Version 1.11 - the exploration update.
|
||||
*/
|
||||
public static final MinecraftVersion EXPLORATION_UPDATE = new MinecraftVersion("1.11");
|
||||
|
||||
/**
|
||||
* Version 1.10 - the frostburn update.
|
||||
*/
|
||||
public static final MinecraftVersion FROSTBURN_UPDATE = new MinecraftVersion("1.10");
|
||||
|
||||
/**
|
||||
* Version 1.9 - the combat update.
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.bukkit.Server;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.MethodUtils;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavaibleException.Reason;
|
||||
import com.comphenix.protocol.utility.RemappedClassSource.RemapperUnavailableException.Reason;
|
||||
|
||||
class RemappedClassSource extends ClassSource {
|
||||
private Object classRemapper;
|
||||
@@ -53,7 +53,7 @@ class RemappedClassSource extends ClassSource {
|
||||
/**
|
||||
* Attempt to load the MCPC remapper.
|
||||
* @return TRUE if we succeeded, FALSE otherwise.
|
||||
* @throws RemapperUnavaibleException If the remapper is not present.
|
||||
* @throws RemapperUnavailableException If the remapper is not present.
|
||||
*/
|
||||
public RemappedClassSource initialize() {
|
||||
try {
|
||||
@@ -64,14 +64,14 @@ class RemappedClassSource extends ClassSource {
|
||||
|
||||
String version = server.getVersion();
|
||||
if (!version.contains("MCPC") && !version.contains("Cauldron")) {
|
||||
throw new RemapperUnavaibleException(Reason.MCPC_NOT_PRESENT);
|
||||
throw new RemapperUnavailableException(Reason.MCPC_NOT_PRESENT);
|
||||
}
|
||||
|
||||
// Obtain the Class remapper used by MCPC+/Cauldron
|
||||
this.classRemapper = FieldUtils.readField(getClass().getClassLoader(), "remapper", true);
|
||||
|
||||
if (this.classRemapper == null) {
|
||||
throw new RemapperUnavaibleException(Reason.REMAPPER_DISABLED);
|
||||
throw new RemapperUnavailableException(Reason.REMAPPER_DISABLED);
|
||||
}
|
||||
|
||||
// Initialize some fields and methods used by the Jar Remapper
|
||||
@@ -82,7 +82,7 @@ class RemappedClassSource extends ClassSource {
|
||||
|
||||
return this;
|
||||
|
||||
} catch (RemapperUnavaibleException e) {
|
||||
} catch (RemapperUnavailableException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
// Damn it
|
||||
@@ -115,7 +115,7 @@ class RemappedClassSource extends ClassSource {
|
||||
}
|
||||
}
|
||||
|
||||
public static class RemapperUnavaibleException extends RuntimeException {
|
||||
public static class RemapperUnavailableException extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public enum Reason {
|
||||
@@ -139,7 +139,7 @@ class RemappedClassSource extends ClassSource {
|
||||
|
||||
private final Reason reason;
|
||||
|
||||
public RemapperUnavaibleException(Reason reason) {
|
||||
public RemapperUnavailableException(Reason reason) {
|
||||
super(reason.getMessage());
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
@@ -60,4 +60,17 @@ public class Util {
|
||||
public static boolean isUsingSpigot() {
|
||||
return Bukkit.getServer().getVersion().contains("Spigot");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently running major Java version.
|
||||
* @return The version or -1 if it could not be found
|
||||
*/
|
||||
public static int getJavaVersion() {
|
||||
try {
|
||||
String version = Runtime.class.getPackage().getSpecificationVersion();
|
||||
return (int) (Double.parseDouble(version) * 10 % 10);
|
||||
} catch (Throwable ex) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,4 +47,26 @@ public abstract class AbstractWrapper {
|
||||
public Class<?> getHandleType() {
|
||||
return handleType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
|
||||
if (obj instanceof AbstractWrapper) {
|
||||
AbstractWrapper that = (AbstractWrapper) obj;
|
||||
return this.handle.equals(that.handle);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return handle.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + "[handle=" + handle + "]";
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
@@ -124,7 +125,7 @@ public class BukkitConverters {
|
||||
* @author Kristian
|
||||
* @param <T> - type that can be converted.
|
||||
*/
|
||||
private static abstract class IgnoreNullConverter<TType> implements EquivalentConverter<TType> {
|
||||
public static abstract class IgnoreNullConverter<TType> implements EquivalentConverter<TType> {
|
||||
@Override
|
||||
public final Object getGeneric(Class<?> genericType, TType specific) {
|
||||
if (specific != null)
|
||||
@@ -158,20 +159,20 @@ public class BukkitConverters {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// Very short
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
// See if they're equivalent
|
||||
if (this == obj) return true;
|
||||
|
||||
if (obj instanceof EquivalentConverter) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
EquivalentConverter other = (EquivalentConverter) obj;
|
||||
return Objects.equal(this.getSpecificType(), other.getSpecificType());
|
||||
EquivalentConverter<?> that = (EquivalentConverter<?>) obj;
|
||||
return Objects.equal(this.getSpecificType(), that.getSpecificType());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.getSpecificType());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -194,23 +195,23 @@ public class BukkitConverters {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// More shortcuts
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
if (obj == this) return true;
|
||||
|
||||
// Add another constraint
|
||||
if (obj instanceof WorldSpecificConverter && super.equals(obj)) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
WorldSpecificConverter other = (WorldSpecificConverter) obj;
|
||||
|
||||
return Objects.equal(world, other.world);
|
||||
WorldSpecificConverter<?> that = (WorldSpecificConverter<?>) obj;
|
||||
return Objects.equal(this.world, that.world);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(this.getSpecificType(), this.world);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve an equivalent converter for a map of generic keys and primitive values.
|
||||
* @param <T> Key type
|
||||
@@ -713,24 +714,24 @@ public class BukkitConverters {
|
||||
* @return Item stack converter.
|
||||
*/
|
||||
public static EquivalentConverter<ItemStack> getItemStackConverter() {
|
||||
return new IgnoreNullConverter<ItemStack>() {
|
||||
return new EquivalentConverter<ItemStack>() {
|
||||
@Override
|
||||
protected Object getGenericValue(Class<?> genericType, ItemStack specific) {
|
||||
return MinecraftReflection.getMinecraftItemStack(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getSpecificValue(Object generic) {
|
||||
public ItemStack getSpecific(Object generic) {
|
||||
return MinecraftReflection.getBukkitItemStack(generic);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getGeneric(Class<?> genericType, ItemStack specific) {
|
||||
return MinecraftReflection.getMinecraftItemStack(specific);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<ItemStack> getSpecificType() {
|
||||
return ItemStack.class;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the converter for the ServerPing packet in {@link PacketType.Status.Server#OUT_SERVER_INFO}.
|
||||
* @return Server ping converter.
|
||||
@@ -964,10 +965,21 @@ public class BukkitConverters {
|
||||
};
|
||||
}
|
||||
|
||||
private static MethodAccessor soundGetter = null;
|
||||
private static MethodAccessor getSound = null;
|
||||
private static MethodAccessor getSoundEffect = null;
|
||||
private static FieldAccessor soundKey = null;
|
||||
|
||||
private static Map<String, Sound> soundIndex = null;
|
||||
|
||||
public static EquivalentConverter<Sound> getSoundConverter() {
|
||||
if (getSound == null || getSoundEffect == null) {
|
||||
Class<?> craftSound = MinecraftReflection.getCraftSoundClass();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(craftSound, true);
|
||||
getSound = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getSound", String.class, new Class<?>[] { Sound.class }));
|
||||
getSoundEffect = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getSoundEffect",
|
||||
MinecraftReflection.getSoundEffectClass(), new Class<?>[] { String.class }));
|
||||
}
|
||||
|
||||
return new IgnoreNullConverter<Sound>() {
|
||||
|
||||
@Override
|
||||
@@ -977,26 +989,42 @@ public class BukkitConverters {
|
||||
|
||||
@Override
|
||||
protected Object getGenericValue(Class<?> genericType, Sound specific) {
|
||||
if (soundGetter == null) {
|
||||
Class<?> soundEffects = MinecraftReflection.getMinecraftClass("SoundEffects");
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(soundEffects, true);
|
||||
soundGetter = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("getSound", MinecraftReflection.getSoundEffectClass(), new Class<?>[] { String.class }));
|
||||
}
|
||||
|
||||
MinecraftKey key = MinecraftKey.fromEnum(specific);
|
||||
return soundGetter.invoke(null, key.getFullKey());
|
||||
// Getting the SoundEffect is easy, Bukkit provides us the methods
|
||||
String key = (String) getSound.invoke(null, specific);
|
||||
return getSoundEffect.invoke(null, key);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sound getSpecificValue(Object generic) {
|
||||
// Getting the Sound is a bit more complicated...
|
||||
if (soundKey == null) {
|
||||
Class<?> soundEffect = generic.getClass();
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(soundEffect, true);
|
||||
soundKey = Accessors.getFieldAccessor(fuzzy.getFieldByType("key", MinecraftReflection.getMinecraftKeyClass()));
|
||||
}
|
||||
|
||||
MinecraftKey key = MinecraftKey.fromHandle(soundKey.get(generic));
|
||||
return Sound.valueOf(key.getEnumFormat());
|
||||
MinecraftKey minecraftKey = MinecraftKey.fromHandle(soundKey.get(generic));
|
||||
String key = minecraftKey.getKey();
|
||||
|
||||
// Use our index if it already exists
|
||||
if (soundIndex != null) {
|
||||
return soundIndex.get(key);
|
||||
}
|
||||
|
||||
// If it doesn't, try to guess the enum name
|
||||
try {
|
||||
return Sound.valueOf(minecraftKey.getEnumFormat());
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
|
||||
// Worst case we index all the sounds and use it later
|
||||
soundIndex = new ConcurrentHashMap<>();
|
||||
for (Sound sound : Sound.values()) {
|
||||
String index = (String) getSound.invoke(null, sound);
|
||||
soundIndex.put(index, sound);
|
||||
}
|
||||
|
||||
return soundIndex.get(key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ import net.md_5.bungee.chat.ComponentSerializer;
|
||||
* Note: The BungeeCord Chat API is not included in CraftBukkit.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public final class ComponentConverter {
|
||||
|
||||
private ComponentConverter() {
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2016 dmulloy2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Handles component parsing in 1.8
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class ComponentParser {
|
||||
|
||||
private ComponentParser() {
|
||||
}
|
||||
|
||||
public static Object deserialize(Object gson, Class<?> component, StringReader str) {
|
||||
try {
|
||||
com.google.gson.stream.JsonReader reader = new com.google.gson.stream.JsonReader(str);
|
||||
reader.setLenient(true);
|
||||
return ((com.google.gson.Gson) gson).getAdapter(component).read(reader);
|
||||
} catch (IOException ex) {
|
||||
throw new RuntimeException("Failed to read JSON", ex);
|
||||
} catch (LinkageError er) {
|
||||
return deserializeLegacy(gson, component, str);
|
||||
}
|
||||
}
|
||||
|
||||
// Should only be needed on 1.8.
|
||||
private static Object deserializeLegacy(Object gson, Class<?> component, StringReader str) {
|
||||
try {
|
||||
Class<?> readerClass = Class.forName("org.bukkit.craftbukkit.libs.com.google.gson.stream.JsonReader");
|
||||
Object reader = readerClass.getConstructor(Reader.class).newInstance(str);
|
||||
Method setLenient = readerClass.getMethod("setLenienent", boolean.class);
|
||||
setLenient.invoke(reader, true);
|
||||
Method getAdapter = gson.getClass().getMethod("getAdapter", Class.class);
|
||||
Object adapter = getAdapter.invoke(gson, component);
|
||||
Method read = adapter.getClass().getMethod("read", readerClass);
|
||||
return read.invoke(adapter, reader);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to read JSON", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.GameMode;
|
||||
@@ -216,7 +217,8 @@ public abstract class EnumWrappers {
|
||||
DRAGON_BREATH("dragonbreath", 42, false),
|
||||
END_ROD("endRod", 43, false),
|
||||
DAMAGE_INDICATOR("damageIndicator", 44, true),
|
||||
SWEEP_ATTACK("sweepAttack", 45, true);
|
||||
SWEEP_ATTACK("sweepAttack", 45, true),
|
||||
FALLING_DUST("fallingdust", 46, true);
|
||||
|
||||
private static final Map<String, Particle> BY_NAME;
|
||||
private static final Map<Integer, Particle> BY_ID;
|
||||
@@ -226,7 +228,7 @@ public abstract class EnumWrappers {
|
||||
BY_NAME = new HashMap<String, Particle>();
|
||||
|
||||
for (Particle particle : values()) {
|
||||
BY_NAME.put(particle.getName().toLowerCase(), particle);
|
||||
BY_NAME.put(particle.getName().toLowerCase(Locale.ENGLISH), particle);
|
||||
BY_ID.put(particle.getId(), particle);
|
||||
}
|
||||
}
|
||||
@@ -264,7 +266,7 @@ public abstract class EnumWrappers {
|
||||
}
|
||||
|
||||
public static Particle getByName(String name) {
|
||||
return BY_NAME.get(name.toLowerCase());
|
||||
return BY_NAME.get(name.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
public static Particle getById(int id) {
|
||||
@@ -302,7 +304,7 @@ public abstract class EnumWrappers {
|
||||
}
|
||||
|
||||
public static SoundCategory getByKey(String key) {
|
||||
return LOOKUP.get(key.toLowerCase());
|
||||
return LOOKUP.get(key.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,6 +322,15 @@ public abstract class EnumWrappers {
|
||||
OFF_HAND;
|
||||
}
|
||||
|
||||
public enum Direction {
|
||||
DOWN(),
|
||||
UP(),
|
||||
NORTH(),
|
||||
SOUTH(),
|
||||
WEST(),
|
||||
EAST();
|
||||
}
|
||||
|
||||
private static Class<?> PROTOCOL_CLASS = null;
|
||||
private static Class<?> CLIENT_COMMAND_CLASS = null;
|
||||
private static Class<?> CHAT_VISIBILITY_CLASS = null;
|
||||
@@ -338,6 +349,7 @@ public abstract class EnumWrappers {
|
||||
private static Class<?> SOUND_CATEGORY_CLASS = null;
|
||||
private static Class<?> ITEM_SLOT_CLASS = null;
|
||||
private static Class<?> HAND_CLASS = null;
|
||||
private static Class<?> DIRECTION_CLASS = null;
|
||||
|
||||
private static boolean INITIALIZED = false;
|
||||
private static Map<Class<?>, EquivalentConverter<?>> FROM_NATIVE = Maps.newHashMap();
|
||||
@@ -373,6 +385,7 @@ public abstract class EnumWrappers {
|
||||
SOUND_CATEGORY_CLASS = getEnum(PacketType.Play.Server.CUSTOM_SOUND_EFFECT.getPacketClass(), 0);
|
||||
ITEM_SLOT_CLASS = getEnum(PacketType.Play.Server.ENTITY_EQUIPMENT.getPacketClass(), 0);
|
||||
HAND_CLASS = getEnum(PacketType.Play.Client.USE_ENTITY.getPacketClass(), 1);
|
||||
DIRECTION_CLASS = getEnum(PacketType.Play.Client.USE_ITEM.getPacketClass(), 0);
|
||||
|
||||
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
|
||||
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
|
||||
@@ -392,6 +405,7 @@ public abstract class EnumWrappers {
|
||||
associate(SOUND_CATEGORY_CLASS, SoundCategory.class, getSoundCategoryConverter());
|
||||
associate(ITEM_SLOT_CLASS, ItemSlot.class, getItemSlotConverter());
|
||||
associate(HAND_CLASS, Hand.class, getHandConverter());
|
||||
associate(DIRECTION_CLASS, Direction.class, getDirectionConverter());
|
||||
INITIALIZED = true;
|
||||
}
|
||||
|
||||
@@ -515,6 +529,11 @@ public abstract class EnumWrappers {
|
||||
return HAND_CLASS;
|
||||
}
|
||||
|
||||
public static Class<?> getDirectionClass() {
|
||||
initialize();
|
||||
return DIRECTION_CLASS;
|
||||
}
|
||||
|
||||
// Get the converters
|
||||
public static EquivalentConverter<Protocol> getProtocolConverter() {
|
||||
return new EnumConverter<Protocol>(Protocol.class);
|
||||
@@ -588,6 +607,10 @@ public abstract class EnumWrappers {
|
||||
return new EnumConverter<Hand>(Hand.class);
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Direction> getDirectionConverter() {
|
||||
return new EnumConverter<Direction>(Direction.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a generic enum converter for use with StructureModifiers.
|
||||
* @param enumClass - Enum class
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Locale;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
@@ -68,9 +69,11 @@ public class MinecraftKey {
|
||||
* is lower case, with underscores replaced by periods.
|
||||
* @param value The value
|
||||
* @return The resulting key
|
||||
* @deprecated This isn't accurate in all cases
|
||||
*/
|
||||
@Deprecated
|
||||
public static MinecraftKey fromEnum(Enum<?> value) {
|
||||
return new MinecraftKey(value.name().toLowerCase().replace("_", "."));
|
||||
return new MinecraftKey(value.name().toLowerCase(Locale.ENGLISH).replace("_", "."));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,9 +105,11 @@ public class MinecraftKey {
|
||||
* Returns this key back into Enum format, upper case with periods replaced
|
||||
* by underscores.
|
||||
* @return The enum format
|
||||
* @deprecated This isn't accurate in all cases
|
||||
*/
|
||||
@Deprecated
|
||||
public String getEnumFormat() {
|
||||
return key.toUpperCase().replace(".", "_");
|
||||
return key.toUpperCase(Locale.ENGLISH).replace(".", "_");
|
||||
}
|
||||
|
||||
private static Constructor<?> constructor = null;
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* (c) 2016 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters.IgnoreNullConverter;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class Vector3F {
|
||||
protected float x;
|
||||
protected float y;
|
||||
protected float z;
|
||||
|
||||
public Vector3F() {
|
||||
this(0, 0, 0);
|
||||
}
|
||||
|
||||
public Vector3F(float x, float y, float z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public Vector3F setX(float x) {
|
||||
this.x = x;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public Vector3F setY(float y) {
|
||||
this.y = y;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public Vector3F setZ(float z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Float.floatToIntBits(x);
|
||||
result = prime * result + Float.floatToIntBits(y);
|
||||
result = prime * result + Float.floatToIntBits(z);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
|
||||
if (obj instanceof Vector3F) {
|
||||
Vector3F that = (Vector3F) obj;
|
||||
if (Float.floatToIntBits(x) != Float.floatToIntBits(that.x))
|
||||
return false;
|
||||
if (Float.floatToIntBits(y) != Float.floatToIntBits(that.y))
|
||||
return false;
|
||||
if (Float.floatToIntBits(z) != Float.floatToIntBits(that.z))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Constructor<?> constructor = null;
|
||||
private static Class<?> clazz = MinecraftReflection.getMinecraftClass("Vector3f");
|
||||
|
||||
public static Class<?> getMinecraftClass() {
|
||||
return clazz;
|
||||
}
|
||||
|
||||
public static EquivalentConverter<Vector3F> getConverter() {
|
||||
return new IgnoreNullConverter<Vector3F>() {
|
||||
|
||||
@Override
|
||||
public Class<Vector3F> getSpecificType() {
|
||||
return Vector3F.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getGenericValue(Class<?> genericType, Vector3F specific) {
|
||||
if (constructor == null) {
|
||||
try {
|
||||
constructor = clazz.getConstructor(float.class, float.class, float.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to find constructor for Vector3f", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return constructor.newInstance(specific.x, specific.y, specific.z);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new RuntimeException("Failed to create new instance of Vector3f", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Vector3F getSpecificValue(Object generic) {
|
||||
StructureModifier<Float> modifier = new StructureModifier<Float>(generic.getClass())
|
||||
.withTarget(generic).withType(float.class);
|
||||
float x = modifier.read(0);
|
||||
float y = modifier.read(1);
|
||||
float z = modifier.read(2);
|
||||
return new Vector3F(x, y, z);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -149,18 +149,35 @@ public class WrappedBlockData extends AbstractWrapper {
|
||||
return new WrappedBlockData(blockData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a deep copy of the current wrapper object.
|
||||
* @return The cloned object.
|
||||
*/
|
||||
public WrappedBlockData deepClone() {
|
||||
return WrappedBlockData.createData(getType(), getData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrappedBlockData[handle=" + handle + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getType().hashCode();
|
||||
result = prime * result + getData();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o instanceof WrappedBlockData) {
|
||||
WrappedBlockData that = (WrappedBlockData) o;
|
||||
return this.getType() == that.getType();
|
||||
return this.getType() == that.getType() && getData() == that.getData();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+33
-37
@@ -1,10 +1,10 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.io.StringReader;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import com.comphenix.protocol.reflect.FieldUtils;
|
||||
import com.comphenix.protocol.reflect.FuzzyReflection;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
@@ -19,18 +19,35 @@ import com.google.common.base.Preconditions;
|
||||
public class WrappedChatComponent extends AbstractWrapper {
|
||||
private static final Class<?> SERIALIZER = MinecraftReflection.getChatSerializerClass();
|
||||
private static final Class<?> COMPONENT = MinecraftReflection.getIChatBaseComponentClass();
|
||||
private static final Class<?> GSON_CLASS = MinecraftReflection.getMinecraftGsonClass();
|
||||
|
||||
private static Object GSON = null;
|
||||
private static MethodAccessor DESERIALIZE = null;
|
||||
|
||||
private static MethodAccessor SERIALIZE_COMPONENT = null;
|
||||
private static MethodAccessor DESERIALIZE_COMPONENT = null;
|
||||
private static MethodAccessor CONSTRUCT_COMPONENT = null;
|
||||
private static ConstructorAccessor CONSTRUCT_TEXT_COMPONENT = null;
|
||||
|
||||
|
||||
static {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER);
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(SERIALIZER, true);
|
||||
|
||||
// Retrieve the correct methods
|
||||
SERIALIZE_COMPONENT = Accessors.getMethodAccessor(fuzzy.getMethodByParameters("serialize", /* a */
|
||||
String.class, new Class<?>[] { COMPONENT }));
|
||||
DESERIALIZE_COMPONENT = findDeserialize(fuzzy);
|
||||
|
||||
try {
|
||||
GSON = FieldUtils.readStaticField(fuzzy.getFieldByType("gson", GSON_CLASS), true);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw new RuntimeException("Failed to obtain GSON field", ex);
|
||||
}
|
||||
|
||||
try {
|
||||
DESERIALIZE = Accessors.getMethodAccessor(FuzzyReflection.fromClass(MinecraftReflection.getMinecraftClass("ChatDeserializer"), true)
|
||||
.getMethodByParameters("deserialize", Object.class, new Class<?>[] { GSON_CLASS, String.class, Class.class, boolean.class }));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// We'll handle it in the ComponentParser
|
||||
DESERIALIZE = null;
|
||||
}
|
||||
|
||||
// Get a component from a standard Minecraft message
|
||||
CONSTRUCT_COMPONENT = Accessors.getMethodAccessor(MinecraftReflection.getCraftChatMessage(), "fromString", String.class);
|
||||
@@ -39,23 +56,17 @@ public class WrappedChatComponent extends AbstractWrapper {
|
||||
CONSTRUCT_TEXT_COMPONENT = Accessors.getConstructorAccessor(MinecraftReflection.getChatComponentTextClass(), String.class);
|
||||
}
|
||||
|
||||
private static MethodAccessor findDeserialize(FuzzyReflection fuzzy) {
|
||||
List<Method> methods = fuzzy.getMethodListByParameters(COMPONENT, new Class<?>[] { String.class });
|
||||
if (methods.isEmpty()) {
|
||||
throw new IllegalArgumentException("Unable to find deserialize method in " + fuzzy.getSource().getName());
|
||||
private static Object deserialize(String json) {
|
||||
// Should be non-null on 1.9 and up
|
||||
if (DESERIALIZE != null) {
|
||||
return DESERIALIZE.invoke(null, GSON, json, COMPONENT, true);
|
||||
}
|
||||
|
||||
// Try to find b, we want leniency
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equals("b")) {
|
||||
return Accessors.getMethodAccessor(method);
|
||||
}
|
||||
}
|
||||
|
||||
// Oh well
|
||||
return Accessors.getMethodAccessor(methods.get(0));
|
||||
// Mock leniency behavior in 1.8
|
||||
StringReader str = new StringReader(json);
|
||||
return ComponentParser.deserialize(GSON, COMPONENT, str);
|
||||
}
|
||||
|
||||
|
||||
private transient String cache;
|
||||
|
||||
private WrappedChatComponent(Object handle, String cache) {
|
||||
@@ -79,7 +90,7 @@ public class WrappedChatComponent extends AbstractWrapper {
|
||||
* @return The chat component wrapper.
|
||||
*/
|
||||
public static WrappedChatComponent fromJson(String json) {
|
||||
return new WrappedChatComponent(DESERIALIZE_COMPONENT.invoke(null, json), json);
|
||||
return new WrappedChatComponent(deserialize(json), json);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +138,7 @@ public class WrappedChatComponent extends AbstractWrapper {
|
||||
* @param obj - the JSON that represents the new component.
|
||||
*/
|
||||
public void setJson(String obj) {
|
||||
this.handle = DESERIALIZE_COMPONENT.invoke(null, obj);
|
||||
this.handle = deserialize(obj);
|
||||
this.cache = obj;
|
||||
}
|
||||
|
||||
@@ -138,21 +149,6 @@ public class WrappedChatComponent extends AbstractWrapper {
|
||||
public WrappedChatComponent deepClone() {
|
||||
return fromJson(getJson());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (obj instanceof WrappedChatComponent) {
|
||||
return ((WrappedChatComponent) obj).handle.equals(handle);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return handle.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.comphenix.protocol.wrappers;
|
||||
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
/**
|
||||
* Allows access to a chunk coordinate.
|
||||
@@ -161,24 +160,6 @@ public class WrappedChunkCoordinate extends AbstractWrapper implements Comparabl
|
||||
return ((Comparable<Object>) handle).compareTo(other.handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (other instanceof WrappedChunkCoordinate) {
|
||||
WrappedChunkCoordinate wrapper = (WrappedChunkCoordinate) other;
|
||||
return Objects.equal(handle, wrapper.handle);
|
||||
}
|
||||
|
||||
// It's tempting to handle the ChunkCoordinate case too, but then
|
||||
// the equals() method won't be commutative, causing a.equals(b) to
|
||||
// be different to b.equals(a).
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return handle.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("ChunkCoordinate [x: %s, y: %s, z: %s]", getX(), getY(), getZ());
|
||||
|
||||
+302
-44
@@ -17,6 +17,7 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
@@ -25,6 +26,7 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.entity.Entity;
|
||||
@@ -43,9 +45,10 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.collection.ConvertedMap;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
|
||||
/**
|
||||
* Represents a DataWatcher in 1.9
|
||||
* Represents a DataWatcher in 1.8 thru 1.10
|
||||
*
|
||||
* @author dmulloy2
|
||||
*/
|
||||
@@ -108,8 +111,14 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
public WrappedDataWatcher(List<WrappedWatchableObject> objects) {
|
||||
this();
|
||||
|
||||
for (WrappedWatchableObject object : objects) {
|
||||
setObject(object.getWatcherObject(), object);
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
for (WrappedWatchableObject object : objects) {
|
||||
setObject(object.getWatcherObject(), object);
|
||||
}
|
||||
} else {
|
||||
for (WrappedWatchableObject object : objects) {
|
||||
setObject(object.getIndex(), object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +225,14 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Renamed to {@link #remove(int)}
|
||||
*/
|
||||
@Deprecated
|
||||
public WrappedWatchableObject removeObject(int index) {
|
||||
return remove(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the item at a given index.
|
||||
*
|
||||
@@ -234,7 +251,15 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
* @return True if it does, false if not
|
||||
*/
|
||||
public boolean hasIndex(int index) {
|
||||
return getMap().containsKey(index);
|
||||
return getObject(index) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set containing all the registered indexes
|
||||
* @return The set
|
||||
*/
|
||||
public Set<Integer> indexSet() {
|
||||
return getMap().keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,46 +346,73 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
* Retrieve a watchable object by index.
|
||||
*
|
||||
* @param index Index of the object to retrieve.
|
||||
* @return The watched object.
|
||||
* @return The watched object or null if it doesn't exist.
|
||||
*/
|
||||
public Object getObject(int index) {
|
||||
return getObject(new WrappedDataWatcherObject(index, null));
|
||||
return getObject(WrappedDataWatcherObject.fromIndex(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a watchable object by watcher object.
|
||||
*
|
||||
* @param object The watcher object
|
||||
* @return The watched object
|
||||
* @return The watched object or null if it doesn't exist.
|
||||
*/
|
||||
public Object getObject(WrappedDataWatcherObject object) {
|
||||
Validate.notNull(object, "Watcher object cannot be null!");
|
||||
|
||||
if (GETTER == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType);
|
||||
GETTER = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType, true);
|
||||
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
GETTER = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactType(object.getHandleType())
|
||||
.returnTypeExact(Object.class)
|
||||
.build(), "get"));
|
||||
} else {
|
||||
GETTER = Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.parameterExactType(int.class)
|
||||
.returnTypeExact(MinecraftReflection.getDataWatcherItemClass())
|
||||
.build()));
|
||||
}
|
||||
}
|
||||
|
||||
Object value = GETTER.invoke(handle, object.getHandle());
|
||||
return WrappedWatchableObject.getWrapped(value);
|
||||
try {
|
||||
Object value = GETTER.invoke(handle, object.getHandle());
|
||||
return WrappedWatchableObject.getWrapped(value);
|
||||
} catch (RuntimeException ex) {
|
||||
// Nothing exists at this index
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Object Setters
|
||||
|
||||
/**
|
||||
* Sets the DataWatcher Item at a given index to a new value.
|
||||
* Sets the DataWatcher Item at a given index to a new value. In 1.9 and up,
|
||||
* you cannot register objects without a watcher object.
|
||||
*
|
||||
* @param index Index of the object to set
|
||||
* @param value New value
|
||||
* @param update Whether or not to inform the client
|
||||
*
|
||||
* @see {@link #setObject(WrappedDataWatcherObject, Object)}
|
||||
* @see {@link #setObject(WrappedDataWatcherObject, Object, boolean)}
|
||||
* @throws IllegalArgumentException in 1.9 and up if there isn't already an
|
||||
* object at this index
|
||||
*/
|
||||
public void setObject(int index, Object value, boolean update) {
|
||||
if (MinecraftReflection.watcherObjectExists() && !hasIndex(index)) {
|
||||
throw new IllegalArgumentException("You cannot register objects without a watcher object!");
|
||||
}
|
||||
|
||||
setObject(WrappedDataWatcherObject.fromIndex(index), value, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #setObject(int, Object, boolean)}
|
||||
*/
|
||||
public void setObject(int index, Object value) {
|
||||
Validate.isTrue(hasIndex(index), "You cannot register objects without the watcher object!");
|
||||
setObject(index, null, value);
|
||||
setObject(index, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,11 +421,39 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
* @param index Index of the object to set
|
||||
* @param Serializer Serializer from {@link Serializer#get(Class)}
|
||||
* @param value New value
|
||||
* @param update Whether or not to inform the client
|
||||
*
|
||||
* @see {@link #setObject(WrappedDataWatcherObject, Object)}
|
||||
*/
|
||||
public void setObject(int index, Serializer serializer, Object value, boolean update) {
|
||||
setObject(new WrappedDataWatcherObject(index, serializer), value, update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link #setObject(int, Serializer, Object, boolean)}
|
||||
*/
|
||||
public void setObject(int index, Serializer serializer, Object value) {
|
||||
setObject(new WrappedDataWatcherObject(index, serializer), value);
|
||||
setObject(new WrappedDataWatcherObject(index, serializer), value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DataWatcher Item at a given index to a new value.
|
||||
*
|
||||
* @param index Index of the object to set
|
||||
* @param value New value
|
||||
* @param update Whether or not to inform the client
|
||||
*
|
||||
* @see {@link #setObject(int, Object, boolean)}
|
||||
*/
|
||||
public void setObject(int index, WrappedWatchableObject value, boolean update) {
|
||||
setObject(index, value.getRawValue(), update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@link #setObject(int, WrappedWatchableObject, boolean)}
|
||||
*/
|
||||
public void setObject(int index, WrappedWatchableObject value) {
|
||||
setObject(index, value.getRawValue(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -381,11 +461,19 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
*
|
||||
* @param object Associated watcher object
|
||||
* @param value Wrapped value
|
||||
* @param update Whether or not to inform the client
|
||||
*
|
||||
* @see {@link #setObject(WrappedDataWatcherObject, Object)}
|
||||
*/
|
||||
public void setObject(WrappedDataWatcherObject object, WrappedWatchableObject value, boolean update) {
|
||||
setObject(object, value.getRawValue(), update);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #setObject(WrappedDataWatcherObject, WrappedWatchableObject, boolean)}
|
||||
*/
|
||||
public void setObject(WrappedDataWatcherObject object, WrappedWatchableObject value) {
|
||||
setObject(object, value.getRawValue());
|
||||
setObject(object, value.getRawValue(), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -399,27 +487,46 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
* @throws IllegalArgumentException If the watcher object is null or must
|
||||
* have a serializer and does not have one.
|
||||
*/
|
||||
public void setObject(WrappedDataWatcherObject object, Object value) {
|
||||
public void setObject(WrappedDataWatcherObject object, Object value, boolean update) {
|
||||
Validate.notNull(object, "Watcher object cannot be null!");
|
||||
|
||||
if (SETTER == null || REGISTER == null) {
|
||||
if (SETTER == null && REGISTER == null) {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(handleType, true);
|
||||
FuzzyMethodContract contract = FuzzyMethodContract.newBuilder()
|
||||
.banModifier(Modifier.STATIC)
|
||||
.requireModifier(Modifier.PUBLIC)
|
||||
.parameterExactArray(object.getHandleType(), Object.class)
|
||||
.build();
|
||||
SETTER = Accessors.getMethodAccessor(fuzzy.getMethod(contract, "set"));
|
||||
REGISTER = Accessors.getMethodAccessor(fuzzy.getMethod(contract, "register"));
|
||||
List<Method> methods = fuzzy.getMethodList(contract);
|
||||
for (Method method : methods) {
|
||||
if (method.getName().equals("set") || method.getName().equals("watch")) {
|
||||
SETTER = Accessors.getMethodAccessor(method);
|
||||
} else {
|
||||
REGISTER = Accessors.getMethodAccessor(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap the object
|
||||
value = WrappedWatchableObject.getUnwrapped(value);
|
||||
|
||||
if (hasIndex(object.getIndex())) {
|
||||
SETTER.invoke(handle, object.getHandle(), WrappedWatchableObject.getUnwrapped(value));
|
||||
SETTER.invoke(handle, object.getHandle(), value);
|
||||
} else {
|
||||
Serializer serializer = object.getSerializer();
|
||||
Validate.notNull(serializer, "You must specify a serializer to register an object!");
|
||||
REGISTER.invoke(handle, object.getHandle(), WrappedWatchableObject.getUnwrapped(value));
|
||||
object.checkSerializer();
|
||||
REGISTER.invoke(handle, object.getHandle(), value);
|
||||
}
|
||||
|
||||
if (update) {
|
||||
getWatchableObject(object.getIndex()).setDirtyState(update);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut for {@link #setObject(WrappedDataWatcherObject, Object, boolean)}
|
||||
*/
|
||||
public void setObject(WrappedDataWatcherObject object, Object value) {
|
||||
setObject(object, value, false);
|
||||
}
|
||||
|
||||
// ---- Utility Methods
|
||||
@@ -432,8 +539,14 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
public WrappedDataWatcher deepClone() {
|
||||
WrappedDataWatcher clone = new WrappedDataWatcher(getEntity());
|
||||
|
||||
for (WrappedWatchableObject wrapper : this) {
|
||||
clone.setObject(wrapper.getWatcherObject(), wrapper);
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
for (WrappedWatchableObject wrapper : this) {
|
||||
clone.setObject(wrapper.getWatcherObject(), wrapper);
|
||||
}
|
||||
} else {
|
||||
for (WrappedWatchableObject wrapper : this) {
|
||||
clone.setObject(wrapper.getIndex(), wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
return clone;
|
||||
@@ -479,26 +592,37 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
ENTITY_FIELD.set(handle, BukkitUnwrapper.getInstance().unwrapItem(entity));
|
||||
}
|
||||
|
||||
private static final ImmutableBiMap<Class<?>, Integer> CLASS_TO_ID = new ImmutableBiMap.Builder<Class<?>, Integer>()
|
||||
.put(Byte.class, 0)
|
||||
.put(Short.class, 1)
|
||||
.put(Integer.class, 2)
|
||||
.put(Float.class, 3)
|
||||
.put(String.class, 4)
|
||||
.put(MinecraftReflection.getItemStackClass(), 5)
|
||||
.put(MinecraftReflection.getBlockPositionClass(), 6)
|
||||
.put(Vector3F.getMinecraftClass(), 7)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* No longer supported in 1.9 due to the removal of a consistent type <-> ID map.
|
||||
* Retrieves the type ID associated with a given class. No longer supported
|
||||
* in 1.9 and up due to the removal of type IDs.
|
||||
*
|
||||
* @param clazz
|
||||
* @return Null
|
||||
* @param clazz Class to find ID for
|
||||
* @return The ID, or null if not found
|
||||
*/
|
||||
@Deprecated
|
||||
public static Integer getTypeID(Class<?> clazz) {
|
||||
return null;
|
||||
return CLASS_TO_ID.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* No longer supported in 1.9 due to the removal of a consistent type <-> ID map.
|
||||
* Retrieves the class associated with a given type ID. No longer
|
||||
* supported in 1.9 and up due to the removal of type IDs.
|
||||
*
|
||||
* @param typeID
|
||||
* @return Null
|
||||
* @param typeID ID to find Class for
|
||||
* @return The Class, or null if not found
|
||||
*/
|
||||
@Deprecated
|
||||
public static Class<?> getTypeClass(int typeID) {
|
||||
return null;
|
||||
return CLASS_TO_ID.inverse().get(typeID);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -544,12 +668,16 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
*
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public static class WrappedDataWatcherObject extends AbstractWrapper {
|
||||
public static class WrappedDataWatcherObject {
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherObjectClass();
|
||||
private static ConstructorAccessor constructor = null;
|
||||
private static MethodAccessor getSerializer = null;
|
||||
|
||||
private final StructureModifier<Object> modifier;
|
||||
private StructureModifier<Object> modifier;
|
||||
private Object handle;
|
||||
|
||||
protected WrappedDataWatcherObject() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new watcher object from a NMS handle.
|
||||
@@ -557,9 +685,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
* @param handle The handle
|
||||
*/
|
||||
public WrappedDataWatcherObject(Object handle) {
|
||||
super(HANDLE_TYPE);
|
||||
|
||||
setHandle(handle);
|
||||
this.handle = handle;
|
||||
this.modifier = new StructureModifier<Object>(HANDLE_TYPE).withTarget(handle);
|
||||
}
|
||||
|
||||
@@ -573,6 +699,14 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
this(newHandle(index, serializer));
|
||||
}
|
||||
|
||||
static WrappedDataWatcherObject fromIndex(int index) {
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
return new WrappedDataWatcherObject(index, null);
|
||||
} else {
|
||||
return new DummyWatcherObject(index);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object newHandle(int index, Serializer serializer) {
|
||||
if (constructor == null) {
|
||||
constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]);
|
||||
@@ -616,6 +750,18 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
}
|
||||
}
|
||||
|
||||
public void checkSerializer() {
|
||||
Validate.notNull(getSerializer(), "You must specify a serializer to register an object!");
|
||||
}
|
||||
|
||||
public Object getHandle() {
|
||||
return handle;
|
||||
}
|
||||
|
||||
public Class<?> getHandleType() {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataWatcherObject[index=" + getIndex() + ", serializer=" + getSerializer() + "]";
|
||||
@@ -624,7 +770,6 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null) return false;
|
||||
|
||||
if (obj instanceof WrappedDataWatcherObject) {
|
||||
WrappedDataWatcherObject other = (WrappedDataWatcherObject) obj;
|
||||
@@ -633,6 +778,57 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return handle.hashCode();
|
||||
}
|
||||
}
|
||||
|
||||
private static class DummyWatcherObject extends WrappedDataWatcherObject {
|
||||
private final int index;
|
||||
|
||||
public DummyWatcherObject(int index) {
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializer getSerializer() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getHandle() {
|
||||
return getIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getHandleType() {
|
||||
return int.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSerializer() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null) return false;
|
||||
|
||||
if (obj instanceof DummyWatcherObject) {
|
||||
DummyWatcherObject that = (DummyWatcherObject) obj;
|
||||
return this.index == that.index;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -768,7 +964,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
* @return The serializer, or null if none exists
|
||||
*/
|
||||
public static Serializer fromHandle(Object handle) {
|
||||
Validate.notNull("Handle cannot be null!");
|
||||
Validate.notNull("handle cannot be null!");
|
||||
initialize();
|
||||
|
||||
for (Serializer serializer : REGISTRY) {
|
||||
@@ -820,5 +1016,67 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Helper methods
|
||||
|
||||
/**
|
||||
* Gets the serializer for IChatBaseComponents
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getChatComponentSerializer() {
|
||||
return get(MinecraftReflection.getIChatBaseComponentClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serializer for ItemStacks
|
||||
* @param optional If true, objects <b>must</b> be wrapped in an {@link Optional}
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getItemStackSerializer(boolean optional) {
|
||||
return get(MinecraftReflection.getItemStackClass(), optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serializer for BlockData
|
||||
* @param optional If true, objects <b>must</b> be wrapped in an {@link Optional}
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getBlockDataSerializer(boolean optional) {
|
||||
return get(MinecraftReflection.getIBlockDataClass(), optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serializer for Vector3Fs
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getVectorSerializer() {
|
||||
return get(Vector3F.getMinecraftClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serializer for BlockPositions
|
||||
* @param optional If true, objects <b>must</b> be wrapped in an {@link Optional}
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getBlockPositionSerializer(boolean optional) {
|
||||
return get(MinecraftReflection.getBlockPositionClass(), optional);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serializer for Directions
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getDirectionSerializer() {
|
||||
return get(EnumWrappers.getDirectionClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the serializer for UUIDs
|
||||
* @param optional If true, objects <b>must</b> be wrapped in an {@link Optional}
|
||||
* @return The serializer
|
||||
*/
|
||||
public static Serializer getUUIDSerializer(boolean optional) {
|
||||
return get(UUID.class, optional);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -19,14 +15,13 @@ import org.bukkit.Server;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.ProtocolLibrary;
|
||||
import com.comphenix.protocol.ProtocolManager;
|
||||
import com.comphenix.protocol.injector.BukkitUnwrapper;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftProtocolVersion;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
@@ -34,25 +29,18 @@ import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.base64.Base64;
|
||||
|
||||
/**
|
||||
* Represents a server ping packet data.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class WrappedServerPing extends AbstractWrapper {
|
||||
/**
|
||||
* Lookup of Minecraft versions and ping version numbers.
|
||||
*/
|
||||
private static ImmutableMap<MinecraftVersion, Integer> VERSION_NUMBERS = ImmutableMap.<MinecraftVersion, Integer>builder()
|
||||
.put(MinecraftVersion.WORLD_UPDATE, 4)
|
||||
.put(MinecraftVersion.SKIN_UPDATE, 5)
|
||||
.put(MinecraftVersion.BOUNTIFUL_UPDATE, 47)
|
||||
.build();
|
||||
private static MinecraftVersion LAST_VERSION = MinecraftVersion.BOUNTIFUL_UPDATE;
|
||||
|
||||
private static Class<?> GAME_PROFILE = MinecraftReflection.getGameProfileClass();
|
||||
private static Class<?> GAME_PROFILE_ARRAY = MinecraftReflection.getArrayClass(GAME_PROFILE);
|
||||
|
||||
@@ -101,7 +89,7 @@ public class WrappedServerPing extends AbstractWrapper {
|
||||
/**
|
||||
* Construct a new server ping initialized with a zero player count, and zero maximum.
|
||||
* <p>
|
||||
* Note that the version string is set to 1.8.
|
||||
* Note that the version string is set to 1.9.4.
|
||||
*/
|
||||
public WrappedServerPing() {
|
||||
super(MinecraftReflection.getServerPingClass());
|
||||
@@ -129,14 +117,8 @@ public class WrappedServerPing extends AbstractWrapper {
|
||||
* Reset the version string to the default state.
|
||||
*/
|
||||
protected void resetVersion() {
|
||||
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
|
||||
MinecraftVersion minecraftVersion = LAST_VERSION;
|
||||
|
||||
// Fetch the latest known version
|
||||
if (manager != null) {
|
||||
minecraftVersion = manager.getMinecraftVersion();
|
||||
}
|
||||
version = VERSION_CONSTRUCTOR.invoke(minecraftVersion.toString(), VERSION_NUMBERS.get(minecraftVersion));
|
||||
MinecraftVersion minecraftVersion = MinecraftVersion.getCurrentVersion();
|
||||
version = VERSION_CONSTRUCTOR.invoke(minecraftVersion.toString(), MinecraftProtocolVersion.getCurrentVersion());
|
||||
VERSION.set(handle, version);
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -132,15 +132,16 @@ public class WrappedSignedProperty extends AbstractWrapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object){
|
||||
public boolean equals(Object object) {
|
||||
if (object == this) return true;
|
||||
|
||||
if (object instanceof WrappedSignedProperty) {
|
||||
if (!super.equals(object))
|
||||
return false;
|
||||
WrappedSignedProperty that = (WrappedSignedProperty) object;
|
||||
return Objects.equal(this.getName(), that.getName())
|
||||
&& Objects.equal(this.getValue(), that.getValue())
|
||||
&& Objects.equal(this.getSignature(), that.getSignature());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,21 +82,4 @@ public class WrappedStatistic extends AbstractWrapper {
|
||||
public String toString() {
|
||||
return String.valueOf(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return handle.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
|
||||
if (obj instanceof WrappedGameProfile) {
|
||||
WrappedStatistic other = (WrappedStatistic) obj;
|
||||
return handle.equals(other.handle);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+150
-91
@@ -16,27 +16,33 @@
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static com.comphenix.protocol.utility.MinecraftReflection.is;
|
||||
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.Accessors;
|
||||
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.Serializer;
|
||||
import com.comphenix.protocol.wrappers.WrappedDataWatcher.WrappedDataWatcherObject;
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
/**
|
||||
* Represents a DataWatcher Item in 1.9.
|
||||
* Represents a DataWatcher Item in 1.8 thru 1.10.
|
||||
* @author dmulloy2
|
||||
*/
|
||||
|
||||
public class WrappedWatchableObject extends AbstractWrapper {
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getDataWatcherItemClass();
|
||||
private static Integer VALUE_INDEX = null;
|
||||
|
||||
private static ConstructorAccessor constructor;
|
||||
|
||||
private final StructureModifier<Object> modifier;
|
||||
|
||||
/**
|
||||
* Constructs a wrapped watchable object around an existing NMS data watcher item.
|
||||
* Constructs a DataWatcher Item wrapper from an existing NMS data watcher item.
|
||||
* @param handle Data watcher item
|
||||
*/
|
||||
public WrappedWatchableObject(Object handle) {
|
||||
@@ -46,7 +52,18 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a wrapped watchable object with a given watcher object and initial value.
|
||||
* Constructs a DataWatcher Item wrapper from a given index and initial value.
|
||||
* <p>
|
||||
* Not recommended in 1.9 and up.
|
||||
* @param index Index of the Item
|
||||
* @param value Initial value
|
||||
*/
|
||||
public WrappedWatchableObject(int index, Object value) {
|
||||
this(newHandle(WrappedDataWatcherObject.fromIndex(index), value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a DataWatcher Item wrapper from a given watcher object and initial value.
|
||||
* @param watcherObject Watcher object
|
||||
* @param value Initial value
|
||||
*/
|
||||
@@ -59,7 +76,12 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
constructor = Accessors.getConstructorAccessor(HANDLE_TYPE.getConstructors()[0]);
|
||||
}
|
||||
|
||||
return constructor.invoke(watcherObject.getHandle(), value);
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
return constructor.invoke(watcherObject.getHandle(), value);
|
||||
} else {
|
||||
// new WatchableObject(classId, index, value)
|
||||
return constructor.invoke(WrappedDataWatcher.getTypeID(value.getClass()), watcherObject.getIndex(), value);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Getter methods
|
||||
@@ -77,7 +99,11 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
* @return The index
|
||||
*/
|
||||
public int getIndex() {
|
||||
return getWatcherObject().getIndex();
|
||||
if (MinecraftReflection.watcherObjectExists()) {
|
||||
return getWatcherObject().getIndex();
|
||||
}
|
||||
|
||||
return modifier.<Integer>withType(int.class).read(1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,44 +119,11 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
* @return Raw value
|
||||
*/
|
||||
public Object getRawValue() {
|
||||
return modifier.readSafely(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the wrapped object value, if needed.
|
||||
*
|
||||
* @param value - the raw NMS object to wrap.
|
||||
* @return The wrapped object.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
static Object getWrapped(Object value) {
|
||||
// Handle the special cases
|
||||
if (MinecraftReflection.isItemStack(value)) {
|
||||
return BukkitConverters.getItemStackConverter().getSpecific(value);
|
||||
} else if (MinecraftReflection.isChunkCoordinates(value)) {
|
||||
return new WrappedChunkCoordinate((Comparable) value);
|
||||
} else {
|
||||
return value;
|
||||
if (VALUE_INDEX == null) {
|
||||
VALUE_INDEX = MinecraftReflection.watcherObjectExists() ? 1 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the wrapped type, if needed.
|
||||
*
|
||||
* @param wrapped - the wrapped class type.
|
||||
* @return The wrapped class type.
|
||||
*/
|
||||
static Class<?> getWrappedType(Class<?> unwrapped) {
|
||||
if (unwrapped.equals(MinecraftReflection.getChunkPositionClass()))
|
||||
return ChunkPosition.class;
|
||||
else if (unwrapped.equals(MinecraftReflection.getBlockPositionClass()))
|
||||
return BlockPosition.class;
|
||||
else if (unwrapped.equals(MinecraftReflection.getChunkCoordinatesClass()))
|
||||
return WrappedChunkCoordinate.class;
|
||||
else if (unwrapped.equals(MinecraftReflection.getItemStackClass()))
|
||||
return ItemStack.class;
|
||||
else
|
||||
return unwrapped;
|
||||
return modifier.readSafely(VALUE_INDEX);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +132,11 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
* @param updateClient Whether or not to update the client
|
||||
*/
|
||||
public void setValue(Object value, boolean updateClient) {
|
||||
modifier.write(1, getUnwrapped(value));
|
||||
if (VALUE_INDEX == null) {
|
||||
VALUE_INDEX = MinecraftReflection.watcherObjectExists() ? 1 : 2;
|
||||
}
|
||||
|
||||
modifier.write(VALUE_INDEX, getUnwrapped(value));
|
||||
|
||||
if (updateClient) {
|
||||
setDirtyState(true);
|
||||
@@ -154,51 +151,12 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
setValue(value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw NMS value.
|
||||
*
|
||||
* @param wrapped - the wrapped position.
|
||||
* @return The raw NMS object.
|
||||
*/
|
||||
static Object getUnwrapped(Object wrapped) {
|
||||
// Convert special cases
|
||||
if (wrapped instanceof ChunkPosition)
|
||||
return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped);
|
||||
else if (wrapped instanceof BlockPosition)
|
||||
return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped);
|
||||
else if (wrapped instanceof WrappedChunkCoordinate)
|
||||
return ((WrappedChunkCoordinate) wrapped).getHandle();
|
||||
else if (wrapped instanceof ItemStack)
|
||||
return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped);
|
||||
else
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the unwrapped type, if needed.
|
||||
*
|
||||
* @param wrapped - the unwrapped class type.
|
||||
* @return The unwrapped class type.
|
||||
*/
|
||||
static Class<?> getUnwrappedType(Class<?> wrapped) {
|
||||
if (wrapped.equals(ChunkPosition.class))
|
||||
return MinecraftReflection.getChunkPositionClass();
|
||||
else if (wrapped.equals(BlockPosition.class))
|
||||
return MinecraftReflection.getBlockPositionClass();
|
||||
else if (wrapped.equals(WrappedChunkCoordinate.class))
|
||||
return MinecraftReflection.getChunkCoordinatesClass();
|
||||
else if (ItemStack.class.isAssignableFrom(wrapped))
|
||||
return MinecraftReflection.getItemStackClass();
|
||||
else
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not the value must be synchronized with the client.
|
||||
* @return True if it must, false if not
|
||||
*/
|
||||
public boolean getDirtyState() {
|
||||
return (boolean) modifier.read(2);
|
||||
return modifier.<Boolean>withType(boolean.class).read(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,27 +164,128 @@ public class WrappedWatchableObject extends AbstractWrapper {
|
||||
* @param dirty New state
|
||||
*/
|
||||
public void setDirtyState(boolean dirty) {
|
||||
modifier.write(2, dirty);
|
||||
modifier.<Boolean>withType(boolean.class).write(0, dirty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) return true;
|
||||
if (obj == null) return false;
|
||||
|
||||
if (obj instanceof WrappedWatchableObject) {
|
||||
// watcher object, value, dirty state
|
||||
WrappedWatchableObject other = (WrappedWatchableObject) obj;
|
||||
return getWatcherObject().equals(other.getWatcherObject())
|
||||
&& getRawValue().equals(other.getRawValue())
|
||||
&& getDirtyState() == other.getDirtyState();
|
||||
WrappedWatchableObject that = (WrappedWatchableObject) obj;
|
||||
return this.getIndex() == that.getIndex() &&
|
||||
this.getRawValue().equals(that.getRawValue()) &&
|
||||
this.getDirtyState() == that.getDirtyState();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + getIndex();
|
||||
result = prime * result + getRawValue().hashCode();
|
||||
result = prime * result + (getDirtyState() ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataWatcherItem[object=" + getWatcherObject() + ", value=" + getValue() + ", dirty=" + getDirtyState() + "]";
|
||||
return "DataWatcherItem[index=" + getIndex() + ", value=" + getValue() + ", dirty=" + getDirtyState() + "]";
|
||||
}
|
||||
|
||||
// ---- Wrapping
|
||||
|
||||
/**
|
||||
* Retrieve the wrapped object value, if needed. All non-primitive objects
|
||||
* with {@link Serializer}s should be covered by this.
|
||||
*
|
||||
* @param value - the raw NMS object to wrap.
|
||||
* @return The wrapped object.
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
static Object getWrapped(Object value) {
|
||||
// Handle watcher items first
|
||||
if (is(MinecraftReflection.getDataWatcherItemClass(), value)) {
|
||||
return getWrapped(new WrappedWatchableObject(value).getRawValue());
|
||||
}
|
||||
|
||||
// Then deal with optionals
|
||||
if (value instanceof Optional) {
|
||||
Optional<?> optional = (Optional<?>) value;
|
||||
if (optional.isPresent()) {
|
||||
return Optional.of(getWrapped(optional.get()));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
// Current supported classes
|
||||
if (is(MinecraftReflection.getIChatBaseComponentClass(), value)) {
|
||||
return WrappedChatComponent.fromHandle(value);
|
||||
} else if (is(MinecraftReflection.getItemStackClass(), value)) {
|
||||
return BukkitConverters.getItemStackConverter().getSpecific(value);
|
||||
} else if (is(MinecraftReflection.getIBlockDataClass(), value)) {
|
||||
return BukkitConverters.getWrappedBlockDataConverter().getSpecific(value);
|
||||
} else if (is (Vector3F.getMinecraftClass(), value)) {
|
||||
return Vector3F.getConverter().getSpecific(value);
|
||||
} else if (is(MinecraftReflection.getBlockPositionClass(), value)) {
|
||||
return BlockPosition.getConverter().getSpecific(value);
|
||||
} else if (is(EnumWrappers.getDirectionClass(), value)) {
|
||||
return EnumWrappers.getDirectionConverter().getSpecific(value);
|
||||
}
|
||||
|
||||
// Legacy classes
|
||||
if (is(MinecraftReflection.getChunkCoordinatesClass(), value)) {
|
||||
return new WrappedChunkCoordinate((Comparable) value);
|
||||
} else if (is(MinecraftReflection.getChunkPositionClass(), value)) {
|
||||
return ChunkPosition.getConverter().getSpecific(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the raw NMS value.
|
||||
*
|
||||
* @param wrapped - the wrapped position.
|
||||
* @return The raw NMS object.
|
||||
*/
|
||||
// Must be kept in sync with getWrapped!
|
||||
static Object getUnwrapped(Object wrapped) {
|
||||
if (wrapped instanceof Optional) {
|
||||
Optional<?> optional = (Optional<?>) wrapped;
|
||||
if (optional.isPresent()) {
|
||||
return Optional.of(getUnwrapped(optional.get()));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
}
|
||||
|
||||
// Current supported classes
|
||||
if (wrapped instanceof WrappedChatComponent) {
|
||||
return ((WrappedChatComponent) wrapped).getHandle();
|
||||
} else if (wrapped instanceof ItemStack) {
|
||||
return BukkitConverters.getItemStackConverter().getGeneric(MinecraftReflection.getItemStackClass(), (ItemStack) wrapped);
|
||||
} else if (wrapped instanceof WrappedBlockData) {
|
||||
return BukkitConverters.getWrappedBlockDataConverter().getGeneric(MinecraftReflection.getIBlockDataClass(), (WrappedBlockData) wrapped);
|
||||
} else if (wrapped instanceof Vector3F) {
|
||||
return Vector3F.getConverter().getGeneric(Vector3F.getMinecraftClass(), (Vector3F) wrapped);
|
||||
} else if (wrapped instanceof BlockPosition) {
|
||||
return BlockPosition.getConverter().getGeneric(MinecraftReflection.getBlockPositionClass(), (BlockPosition) wrapped);
|
||||
} else if (wrapped instanceof Direction) {
|
||||
return EnumWrappers.getDirectionConverter().getGeneric(EnumWrappers.getDirectionClass(), (Direction) wrapped);
|
||||
}
|
||||
|
||||
// Legacy classes
|
||||
if (wrapped instanceof ChunkPosition) {
|
||||
return ChunkPosition.getConverter().getGeneric(MinecraftReflection.getChunkPositionClass(), (ChunkPosition) wrapped);
|
||||
} else if (wrapped instanceof WrappedChunkCoordinate) {
|
||||
return ((WrappedChunkCoordinate) wrapped).getHandle();
|
||||
}
|
||||
|
||||
return wrapped;
|
||||
}
|
||||
}
|
||||
+29
-24
@@ -46,7 +46,7 @@ class TileEntityAccessor<T extends BlockState> {
|
||||
private boolean writeDetected;
|
||||
private boolean readDetected;
|
||||
|
||||
private TileEntityAccessor() {
|
||||
TileEntityAccessor() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@@ -59,27 +59,30 @@ class TileEntityAccessor<T extends BlockState> {
|
||||
if (tileEntityField != null) {
|
||||
this.tileEntityField = tileEntityField;
|
||||
Class<?> type = tileEntityField.getField().getType();
|
||||
|
||||
// Possible read/write methods
|
||||
try {
|
||||
findMethodsUsingASM();
|
||||
} catch (IOException ex1) {
|
||||
try {
|
||||
// Much slower though
|
||||
findMethodUsingCGLib(state);
|
||||
} catch (Exception ex2) {
|
||||
throw new RuntimeException("Cannot find read/write methods in " + type, ex2);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we found them
|
||||
if (readCompound == null)
|
||||
throw new RuntimeException("Unable to find read method in " + type);
|
||||
if (writeCompound == null)
|
||||
throw new RuntimeException("Unable to find write method in " + type);
|
||||
findMethods(type, state);
|
||||
}
|
||||
}
|
||||
|
||||
void findMethods(Class<?> type, T state) {
|
||||
// Possible read/write methods
|
||||
try {
|
||||
findMethodsUsingASM();
|
||||
} catch (IOException ex1) {
|
||||
try {
|
||||
// Much slower though
|
||||
findMethodUsingCGLib(state);
|
||||
} catch (Exception ex2) {
|
||||
throw new RuntimeException("Cannot find read/write methods in " + type, ex2);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure we found them
|
||||
if (readCompound == null)
|
||||
throw new RuntimeException("Unable to find read method in " + type);
|
||||
if (writeCompound == null)
|
||||
throw new RuntimeException("Unable to find write method in " + type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the read/write methods in TileEntity.
|
||||
* @throws IOException If we cannot find these methods.
|
||||
@@ -90,7 +93,7 @@ class TileEntityAccessor<T extends BlockState> {
|
||||
final ClassReader reader = new ClassReader(tileEntityClass.getCanonicalName());
|
||||
|
||||
final String tagCompoundName = getJarName(MinecraftReflection.getNBTCompoundClass());
|
||||
final String expectedDesc = "(L" + tagCompoundName + ";)V";
|
||||
final String expectedDesc = "(L" + tagCompoundName + ";)";
|
||||
|
||||
reader.accept(new EmptyClassVisitor() {
|
||||
@Override
|
||||
@@ -98,7 +101,7 @@ class TileEntityAccessor<T extends BlockState> {
|
||||
final String methodName = name;
|
||||
|
||||
// Detect read/write calls to NBTTagCompound
|
||||
if (expectedDesc.equals(desc)) {
|
||||
if (desc.startsWith(expectedDesc)) {
|
||||
return new EmptyMethodVisitor() {
|
||||
private int readMethods;
|
||||
private int writeMethods;
|
||||
@@ -106,9 +109,9 @@ class TileEntityAccessor<T extends BlockState> {
|
||||
@Override
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||
// This must be a virtual call on NBTTagCompound that accepts a String
|
||||
if (opcode == Opcodes.INVOKEVIRTUAL &&
|
||||
tagCompoundName.equals(owner) &&
|
||||
desc.startsWith("(Ljava/lang/String")) {
|
||||
if (opcode == Opcodes.INVOKEVIRTUAL
|
||||
&& tagCompoundName.equals(owner)
|
||||
&& desc.startsWith("(Ljava/lang/String")) {
|
||||
|
||||
// Is this a write call?
|
||||
if (desc.endsWith(")V")) {
|
||||
@@ -126,10 +129,12 @@ class TileEntityAccessor<T extends BlockState> {
|
||||
} else if (writeMethods > readMethods) {
|
||||
writeCompound = Accessors.getMethodAccessor(tileEntityClass, methodName, nbtCompoundClass);
|
||||
}
|
||||
|
||||
super.visitEnd();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}, 0);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>ProtocolLib</artifactId>
|
||||
<name>ProtocolLib</name>
|
||||
<version>4.0.1</version>
|
||||
<version>4.2.1</version>
|
||||
|
||||
<description>Provides read/write access to the Minecraft protocol.</description>
|
||||
<url>http://www.spigotmc.org/resources/protocollib.1997/</url>
|
||||
@@ -19,6 +19,7 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.build.number></project.build.number>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -87,11 +88,11 @@
|
||||
<manifestEntries>
|
||||
<Main-Class>com.comphenix.protocol.Application</Main-Class>
|
||||
<Implementation-Title>ProtocolLib</Implementation-Title>
|
||||
<Implementation-Version>${project.version}${project.build.number}</Implementation-Version>
|
||||
<Implementation-Version>${project.fullVersion}</Implementation-Version>
|
||||
<Implementation-Vendor>dmulloy2</Implementation-Vendor>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
<finalName>ProtocolLib</finalName>
|
||||
<finalName>${project.name}</finalName>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -121,6 +122,7 @@
|
||||
</activation>
|
||||
<properties>
|
||||
<project.build.number>-b${env.BUILD_NUMBER}</project.build.number>
|
||||
<project.fullVersion>${project.version}${project.build.number}</project.fullVersion>
|
||||
</properties>
|
||||
</profile>
|
||||
|
||||
@@ -132,6 +134,9 @@
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<properties>
|
||||
<project.fullVersion>${project.version}</project.fullVersion>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
@@ -162,6 +167,7 @@
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<!-- TODO: Look into signing releases
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-gpg-plugin</artifactId>
|
||||
@@ -176,6 +182,7 @@
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
-->
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
@@ -222,7 +229,7 @@
|
||||
<dependency>
|
||||
<groupId>com.comphenix.protocol</groupId>
|
||||
<artifactId>ProtocolLib-API</artifactId>
|
||||
<version>4.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- Included with Minecraft
|
||||
<dependency>
|
||||
@@ -234,13 +241,13 @@
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.9.4-R0.1-SNAPSHOT</version>
|
||||
<version>1.11.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot</artifactId>
|
||||
<version>1.9.4-R0.1-SNAPSHOT</version>
|
||||
<version>1.11.2-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2012 Kristian S. Stangeland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* Ignore this class.
|
||||
*
|
||||
* @author Kristian
|
||||
*/
|
||||
public class Application {
|
||||
private static Thread mainThread;
|
||||
private static boolean primaryMethod = true;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// For now, though we might consider making a proper application
|
||||
System.out.println("This is a Bukkit library. Place it in the plugin-folder and restart the server!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if we are running on the main thread.
|
||||
* @return TRUE if we are, FALSE otherwise.
|
||||
*/
|
||||
public static boolean isPrimaryThread() {
|
||||
if (primaryMethod) {
|
||||
try {
|
||||
return Bukkit.isPrimaryThread();
|
||||
} catch (LinkageError e) {
|
||||
primaryMethod = false;
|
||||
}
|
||||
}
|
||||
// Fallback method
|
||||
return Thread.currentThread().equals(mainThread);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the calling thread as the primary thread.
|
||||
*/
|
||||
static void registerPrimaryThread() {
|
||||
mainThread = Thread.currentThread();
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
@@ -252,16 +253,34 @@ class CommandProtocol extends CommandBase {
|
||||
pw.println();
|
||||
|
||||
Set<PacketListener> listeners = manager.getPacketListeners();
|
||||
if (listeners.size() > 0) {
|
||||
Set<Plugin> plugins = new HashSet<>();
|
||||
|
||||
if (!listeners.isEmpty()) {
|
||||
pw.println("Listeners:");
|
||||
|
||||
for (PacketListener listener : listeners) {
|
||||
pw.println(DetailedErrorReporter.getStringDescription(listener));
|
||||
|
||||
Plugin plugin = listener.getPlugin();
|
||||
if (plugin != null) {
|
||||
plugins.add(plugin);
|
||||
} else {
|
||||
pw.println("(Missing plugin!)");
|
||||
}
|
||||
}
|
||||
|
||||
pw.println();
|
||||
} else {
|
||||
pw.println("No listeners");
|
||||
}
|
||||
|
||||
if (!plugins.isEmpty()) {
|
||||
pw.println("Plugins Using ProtocolLib:");
|
||||
for (Plugin plugin : plugins) {
|
||||
pw.println(plugin.getName() + " by " + plugin.getDescription().getAuthors());
|
||||
}
|
||||
}
|
||||
|
||||
sender.sendMessage("Data dump written to " + file.getAbsolutePath());
|
||||
} catch (IOException ex) {
|
||||
ProtocolLogger.log(Level.SEVERE, "Failed to create dump:", ex);
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2017 Dan Mulloy
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.MessageFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.FileHandler;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.Handler;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.commons.io.HexDump;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.events.ListeningWhitelist;
|
||||
import com.comphenix.protocol.events.PacketEvent;
|
||||
import com.comphenix.protocol.events.PacketListener;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
import com.google.common.base.Charsets;
|
||||
|
||||
/**
|
||||
* Logs packets to a given stream
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketLogging implements CommandExecutor, PacketListener {
|
||||
public static final String NAME = "packetlog";
|
||||
|
||||
private List<PacketType> sendingTypes = new ArrayList<>();
|
||||
private List<PacketType> receivingTypes = new ArrayList<>();
|
||||
|
||||
private ListeningWhitelist sendingWhitelist;
|
||||
private ListeningWhitelist receivingWhitelist;
|
||||
|
||||
private Logger fileLogger;
|
||||
private LogLocation location = LogLocation.FILE;
|
||||
|
||||
private final ProtocolManager manager;
|
||||
private final Plugin plugin;
|
||||
|
||||
PacketLogging(Plugin plugin, ProtocolManager manager) {
|
||||
this.plugin = plugin;
|
||||
this.manager = manager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
PacketType type = null;
|
||||
|
||||
try {
|
||||
if (args.length > 2) {
|
||||
Protocol protocol;
|
||||
|
||||
try {
|
||||
protocol = Protocol.valueOf(args[0].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown protocol " + args[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
Sender pSender;
|
||||
|
||||
try {
|
||||
pSender = Sender.valueOf(args[1].toUpperCase());
|
||||
} catch (IllegalArgumentException ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown sender: " + args[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
try { // Try IDs first
|
||||
int id = Integer.parseInt(args[2]);
|
||||
type = PacketType.findCurrent(protocol, pSender, id);
|
||||
} catch (NumberFormatException ex) { // Check packet names
|
||||
String name = args[2];
|
||||
outer: for (PacketType packet : PacketType.values()) {
|
||||
if (packet.getProtocol() == protocol && packet.getSender() == pSender) {
|
||||
if (packet.name().equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break outer;
|
||||
}
|
||||
for (String className : packet.getClassNames()) {
|
||||
if (className.equalsIgnoreCase(name)) {
|
||||
type = packet;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IllegalArgumentException ex) { // RIP
|
||||
type = null;
|
||||
}
|
||||
|
||||
if (type == null) {
|
||||
sender.sendMessage(ChatColor.RED + "Unknown packet: " + args[2]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length > 3) {
|
||||
if (args[3].equalsIgnoreCase("console")) {
|
||||
this.location = LogLocation.CONSOLE;
|
||||
} else {
|
||||
this.location = LogLocation.FILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pSender == Sender.CLIENT) {
|
||||
if (receivingTypes.contains(type)) {
|
||||
receivingTypes.remove(type);
|
||||
} else {
|
||||
receivingTypes.add(type);
|
||||
}
|
||||
} else {
|
||||
if (sendingTypes.contains(type)) {
|
||||
sendingTypes.remove(type);
|
||||
} else {
|
||||
sendingTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
startLogging();
|
||||
sender.sendMessage(ChatColor.GREEN + "Now logging " + type.getPacketClass().getSimpleName());
|
||||
return true;
|
||||
}
|
||||
|
||||
sender.sendMessage(ChatColor.RED + "Invalid syntax: /packetlog <protocol> <sender> <packet> [location]");
|
||||
return true;
|
||||
} catch (Throwable ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Failed to parse command: " + ex.toString());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private void startLogging() {
|
||||
manager.removePacketListener(this);
|
||||
|
||||
if (sendingTypes.isEmpty() && receivingTypes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendingWhitelist = ListeningWhitelist.newBuilder().types(sendingTypes).build();
|
||||
this.receivingWhitelist = ListeningWhitelist.newBuilder().types(receivingTypes).build();
|
||||
|
||||
// Setup the file logger if it hasn't been already
|
||||
if (location == LogLocation.FILE && fileLogger == null) {
|
||||
fileLogger = Logger.getLogger("ProtocolLib-FileLogging");
|
||||
|
||||
for (Handler handler : fileLogger.getHandlers())
|
||||
fileLogger.removeHandler(handler);
|
||||
fileLogger.setUseParentHandlers(false);
|
||||
|
||||
try {
|
||||
File logFile = new File(plugin.getDataFolder(), "log.log");
|
||||
FileHandler handler = new FileHandler(logFile.getAbsolutePath(), true);
|
||||
handler.setFormatter(new LogFormatter());
|
||||
fileLogger.addHandler(handler);
|
||||
} catch (IOException ex) {
|
||||
plugin.getLogger().log(Level.SEVERE, "Failed to obtain log file:", ex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
manager.addPacketListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSending(PacketEvent event) {
|
||||
log(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceiving(PacketEvent event) {
|
||||
log(event);
|
||||
}
|
||||
|
||||
// Here's where the magic happens
|
||||
|
||||
private static String hexDump(byte[] bytes) throws IOException {
|
||||
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||
HexDump.dump(bytes, 0, output, 0);
|
||||
return new String(output.toByteArray(), Charsets.UTF_8);
|
||||
}
|
||||
}
|
||||
|
||||
private void log(PacketEvent event) {
|
||||
try {
|
||||
byte[] bytes = WirePacket.bytesFromPacket(event.getPacket());
|
||||
String hexDump = hexDump(bytes);
|
||||
|
||||
if (location == LogLocation.FILE) {
|
||||
fileLogger.log(Level.INFO, event.getPacketType() + ":");
|
||||
fileLogger.log(Level.INFO, hexDump);
|
||||
fileLogger.log(Level.INFO, "");
|
||||
} else {
|
||||
System.out.println(event.getPacketType() + ":");
|
||||
System.out.println(hexDump);
|
||||
System.out.println();
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to log packet " + event.getPacketType() + ":", ex);
|
||||
plugin.getLogger().log(Level.WARNING, "Clearing packet logger...");
|
||||
|
||||
sendingTypes.clear();
|
||||
receivingTypes.clear();
|
||||
startLogging();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningWhitelist getSendingWhitelist() {
|
||||
return sendingWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListeningWhitelist getReceivingWhitelist() {
|
||||
return receivingWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Plugin getPlugin() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
private static enum LogLocation {
|
||||
CONSOLE,
|
||||
FILE;
|
||||
}
|
||||
|
||||
private static class LogFormatter extends Formatter {
|
||||
private static final SimpleDateFormat DATE = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||
private static final String FORMAT = "[{0}] {1}";
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
String string = formatMessage(record);
|
||||
if (string.isEmpty()) {
|
||||
return LINE_SEPARATOR;
|
||||
}
|
||||
|
||||
StringBuilder message = new StringBuilder();
|
||||
message.append(MessageFormat.format(FORMAT, DATE.format(record.getMillis()), string));
|
||||
message.append(LINE_SEPARATOR);
|
||||
return message.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import java.util.Collection;
|
||||
import java.util.Deque;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
import com.comphenix.protocol.PacketType.Protocol;
|
||||
@@ -53,7 +54,7 @@ class PacketTypeParser {
|
||||
// And finally, parse packet names if we have a protocol
|
||||
if (protocol != null) {
|
||||
for (Iterator<String> it = arguments.iterator(); it.hasNext(); ) {
|
||||
String name = it.next().toUpperCase();
|
||||
String name = it.next().toUpperCase(Locale.ENGLISH);
|
||||
Collection<PacketType> names = PacketType.fromName(name);
|
||||
|
||||
for (PacketType type : names) {
|
||||
|
||||
@@ -52,6 +52,7 @@ import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||
import com.comphenix.protocol.utility.ChatExtensions;
|
||||
import com.comphenix.protocol.utility.EnhancerFactory;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.Util;
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -89,7 +90,8 @@ public class ProtocolLib extends JavaPlugin {
|
||||
private enum ProtocolCommand {
|
||||
FILTER,
|
||||
PACKET,
|
||||
PROTOCOL
|
||||
PROTOCOL,
|
||||
LOGGING;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -142,6 +144,7 @@ public class ProtocolLib extends JavaPlugin {
|
||||
private CommandProtocol commandProtocol;
|
||||
private CommandPacket commandPacket;
|
||||
private CommandFilter commandFilter;
|
||||
private PacketLogging packetLogging;
|
||||
|
||||
// Whether or not disable is not needed
|
||||
private boolean skipDisable;
|
||||
@@ -149,10 +152,16 @@ public class ProtocolLib extends JavaPlugin {
|
||||
@Override
|
||||
public void onLoad() {
|
||||
// Logging
|
||||
logger = getLoggerSafely();
|
||||
logger = getLogger();
|
||||
ProtocolLogger.init(this);
|
||||
|
||||
Application.registerPrimaryThread();
|
||||
int java = Util.getJavaVersion();
|
||||
if (java != -1 && java < 8 && !getConfig().getBoolean("ignoreJava", false)) {
|
||||
logger.warning("Detected outdated Java version: Java " + java);
|
||||
logger.warning("It is recommended that you update to Java 8 as soon as possible.");
|
||||
logger.warning("Future versions of ProtocolLib many not support Java " + java + ".");
|
||||
logger.warning("Java 8 will allow for much faster reflection performance.");
|
||||
}
|
||||
|
||||
// Initialize enhancer factory
|
||||
EnhancerFactory.getInstance().setClassLoader(getClassLoader());
|
||||
@@ -262,6 +271,9 @@ public class ProtocolLib extends JavaPlugin {
|
||||
case PACKET:
|
||||
commandPacket = new CommandPacket(reporter, this, logger, commandFilter, protocolManager);
|
||||
break;
|
||||
case LOGGING:
|
||||
packetLogging = new PacketLogging(this, protocolManager);
|
||||
break;
|
||||
}
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
@@ -397,6 +409,7 @@ public class ProtocolLib extends JavaPlugin {
|
||||
registerCommand(CommandProtocol.NAME, commandProtocol);
|
||||
registerCommand(CommandPacket.NAME, commandPacket);
|
||||
registerCommand(CommandFilter.NAME, commandFilter);
|
||||
registerCommand(PacketLogging.NAME, packetLogging);
|
||||
|
||||
// Player login and logout events
|
||||
protocolManager.registerEvents(manager, this);
|
||||
@@ -650,26 +663,6 @@ public class ProtocolLib extends JavaPlugin {
|
||||
reporter = new BasicErrorReporter();
|
||||
}
|
||||
|
||||
// Get the Bukkit logger first, before we try to create our own
|
||||
private Logger getLoggerSafely() {
|
||||
Logger log = null;
|
||||
|
||||
try {
|
||||
log = getLogger();
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw e;
|
||||
} catch (ThreadDeath e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Use the default logger instead
|
||||
if (log == null)
|
||||
log = Logger.getLogger("Minecraft");
|
||||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the metrics instance used to measure users of this library.
|
||||
* <p>
|
||||
|
||||
+65
-84
@@ -17,17 +17,15 @@
|
||||
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
@@ -54,62 +52,44 @@ class EntityUtilities {
|
||||
private static Method scanPlayersMethod;
|
||||
|
||||
/*
|
||||
* While this function may look pretty bad, it's essentially just a reflection-warped
|
||||
* version of the following:
|
||||
*
|
||||
* @SuppressWarnings("unchecked")
|
||||
* public static void updateEntity2(Entity entity, List<Player> observers) {
|
||||
*
|
||||
* World world = entity.getWorld();
|
||||
* WorldServer worldServer = ((CraftWorld) world).getHandle();
|
||||
*
|
||||
* EntityTracker tracker = worldServer.tracker;
|
||||
* EntityTrackerEntry entry = (EntityTrackerEntry) tracker.trackedEntities.get(entity.getEntityId());
|
||||
*
|
||||
* List<EntityPlayer> nmsPlayers = getNmsPlayers(observers);
|
||||
*
|
||||
* entry.trackedPlayers.removeAll(nmsPlayers);
|
||||
* entry.scanPlayers(nmsPlayers);
|
||||
* }
|
||||
*
|
||||
* private static List<EntityPlayer> getNmsPlayers(List<Player> players) {
|
||||
* List<EntityPlayer> nsmPlayers = new ArrayList<EntityPlayer>();
|
||||
*
|
||||
* for (Player bukkitPlayer : players) {
|
||||
* CraftPlayer craftPlayer = (CraftPlayer) bukkitPlayer;
|
||||
* nsmPlayers.add(craftPlayer.getHandle());
|
||||
* }
|
||||
*
|
||||
* return nsmPlayers;
|
||||
* }
|
||||
*
|
||||
*/
|
||||
public static void updateEntity2(Entity entity, List<Player> observers) {
|
||||
EntityTrackerEntry entry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
|
||||
|
||||
List<EntityPlayer> nmsPlayers = getNmsPlayers(observers);
|
||||
|
||||
entry.trackedPlayers.removeAll(nmsPlayers);
|
||||
entry.scanPlayers(nmsPlayers);
|
||||
}
|
||||
*/
|
||||
|
||||
public static void updateEntity(Entity entity, List<Player> observers) throws FieldAccessException {
|
||||
if (entity == null || !entity.isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
//EntityTrackerEntry trackEntity = (EntityTrackerEntry) tracker.trackedEntities.get(entity.getEntityId());
|
||||
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
|
||||
if (trackerEntry == null) {
|
||||
throw new IllegalArgumentException("Cannot find entity trackers for " + entity + ".");
|
||||
}
|
||||
|
||||
if (trackedPlayersField == null) {
|
||||
// This one is fairly easy
|
||||
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
|
||||
}
|
||||
|
||||
// Phew, finally there.
|
||||
Collection<?> trackedPlayers = (Collection<?>) FieldUtils.readField(trackedPlayersField, trackerEntry, false);
|
||||
Collection<?> trackedPlayers = getTrackedPlayers(trackedPlayersField, trackerEntry);
|
||||
List<Object> nmsPlayers = unwrapBukkit(observers);
|
||||
|
||||
// trackEntity.trackedPlayers.clear();
|
||||
|
||||
trackedPlayers.removeAll(nmsPlayers);
|
||||
|
||||
// We have to rely on a NAME once again. Damn it.
|
||||
// TODO: Make sure this stays up to date with version changes - 1.9
|
||||
// TODO: Make sure this stays up to date with version changes - 1.8 - 1.10
|
||||
if (scanPlayersMethod == null) {
|
||||
scanPlayersMethod = trackerEntry.getClass().getMethod("scanPlayers", List.class);
|
||||
}
|
||||
|
||||
//trackEntity.scanPlayers(server.players);
|
||||
scanPlayersMethod.invoke(trackerEntry, nmsPlayers);
|
||||
|
||||
|
||||
scanPlayersMethod.invoke(trackerEntry, nmsPlayers);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw e;
|
||||
} catch (IllegalAccessException e) {
|
||||
@@ -130,28 +110,23 @@ class EntityUtilities {
|
||||
* @throws FieldAccessException If reflection failed.
|
||||
*/
|
||||
public static List<Player> getEntityTrackers(Entity entity) {
|
||||
if (entity == null || !entity.isValid()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
try {
|
||||
List<Player> result = new ArrayList<Player>();
|
||||
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
|
||||
|
||||
Object trackerEntry = getEntityTrackerEntry(entity.getWorld(), entity.getEntityId());
|
||||
if (trackerEntry == null) {
|
||||
throw new IllegalArgumentException("Cannot find entity trackers for " + entity + (entity.isDead() ? " - entity is dead." : "."));
|
||||
throw new IllegalArgumentException("Cannot find entity trackers for " + entity + ".");
|
||||
}
|
||||
|
||||
if (trackedPlayersField == null) {
|
||||
trackedPlayersField = FuzzyReflection.fromObject(trackerEntry).getFieldByType("java\\.util\\..*");
|
||||
}
|
||||
|
||||
Collection<?> trackedPlayers = null;
|
||||
Object value = FieldUtils.readField(trackedPlayersField, trackerEntry, false);
|
||||
|
||||
if (value instanceof Collection) {
|
||||
trackedPlayers = (Collection<?>) value;
|
||||
} else if (value instanceof Map) { // PaperSpigot
|
||||
trackedPlayers = ((Map<?, ?>) value).keySet();
|
||||
} else { // Please, no more changes
|
||||
throw new IllegalStateException("trackedPlayers field was an unknown type: expected Set or Map, but got " + value.getClass());
|
||||
}
|
||||
Collection<?> trackedPlayers = getTrackedPlayers(trackedPlayersField, trackerEntry);
|
||||
|
||||
// Wrap every player - we also ensure that the underlying tracker list is immutable
|
||||
for (Object tracker : trackedPlayers) {
|
||||
@@ -159,20 +134,38 @@ class EntityUtilities {
|
||||
result.add((Player) MinecraftReflection.getBukkitEntity(tracker));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
return result;
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Security limitation prevented access to the list of tracked players.", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the entity tracker entry given a ID.
|
||||
* @param world - world server.
|
||||
* @param entityID - entity ID.
|
||||
* @return The entity tracker entry.
|
||||
* @throws FieldAccessException
|
||||
*/
|
||||
|
||||
// Damn you, Paper
|
||||
private static Collection<?> getTrackedPlayers(Field field, Object entry) throws IllegalAccessException {
|
||||
Validate.notNull(field, "Cannot find 'trackedPlayers' field.");
|
||||
Validate.notNull(entry, "entry cannot be null!");
|
||||
|
||||
Object value = FieldUtils.readField(field, entry, false);
|
||||
|
||||
if (value instanceof Collection) {
|
||||
return (Collection<?>) value;
|
||||
} else if (value instanceof Map) {
|
||||
return ((Map<?, ?>) value).keySet();
|
||||
} else {
|
||||
// Please. No more changes.
|
||||
throw new IllegalStateException("trackedPlayers field was an unknown type: expected Collection or Map, but got " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
private static EntityTrackerEntry getEntityTrackerEntry2(World world, int entityID) {
|
||||
WorldServer worldServer = ((CraftWorld) world).getHandle();
|
||||
EntityTracker tracker = worldServer.tracker;
|
||||
return tracker.trackedEntities.get(entityID);
|
||||
}
|
||||
*/
|
||||
|
||||
private static Object getEntityTrackerEntry(World world, int entityID) throws FieldAccessException, IllegalArgumentException {
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
Object worldServer = unwrapper.unwrapItem(world);
|
||||
@@ -189,29 +182,18 @@ class EntityUtilities {
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Cannot access 'tracker' field due to security limitations.", e);
|
||||
}
|
||||
|
||||
|
||||
// Looking for an IntHashMap in the tracker entry
|
||||
if (trackedEntitiesField == null) {
|
||||
@SuppressWarnings("rawtypes")
|
||||
Set<Class> ignoredTypes = new HashSet<Class>();
|
||||
|
||||
// Well, this is more difficult. But we're looking for a Minecraft object that is not
|
||||
// created by the constructor(s).
|
||||
for (Constructor<?> constructor : tracker.getClass().getConstructors()) {
|
||||
for (Class<?> type : constructor.getParameterTypes()) {
|
||||
ignoredTypes.add(type);
|
||||
}
|
||||
}
|
||||
|
||||
// The Minecraft field that's NOT filled in by the constructor
|
||||
trackedEntitiesField = FuzzyReflection.fromObject(tracker, true).
|
||||
getFieldByType(MinecraftReflection.getMinecraftObjectRegex(), ignoredTypes);
|
||||
trackedEntitiesField = FuzzyReflection.fromObject(tracker, false)
|
||||
.getFieldByType("trackedEntities", MinecraftReflection.getIntHashMapClass());
|
||||
}
|
||||
|
||||
// Read the entity hashmap
|
||||
|
||||
// Read the map
|
||||
Object trackedEntities = null;
|
||||
|
||||
try {
|
||||
trackedEntities = FieldUtils.readField(trackedEntitiesField, tracker, true);
|
||||
trackedEntities = FieldUtils.readField(trackedEntitiesField, tracker, false);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new FieldAccessException("Cannot access 'trackedEntities' field due to security limitations.", e);
|
||||
}
|
||||
@@ -221,7 +203,7 @@ class EntityUtilities {
|
||||
|
||||
/**
|
||||
* Retrieve entity from a ID, even it it's newly created.
|
||||
* @return The asssociated entity.
|
||||
* @return The associated entity.
|
||||
* @throws FieldAccessException Reflection error.
|
||||
*/
|
||||
public static Entity getEntityFromID(World world, int entityID) throws FieldAccessException {
|
||||
@@ -256,7 +238,6 @@ class EntityUtilities {
|
||||
}
|
||||
|
||||
private static List<Object> unwrapBukkit(List<Player> players) {
|
||||
|
||||
List<Object> output = Lists.newArrayList();
|
||||
BukkitUnwrapper unwrapper = new BukkitUnwrapper();
|
||||
|
||||
|
||||
+19
-28
@@ -582,35 +582,26 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
* @param packet - the packet.
|
||||
*/
|
||||
protected void handleLogin(Class<?> packetClass, Object packet) {
|
||||
try {
|
||||
Class<?> loginClass = PACKET_LOGIN_CLIENT;
|
||||
FieldAccessor loginClient = LOGIN_GAME_PROFILE;
|
||||
// Try to find the login packet class
|
||||
if (PACKET_LOGIN_CLIENT == null) {
|
||||
PACKET_LOGIN_CLIENT = PacketType.Login.Client.START.getPacketClass();
|
||||
}
|
||||
|
||||
// Initialize packet class and login
|
||||
if (loginClass == null) {
|
||||
loginClass = PacketType.Login.Client.START.getPacketClass();
|
||||
PACKET_LOGIN_CLIENT = loginClass;
|
||||
}
|
||||
if (loginClient == null) {
|
||||
loginClient = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true);
|
||||
LOGIN_GAME_PROFILE = loginClient;
|
||||
}
|
||||
// If we can't, there's an issue
|
||||
if (PACKET_LOGIN_CLIENT == null) {
|
||||
throw new IllegalStateException("Failed to obtain login start packet. Did you build Spigot with BuildTools?");
|
||||
}
|
||||
|
||||
// See if we are dealing with the login packet
|
||||
if (loginClass.equals(packetClass)) {
|
||||
// GameProfile profile = (GameProfile) loginClient.get(packet);
|
||||
WrappedGameProfile profile = WrappedGameProfile.fromHandle(loginClient.get(packet));
|
||||
if (LOGIN_GAME_PROFILE == null) {
|
||||
LOGIN_GAME_PROFILE = Accessors.getFieldAccessor(PACKET_LOGIN_CLIENT, MinecraftReflection.getGameProfileClass(), true);
|
||||
}
|
||||
|
||||
// Save the channel injector
|
||||
factory.cacheInjector(profile.getName(), this);
|
||||
}
|
||||
} catch (IllegalArgumentException ex) { // Thrown by FuzzyReflection#getFields()
|
||||
System.err.println(String.format("[ProtocolLib] Encountered NPE in handleLogin(%s, %s)", packetClass, packet));
|
||||
System.err.println("PACKET_LOGIN_CLIENT = " + PACKET_LOGIN_CLIENT);
|
||||
System.err.println("LOGIN_GAME_PROFILE = " + LOGIN_GAME_PROFILE);
|
||||
System.err.println("GameProfile class = " + MinecraftReflection.getGameProfileClass());
|
||||
System.err.println("Provide this information in a new or existing issue");
|
||||
throw ex;
|
||||
// See if we are dealing with the login packet
|
||||
if (PACKET_LOGIN_CLIENT.equals(packetClass)) {
|
||||
WrappedGameProfile profile = WrappedGameProfile.fromHandle(LOGIN_GAME_PROFILE.get(packet));
|
||||
|
||||
// Save the channel injector
|
||||
factory.cacheInjector(profile.getName(), this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,7 +671,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
MinecraftMethods.getSendPacketMethod().invoke(getPlayerConnection(), packet);
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ProtocolLibrary.getErrorReporter().reportWarning(factory.getPlugin(),
|
||||
ProtocolLibrary.getErrorReporter().reportWarning(this,
|
||||
Report.newBuilder(REPORT_CANNOT_SEND_PACKET).messageParam(packet, playerName).error(ex).build());
|
||||
}
|
||||
}
|
||||
@@ -725,7 +716,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
|
||||
*/
|
||||
private Object getPlayerConnection() {
|
||||
if (playerConnection == null) {
|
||||
playerConnection = MinecraftFields.getPlayerConnection(player);
|
||||
playerConnection = MinecraftFields.getPlayerConnection(getPlayer());
|
||||
}
|
||||
return playerConnection;
|
||||
}
|
||||
|
||||
@@ -354,11 +354,12 @@ public class BukkitUpdater extends Updater {
|
||||
this.plugin.getLogger().warning("Please double-check your configuration to ensure it is correct.");
|
||||
this.result = UpdateResult.FAIL_APIKEY;
|
||||
} else {
|
||||
this.plugin.getLogger().warning("The updater could not contact dev.bukkit.org for updating.");
|
||||
this.plugin.getLogger().warning("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime.");
|
||||
// People don't care
|
||||
// this.plugin.getLogger().warning("The updater could not contact dev.bukkit.org for updating.");
|
||||
// this.plugin.getLogger().warning("If you have not recently modified your configuration and this is the first time you are seeing this message, the site may be experiencing temporary downtime.");
|
||||
this.result = UpdateResult.FAIL_DBO;
|
||||
}
|
||||
e.printStackTrace();
|
||||
// e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
@@ -75,7 +74,8 @@ public final class SpigotUpdater extends Updater {
|
||||
ProtocolLibrary.getErrorReporter().reportDetailed(
|
||||
SpigotUpdater.this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(ex).callerParam(this));
|
||||
} else {
|
||||
plugin.getLogger().log(Level.WARNING, "Failed to check for updates: " + ex);
|
||||
// People don't care
|
||||
// plugin.getLogger().log(Level.WARNING, "Failed to check for updates: " + ex);
|
||||
}
|
||||
|
||||
ProtocolLibrary.disableUpdates();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
name: ProtocolLib
|
||||
#version: ${project.version}${project.build.number}
|
||||
version: ${project.version}
|
||||
version: ${project.fullVersion}
|
||||
description: Provides read/write access to the Minecraft protocol.
|
||||
authors: [dmulloy2, comphenix]
|
||||
|
||||
@@ -25,6 +24,11 @@ commands:
|
||||
aliases: [packet_filter]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
packetlog:
|
||||
description: Logs hex representations of packets to a file or console
|
||||
usage: /<command> <protocol> <sender> <packet> [location]
|
||||
permission: protocol.admin
|
||||
permission-message: You don't have <permission>
|
||||
|
||||
permissions:
|
||||
protocol.*:
|
||||
|
||||
@@ -5,13 +5,13 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.DispenserRegistry;
|
||||
import net.minecraft.server.v1_11_R1.DispenserRegistry;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_9_R2.util.Versioning;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.inventory.CraftItemFactory;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.util.Versioning;
|
||||
|
||||
import com.comphenix.protocol.utility.Constants;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
@@ -24,6 +24,7 @@ import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
*/
|
||||
public class BukkitInitialization {
|
||||
private static boolean initialized;
|
||||
private static boolean packaged;
|
||||
|
||||
/**
|
||||
* Initialize Bukkit and ProtocolLib such that we can perfrom unit testing.
|
||||
@@ -34,6 +35,8 @@ public class BukkitInitialization {
|
||||
// Denote that we're done
|
||||
initialized = true;
|
||||
|
||||
initializePackage();
|
||||
|
||||
DispenserRegistry.c(); // Basically registers everything
|
||||
|
||||
// Mock the server object
|
||||
@@ -50,7 +53,7 @@ public class BukkitInitialization {
|
||||
// Inject this fake server
|
||||
Bukkit.setServer(mockedServer);
|
||||
|
||||
initializePackage();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +61,11 @@ public class BukkitInitialization {
|
||||
* Ensure that package names are correctly set up.
|
||||
*/
|
||||
public static void initializePackage() {
|
||||
// Initialize reflection
|
||||
MinecraftReflection.setMinecraftPackage(Constants.NMS, Constants.OBC);
|
||||
MinecraftVersion.setCurrentVersion(MinecraftVersion.COMBAT_UPDATE);
|
||||
if (!packaged) {
|
||||
packaged = true;
|
||||
|
||||
MinecraftReflection.setMinecraftPackage(Constants.NMS, Constants.OBC);
|
||||
MinecraftVersion.setCurrentVersion(MinecraftVersion.FROSTBURN_UPDATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,19 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2016 dmulloy2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -6,6 +22,8 @@ import static org.junit.Assert.assertFalse;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import net.minecraft.server.v1_11_R1.PacketLoginInStart;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -14,8 +32,9 @@ import com.comphenix.protocol.PacketType.Sender;
|
||||
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
|
||||
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.PacketLoginInStart;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class PacketTypeTest {
|
||||
|
||||
@BeforeClass
|
||||
|
||||
+34
-31
@@ -24,19 +24,20 @@ import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.AttributeModifier;
|
||||
import net.minecraft.server.v1_9_R2.DataWatcher;
|
||||
import net.minecraft.server.v1_9_R2.Entity;
|
||||
import net.minecraft.server.v1_9_R2.EntityLightning;
|
||||
import net.minecraft.server.v1_9_R2.MobEffect;
|
||||
import net.minecraft.server.v1_9_R2.MobEffectList;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutBoss;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.server.v1_11_R1.AttributeModifier;
|
||||
import net.minecraft.server.v1_11_R1.DataWatcher;
|
||||
import net.minecraft.server.v1_11_R1.Entity;
|
||||
import net.minecraft.server.v1_11_R1.EntityLightning;
|
||||
import net.minecraft.server.v1_11_R1.MobEffect;
|
||||
import net.minecraft.server.v1_11_R1.MobEffectList;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayOutBoss;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
|
||||
import org.apache.commons.lang.SerializationUtils;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
@@ -203,7 +204,7 @@ public class PacketContainerTest {
|
||||
ItemStack item = itemWithData();
|
||||
|
||||
StructureModifier<ItemStack> items = windowClick.getItemModifier();
|
||||
assertNull(items.read(0));
|
||||
// assertNull(items.read(0));
|
||||
|
||||
// Insert the item and check if it's there
|
||||
items.write(0, item);
|
||||
@@ -220,31 +221,22 @@ public class PacketContainerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetItemArrayModifier() {
|
||||
public void testGetItemListModifier() {
|
||||
PacketContainer windowItems = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||
StructureModifier<ItemStack[]> itemAccess = windowItems.getItemArrayModifier();
|
||||
StructureModifier<List<ItemStack>> itemAccess = windowItems.getItemListModifier();
|
||||
|
||||
ItemStack[] itemArray = new ItemStack[] {
|
||||
itemWithData(),
|
||||
new ItemStack(Material.DIAMOND_AXE)
|
||||
};
|
||||
List<ItemStack> items = new ArrayList<>();
|
||||
items.add(itemWithData());
|
||||
items.add(new ItemStack(Material.DIAMOND_AXE));
|
||||
|
||||
assertNull(itemAccess.read(0));
|
||||
|
||||
// Insert and check that it was succesful
|
||||
itemAccess.write(0, itemArray);
|
||||
itemAccess.write(0, items);
|
||||
|
||||
// Read back array
|
||||
ItemStack[] comparison = itemAccess.read(0);
|
||||
assertEquals(itemArray.length, comparison.length);
|
||||
|
||||
// Check that it is equivalent
|
||||
for (int i = 0; i < itemArray.length; i++) {
|
||||
ItemStack original = itemArray[i];
|
||||
ItemStack written = comparison[i];
|
||||
|
||||
assertTrue(String.format("Array element %s is not the same: %s != %s", i, original, written), equivalentItem(original, written));
|
||||
}
|
||||
List<ItemStack> comparison = itemAccess.read(0);
|
||||
assertEquals(items, comparison);
|
||||
}
|
||||
|
||||
private boolean equivalentItem(ItemStack first, ItemStack second) {
|
||||
@@ -520,6 +512,19 @@ public class PacketContainerTest {
|
||||
UPDATE_PROPERTIES;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComponentArrays() {
|
||||
PacketContainer signChange = new PacketContainer(PacketType.Play.Server.TILE_ENTITY_DATA);
|
||||
WrappedChatComponent[] components = new WrappedChatComponent[] {
|
||||
WrappedChatComponent.fromText("hello world"), WrappedChatComponent.fromText(""),
|
||||
WrappedChatComponent.fromText(""), WrappedChatComponent.fromText("")
|
||||
};
|
||||
signChange.getChatComponentArrays().write(0, components);
|
||||
|
||||
WrappedChatComponent[] back = signChange.getChatComponentArrays().read(0);
|
||||
assertArrayEquals(components, back);
|
||||
}
|
||||
|
||||
private static final List<PacketType> BLACKLISTED = Util.asList(
|
||||
PacketType.Play.Client.CUSTOM_PAYLOAD, PacketType.Play.Server.CUSTOM_PAYLOAD,
|
||||
PacketType.Play.Server.SET_COOLDOWN
|
||||
@@ -529,7 +534,7 @@ public class PacketContainerTest {
|
||||
public void testDeepClone() {
|
||||
// Try constructing all the packets
|
||||
for (PacketType type : PacketType.values()) {
|
||||
if (BLACKLISTED.contains(type)) {
|
||||
if (BLACKLISTED.contains(type) || type.isDeprecated()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -575,9 +580,7 @@ public class PacketContainerTest {
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (!registered) {
|
||||
// Let the test pass
|
||||
System.err.println("The packet ID " + type + " is not registered.");
|
||||
assertEquals(e.getMessage(), "The packet ID " + type + " is not registered.");
|
||||
e.printStackTrace();
|
||||
} else {
|
||||
// Something is very wrong
|
||||
throw e;
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* (c) 2016 dmulloy2
|
||||
*/
|
||||
package com.comphenix.protocol.injector;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
import com.comphenix.protocol.injector.netty.WirePacket;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class WirePacketTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializePackage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackets() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.CHAT);
|
||||
WirePacket wire = WirePacket.fromPacket(packet);
|
||||
WirePacket handle = WirePacket.fromPacket(packet.getHandle());
|
||||
assertEquals(wire, handle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSerialization() {
|
||||
int id = 42;
|
||||
byte[] array = { 1, 3, 7, 21, 88, 67, 8 };
|
||||
|
||||
WirePacket packet = new WirePacket(id, array);
|
||||
|
||||
ByteBuf buf = packet.serialize();
|
||||
|
||||
int backId = WirePacket.readVarInt(buf);
|
||||
byte[] backArray = new byte[buf.readableBytes()];
|
||||
buf.readBytes(backArray);
|
||||
|
||||
assertEquals(id, backId);
|
||||
assertArrayEquals(array, backArray);
|
||||
}
|
||||
}
|
||||
+22
@@ -1,14 +1,20 @@
|
||||
package com.comphenix.protocol.reflect.cloning;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.server.v1_11_R1.ItemStack;
|
||||
import net.minecraft.server.v1_11_R1.NonNullList;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.events.PacketContainer;
|
||||
|
||||
public class AggregateClonerTest {
|
||||
|
||||
@@ -22,4 +28,20 @@ public class AggregateClonerTest {
|
||||
List<Integer> input = Arrays.asList(1, 2, 3);
|
||||
assertEquals(input, AggregateCloner.DEFAULT.clone(input));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonNullList() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Server.WINDOW_ITEMS);
|
||||
|
||||
NonNullList<ItemStack> list = NonNullList.a(16, ItemStack.a);
|
||||
packet.getModifier().write(1, list);
|
||||
|
||||
PacketContainer cloned = packet.deepClone();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
NonNullList<ItemStack> list1 = (NonNullList<ItemStack>) cloned.getModifier().read(1);
|
||||
|
||||
assertEquals(list.size(), list1.size());
|
||||
assertArrayEquals(list.toArray(), list1.toArray());
|
||||
}
|
||||
}
|
||||
@@ -23,21 +23,21 @@ public class UpdaterTest {
|
||||
private static final int BUKKIT_DEV_ID = 45564;
|
||||
private static Plugin plugin;
|
||||
|
||||
//@BeforeClass
|
||||
// @BeforeClass
|
||||
public static void preparePlugin() {
|
||||
Server server = mock(Server.class);
|
||||
when(server.getUpdateFolder()).thenReturn(null);
|
||||
|
||||
plugin = mock(Plugin.class);
|
||||
String version = System.getProperty("projectVersion");
|
||||
if (version == null) version = "4.0.1-SNAPSHOT-b281";
|
||||
if (version == null) version = "4.2.1";
|
||||
when(plugin.getDescription()).thenReturn(new PluginDescriptionFile("ProtocolLib", version, null));
|
||||
when(plugin.getLogger()).thenReturn(Logger.getLogger("ProtocolLib"));
|
||||
when(plugin.getDataFolder()).thenReturn(null);
|
||||
when(plugin.getServer()).thenReturn(server);
|
||||
}
|
||||
|
||||
//@Test
|
||||
// @Test
|
||||
public void testSpigotUpdater() {
|
||||
SpigotUpdater updater = new SpigotUpdater(plugin, UpdateType.NO_DOWNLOAD, true);
|
||||
|
||||
@@ -54,7 +54,7 @@ public class UpdaterTest {
|
||||
System.out.println("Update available: " + updater.versionCheck(remote));
|
||||
}
|
||||
|
||||
//@Test
|
||||
// @Test
|
||||
public void testBukkitUpdater() {
|
||||
BukkitUpdater updater = new BukkitUpdater(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true);
|
||||
if (! updater.read()) {
|
||||
|
||||
+13
-13
@@ -5,6 +5,19 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import net.minecraft.server.v1_11_R1.ChatComponentText;
|
||||
import net.minecraft.server.v1_11_R1.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_11_R1.DataWatcher;
|
||||
import net.minecraft.server.v1_11_R1.IBlockData;
|
||||
import net.minecraft.server.v1_11_R1.IChatBaseComponent;
|
||||
import net.minecraft.server.v1_11_R1.IChatBaseComponent.ChatSerializer;
|
||||
import net.minecraft.server.v1_11_R1.NBTCompressedStreamTools;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.server.v1_11_R1.PlayerConnection;
|
||||
import net.minecraft.server.v1_11_R1.ServerPing;
|
||||
import net.minecraft.server.v1_11_R1.ServerPing.ServerData;
|
||||
import net.minecraft.server.v1_11_R1.ServerPing.ServerPingPlayerSample;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Entity;
|
||||
@@ -18,19 +31,6 @@ import org.powermock.core.classloader.annotations.PowerMockIgnore;
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.ChatComponentText;
|
||||
import net.minecraft.server.v1_9_R2.ChunkCoordIntPair;
|
||||
import net.minecraft.server.v1_9_R2.DataWatcher;
|
||||
import net.minecraft.server.v1_9_R2.IBlockData;
|
||||
import net.minecraft.server.v1_9_R2.IChatBaseComponent;
|
||||
import net.minecraft.server.v1_9_R2.IChatBaseComponent.ChatSerializer;
|
||||
import net.minecraft.server.v1_9_R2.NBTCompressedStreamTools;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.server.v1_9_R2.PlayerConnection;
|
||||
import net.minecraft.server.v1_9_R2.ServerPing;
|
||||
import net.minecraft.server.v1_9_R2.ServerPing.ServerData;
|
||||
import net.minecraft.server.v1_9_R2.ServerPing.ServerPingPlayerSample;
|
||||
|
||||
@RunWith(org.powermock.modules.junit4.PowerMockRunner.class)
|
||||
@PowerMockIgnore({ "org.apache.log4j.*", "org.apache.logging.*", "org.bukkit.craftbukkit.libs.jline.*" })
|
||||
public class MinecraftReflectionTest {
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.IntHashMap;
|
||||
import net.minecraft.server.v1_11_R1.IntHashMap;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.DyeColor;
|
||||
|
||||
+4
-4
@@ -16,15 +16,15 @@ public class ChunkCoordIntPairTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
net.minecraft.server.v1_9_R2.ChunkCoordIntPair pair = new net.minecraft.server.v1_9_R2.ChunkCoordIntPair(1, 2);
|
||||
net.minecraft.server.v1_11_R1.ChunkCoordIntPair pair = new net.minecraft.server.v1_11_R1.ChunkCoordIntPair(1, 2);
|
||||
ChunkCoordIntPair specific = ChunkCoordIntPair.getConverter().getSpecific(pair);
|
||||
|
||||
assertEquals(1, specific.getChunkX());
|
||||
assertEquals(2, specific.getChunkZ());
|
||||
|
||||
net.minecraft.server.v1_9_R2.ChunkCoordIntPair roundtrip =
|
||||
(net.minecraft.server.v1_9_R2.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
|
||||
getGeneric(net.minecraft.server.v1_9_R2.ChunkCoordIntPair.class, specific);
|
||||
net.minecraft.server.v1_11_R1.ChunkCoordIntPair roundtrip =
|
||||
(net.minecraft.server.v1_11_R1.ChunkCoordIntPair) ChunkCoordIntPair.getConverter().
|
||||
getGeneric(net.minecraft.server.v1_11_R1.ChunkCoordIntPair.class, specific);
|
||||
|
||||
assertEquals(1, roundtrip.x);
|
||||
assertEquals(2, roundtrip.z);
|
||||
|
||||
+7
-6
@@ -1,12 +1,13 @@
|
||||
package com.comphenix.protocol.wrappers;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import net.minecraft.server.v1_9_R2.EntityHuman.EnumChatVisibility;
|
||||
import net.minecraft.server.v1_9_R2.EnumDifficulty;
|
||||
import net.minecraft.server.v1_9_R2.EnumProtocol;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayInClientCommand.EnumClientCommand;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayInUseEntity.EnumEntityUseAction;
|
||||
import net.minecraft.server.v1_9_R2.WorldSettings.EnumGamemode;
|
||||
|
||||
import net.minecraft.server.v1_11_R1.EntityHuman.EnumChatVisibility;
|
||||
import net.minecraft.server.v1_11_R1.EnumDifficulty;
|
||||
import net.minecraft.server.v1_11_R1.EnumGamemode;
|
||||
import net.minecraft.server.v1_11_R1.EnumProtocol;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayInClientCommand.EnumClientCommand;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayInUseEntity.EnumEntityUseAction;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
+3
-3
@@ -6,9 +6,9 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.AttributeModifier;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.server.v1_9_R2.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
import net.minecraft.server.v1_11_R1.AttributeModifier;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayOutUpdateAttributes;
|
||||
import net.minecraft.server.v1_11_R1.PacketPlayOutUpdateAttributes.AttributeSnapshot;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
+5
-7
@@ -19,15 +19,13 @@ package com.comphenix.protocol.wrappers;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNotSame;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.EntityLightning;
|
||||
import net.minecraft.server.v1_9_R2.ItemStack;
|
||||
import net.minecraft.server.v1_11_R1.EntityLightning;
|
||||
|
||||
import org.bukkit.craftbukkit.v1_9_R2.entity.CraftLightningStrike;
|
||||
import org.bukkit.craftbukkit.v1_11_R1.entity.CraftLightningStrike;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
@@ -92,11 +90,11 @@ public class WrappedDataWatcherTest {
|
||||
|
||||
@Test
|
||||
public void testSerializers() {
|
||||
Serializer blockPos = Registry.get(net.minecraft.server.v1_9_R2.BlockPosition.class, false);
|
||||
Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_9_R2.BlockPosition.class, true);
|
||||
Serializer blockPos = Registry.get(net.minecraft.server.v1_11_R1.BlockPosition.class, false);
|
||||
Serializer optionalBlockPos = Registry.get(net.minecraft.server.v1_11_R1.BlockPosition.class, true);
|
||||
assertNotSame(blockPos, optionalBlockPos);
|
||||
|
||||
assertNull(Registry.get(ItemStack.class, false));
|
||||
// assertNull(Registry.get(ItemStack.class, false));
|
||||
assertNotNull(Registry.get(UUID.class, true));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -26,8 +26,8 @@ import java.io.DataInputStream;
|
||||
import java.io.DataOutput;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
import net.minecraft.server.v1_9_R2.ItemStack;
|
||||
import net.minecraft.server.v1_9_R2.Items;
|
||||
import net.minecraft.server.v1_11_R1.ItemStack;
|
||||
import net.minecraft.server.v1_11_R1.Items;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||
* Copyright (C) 2016 dmulloy2
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under the terms of the
|
||||
* GNU General Public License as published by the Free Software Foundation; either version 2 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program;
|
||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||
* 02111-1307 USA
|
||||
*/
|
||||
package com.comphenix.protocol.wrappers.nbt;
|
||||
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.comphenix.protocol.BukkitInitialization;
|
||||
|
||||
/**
|
||||
* @author dmulloy2
|
||||
*/
|
||||
public class TileEntityTest {
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
BukkitInitialization.initializePackage();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
// Ensure the read and write methods exist
|
||||
TileEntityAccessor<BlockState> accessor = new TileEntityAccessor<>();
|
||||
accessor.findMethods(null, null);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user