diff --git a/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java b/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java
index 72488d5e..bbea4086 100644
--- a/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java
+++ b/modules/API/src/main/java/com/comphenix/protocol/events/PacketContainer.java
@@ -46,6 +46,7 @@ import org.bukkit.World;
import org.bukkit.WorldType;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
+import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.Vector;
import com.comphenix.protocol.PacketType;
@@ -86,6 +87,7 @@ import com.comphenix.protocol.wrappers.EnumWrappers.PlayerDigType;
import com.comphenix.protocol.wrappers.EnumWrappers.PlayerInfoAction;
import com.comphenix.protocol.wrappers.EnumWrappers.ResourcePackStatus;
import com.comphenix.protocol.wrappers.EnumWrappers.ScoreboardAction;
+import com.comphenix.protocol.wrappers.EnumWrappers.SoundCategory;
import com.comphenix.protocol.wrappers.EnumWrappers.TitleAction;
import com.comphenix.protocol.wrappers.EnumWrappers.WorldBorderAction;
import com.comphenix.protocol.wrappers.MultiBlockChangeInfo;
@@ -578,12 +580,11 @@ public class PacketContainer implements Serializable {
return structureModifier.withType(
Collection.class,
BukkitConverters.getListConverter(
- MinecraftReflection.getWatchableObjectClass(),
+ MinecraftReflection.getDataWatcherItemClass(),
BukkitConverters.getWatchableObjectConverter())
);
}
-
-
+
/**
* Retrieves a read/write structure for block fields.
*
@@ -845,6 +846,26 @@ public class PacketContainer implements Serializable {
EnumWrappers.getParticleClass(), EnumWrappers.getParticleConverter());
}
+ /**
+ * Retrieve a read/write structure for the MobEffectList class in 1.9.
+ * @return A modifier for MobEffectList fields.
+ */
+ public StructureModifier getEffectTypes() {
+ // Convert to and from Bukkit
+ return structureModifier.withType(
+ MinecraftReflection.getMobEffectListClass(), BukkitConverters.getEffectTypeConverter());
+ }
+
+ /**
+ * Retrieve a read/write structure for the SoundCategory enum in 1.9.
+ * @return A modifier for SoundCategory enum fields.
+ */
+ public StructureModifier getSoundCategories() {
+ // Convert to and from the enums
+ return structureModifier.withType(
+ EnumWrappers.getSoundCategoryClass(), EnumWrappers.getSoundCategoryConverter());
+ }
+
/**
* Retrieves the ID of this packet.
*
diff --git a/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java
index e516329f..9ab146c6 100644
--- a/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java
+++ b/modules/API/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java
@@ -1341,6 +1341,11 @@ public class MinecraftReflection {
return getMinecraftClass("MinecraftKey");
}
+ public static Class> getMobEffectListClass() {
+ // TODO Implement a fallback
+ return getMinecraftClass("MobEffectList");
+ }
+
/**
* Retrieve the ServerConnection abstract class.
* @return The ServerConnection class.
diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java
index dd2baa96..4cddbe19 100644
--- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java
+++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java
@@ -1105,7 +1105,7 @@ public class BukkitConverters {
put(MinecraftReflection.getItemStackClass(), (EquivalentConverter) getItemStackConverter()).
put(MinecraftReflection.getNBTBaseClass(), (EquivalentConverter) getNbtConverter()).
put(MinecraftReflection.getNBTCompoundClass(), (EquivalentConverter) getNbtConverter()).
- put(MinecraftReflection.getWatchableObjectClass(), (EquivalentConverter) getWatchableObjectConverter()).
+ put(MinecraftReflection.getDataWatcherItemClass(), (EquivalentConverter) getWatchableObjectConverter()).
put(MinecraftReflection.getMobEffectClass(), (EquivalentConverter) getPotionEffectConverter()).
put(MinecraftReflection.getNmsWorldClass(), (EquivalentConverter) getWorldConverter());
@@ -1146,4 +1146,38 @@ public class BukkitConverters {
}
return unwrappers;
}
+
+ private static MethodAccessor getMobEffectId = null;
+ private static MethodAccessor getMobEffect = null;
+
+ public static EquivalentConverter getEffectTypeConverter() {
+ return new IgnoreNullConverter() {
+
+ @Override
+ public Class getSpecificType() {
+ return PotionEffectType.class;
+ }
+
+ @Override
+ protected Object getGenericValue(Class> genericType, PotionEffectType specific) {
+ if (getMobEffect == null) {
+ getMobEffect = Accessors.getMethodAccessor(genericType, "fromId", int.class);
+ }
+
+ int id = specific.getId();
+ return getMobEffect.invoke(null, id);
+ }
+
+ @Override
+ protected PotionEffectType getSpecificValue(Object generic) {
+ Class> clazz = MinecraftReflection.getMobEffectListClass();
+ if (getMobEffectId == null) {
+ getMobEffectId = Accessors.getMethodAccessor(clazz, "getId", clazz);
+ }
+
+ int id = (int) getMobEffectId.invoke(null, generic);
+ return PotionEffectType.getById(id);
+ }
+ };
+ }
}
diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java
index 23923a8b..7689ab9b 100644
--- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java
+++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java
@@ -272,6 +272,40 @@ public abstract class EnumWrappers {
}
}
+ public enum SoundCategory {
+ MASTER("master"),
+ MUSIC("music"),
+ RECORDS("record"),
+ WEATHER("weather"),
+ BLOCKS("block"),
+ HOSTILE("hostile"),
+ NEUTRAL("neutral"),
+ PLAYERS("player"),
+ AMBIENT("ambient"),
+ VOICE("voice");
+
+ private static final Map LOOKUP;
+ static {
+ LOOKUP = new HashMap<>();
+ for (SoundCategory category : values()) {
+ LOOKUP.put(category.key, category);
+ }
+ }
+
+ private final String key;
+ private SoundCategory(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public static SoundCategory getByKey(String key) {
+ return LOOKUP.get(key.toLowerCase());
+ }
+ }
+
private static Class> PROTOCOL_CLASS = null;
private static Class> CLIENT_COMMAND_CLASS = null;
private static Class> CHAT_VISIBILITY_CLASS = null;
@@ -287,6 +321,7 @@ public abstract class EnumWrappers {
private static Class> PLAYER_ACTION_CLASS = null;
private static Class> SCOREBOARD_ACTION_CLASS = null;
private static Class> PARTICLE_CLASS = null;
+ private static Class> SOUND_CATEGORY_CLASS = null;
private static boolean INITIALIZED = false;
private static Map, EquivalentConverter>> FROM_NATIVE = Maps.newHashMap();
@@ -319,6 +354,7 @@ public abstract class EnumWrappers {
PLAYER_ACTION_CLASS = getEnum(PacketType.Play.Client.ENTITY_ACTION.getPacketClass(), 0);
SCOREBOARD_ACTION_CLASS = getEnum(PacketType.Play.Server.SCOREBOARD_SCORE.getPacketClass(), 0);
PARTICLE_CLASS = getEnum(PacketType.Play.Server.WORLD_PARTICLES.getPacketClass(), 0);
+ SOUND_CATEGORY_CLASS = getEnum(PacketType.Play.Server.CUSTOM_SOUND_EFFECT.getPacketClass(), 0);
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter());
@@ -335,6 +371,7 @@ public abstract class EnumWrappers {
associate(PLAYER_ACTION_CLASS, PlayerAction.class, getEntityActionConverter());
associate(SCOREBOARD_ACTION_CLASS, ScoreboardAction.class, getUpdateScoreActionConverter());
associate(PARTICLE_CLASS, Particle.class, getParticleConverter());
+ associate(SOUND_CATEGORY_CLASS, SoundCategory.class, getSoundCategoryConverter());
INITIALIZED = true;
}
@@ -443,6 +480,11 @@ public abstract class EnumWrappers {
return PARTICLE_CLASS;
}
+ public static Class> getSoundCategoryClass() {
+ initialize();
+ return SOUND_CATEGORY_CLASS;
+ }
+
// Get the converters
public static EquivalentConverter getProtocolConverter() {
return new EnumConverter(Protocol.class);
@@ -504,6 +546,10 @@ public abstract class EnumWrappers {
return new EnumConverter(Particle.class);
}
+ public static EquivalentConverter getSoundCategoryConverter() {
+ return new EnumConverter(SoundCategory.class);
+ }
+
/**
* Retrieve a generic enum converter for use with StructureModifiers.
* @param enumClass - Enum class
diff --git a/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java b/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java
index a9ba9f39..b82468b8 100644
--- a/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java
+++ b/modules/API/src/main/java/com/comphenix/protocol/wrappers/PlayerInfoData.java
@@ -25,37 +25,61 @@ import com.comphenix.protocol.wrappers.EnumWrappers.NativeGameMode;
import com.google.common.base.Objects;
/**
+ * Represents an immutable PlayerInfoData in the PLAYER_INFO packet.
* @author dmulloy2
*/
-
public class PlayerInfoData {
private static Constructor> constructor;
- protected final WrappedGameProfile profile;
- protected final int ping;
- protected final NativeGameMode gameMode;
- protected final WrappedChatComponent displayName;
+ private final int latency;
+ private final NativeGameMode gameMode;
+ private final WrappedGameProfile profile;
+ private final WrappedChatComponent displayName;
// This is the same order as the NMS class, minus the packet (which isn't a field)
- public PlayerInfoData(WrappedGameProfile profile, int ping, NativeGameMode gameMode, WrappedChatComponent displayName) {
- this.ping = ping;
- this.gameMode = gameMode;
+ public PlayerInfoData(WrappedGameProfile profile, int latency, NativeGameMode gameMode, WrappedChatComponent displayName) {
this.profile = profile;
+ this.latency = latency;
+ this.gameMode = gameMode;
this.displayName = displayName;
}
+ /**
+ * Gets the GameProfile of the player represented by this data.
+ * @return The GameProfile
+ */
public WrappedGameProfile getProfile() {
return profile;
}
+ /**
+ * @deprecated Replaced by {@link #getLatency()}
+ */
+ @Deprecated
public int getPing() {
- return ping;
+ return latency;
}
+ /**
+ * Gets the latency between the client and the server.
+ * @return The latency
+ */
+ public int getLatency() {
+ return latency;
+ }
+
+ /**
+ * Gets the GameMode of the player represented by this data.
+ * @return The GameMode
+ */
public NativeGameMode getGameMode() {
return gameMode;
}
+ /**
+ * Gets the display name of the player represented by this data.
+ * @return The display name
+ */
public WrappedChatComponent getDisplayName() {
return displayName;
}
@@ -91,7 +115,7 @@ public class PlayerInfoData {
Object result = constructor.newInstance(
null,
specific.profile.handle,
- specific.ping,
+ specific.latency,
EnumWrappers.getGameModeConverter().getGeneric(EnumWrappers.getGameModeClass(), specific.gameMode),
specific.displayName != null ? specific.displayName.handle : null
);
@@ -112,7 +136,7 @@ public class PlayerInfoData {
WrappedGameProfile gameProfile = gameProfiles.read(0);
StructureModifier ints = modifier.withType(int.class);
- int ping = ints.read(0);
+ int latency = ints.read(0);
StructureModifier gameModes = modifier.withType(
EnumWrappers.getGameModeClass(), EnumWrappers.getGameModeConverter());
@@ -122,7 +146,7 @@ public class PlayerInfoData {
MinecraftReflection.getIChatBaseComponentClass(), BukkitConverters.getWrappedChatComponentConverter());
WrappedChatComponent displayName = displayNames.read(0);
- return new PlayerInfoData(gameProfile, ping, gameMode, displayName);
+ return new PlayerInfoData(gameProfile, latency, gameMode, displayName);
}
// Otherwise, return null
@@ -146,7 +170,7 @@ public class PlayerInfoData {
// Only compare objects of similar type
if (obj instanceof PlayerInfoData) {
PlayerInfoData other = (PlayerInfoData) obj;
- return profile.equals(other.profile) && ping == other.ping && gameMode == other.gameMode
+ return profile.equals(other.profile) && latency == other.latency && gameMode == other.gameMode
&& displayName.equals(other.displayName);
}
return false;
@@ -154,12 +178,12 @@ public class PlayerInfoData {
@Override
public int hashCode() {
- return Objects.hashCode(profile, ping, gameMode, displayName);
+ return Objects.hashCode(latency, gameMode, profile, displayName);
}
@Override
public String toString() {
- return String.format("PlayerInfoData { profile=%s, ping=%s, gameMode=%s, displayName=%s }",
- profile, ping, gameMode, displayName);
+ return String.format("PlayerInfoData[latency=%s, gameMode=%s, profile=%s, displayName=%s",
+ latency, gameMode, profile, displayName);
}
}
diff --git a/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java b/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java
index 19116180..394b93ef 100644
--- a/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java
+++ b/modules/ProtocolLib/src/test/java/com/comphenix/integration/protocol/SimpleMinecraftClient.java
@@ -33,7 +33,7 @@ public class SimpleMinecraftClient {
/**
* Query the local server for ping information.
* @return The server information.
- * @throws IOException
+ * @throws IOException
*/
public String queryLocalPing() throws IOException {
return queryServerPing(new InetSocketAddress("localhost", 25565));
@@ -173,7 +173,7 @@ public class SimpleMinecraftClient {
}
}
- private static class HandshakePacket extends SimplePacket {
+ private static class HandshakePacket extends SimplePacket {
private int protocol;
private String host;
private int port;
@@ -209,6 +209,7 @@ public class SimpleMinecraftClient {
serializer.serializeVarInt(output, type.getCurrentId());
}
+ @SuppressWarnings("unused")
public void read(PacketType type, DataInputStream input) throws IOException {
// Note - we don't read the packet id
if (this.type != type) {