Compare commits

..
19 Commits
Author SHA1 Message Date
Dan Mulloy 9a65ddbc43 Update version to 4.5.1 for release 2020-06-03 21:21:31 -04:00
Dan Mulloy 54c252a354 Improve WrappedDataWatcher hasIndex performance
Use the map to check for indices instead of getting the object

Addresses #850
2020-05-27 21:56:22 -04:00
Dan Mulloy e92abda187 Try to fix forge compatibility
Addresses #825
2020-05-27 21:41:56 -04:00
Dan Mulloy 3f7b7f4bb3 Make sure all Spigot forks are included for updater purposes
Addresses #835
2020-05-24 20:35:25 -04:00
Andrew Steinborn 944b3f8280 Cache PacketType#hashCode (#818)
This should result in a general performance improvement, as PacketType is often used as map keys across ProtocolLib.
2020-05-24 15:45:42 -04:00
Dan Mulloy b04fca8324 Fix packet interception error with ViaVersion (#724)
Thanks to @KennyTV and @MedicOP for their help in tracking this bug down. Essentially the decode method we were using could be different depending on when the player logged in, which clashed with PL's static handling of it.

Fixes #724
Fixes #791
Fixes #803
Fixes #811
Fixes #813
Fixes #819
...and probably some others...
2020-05-24 15:29:01 -04:00
Dan Mulloy bfa0eee91e Fix direction and dimension enums 2020-05-03 15:59:55 -04:00
Dan Mulloy 308e3d3417 Update to 1.15.2 2020-05-03 13:15:42 -04:00
Dan Mulloy 42e48aa9b8 Be more specific in which sendPacket method we choose
Related to PaperMC/Paper#3282
2020-05-03 12:44:59 -04:00
Dan Mulloy 18d0193288 Merge remote-tracking branch 'origin/master' 2020-04-30 18:47:06 -04:00
Dan Mulloy 0ab552a6ef Fix issue with legacy block data (#809)
Fixes #809
2020-04-30 18:46:29 -04:00
Dan Mulloy d9fef94bc6 Merge pull request #782 from bergerkiller/master
Replace ThreadLocal scheduleProcessPackets with queue, fixes #763
2020-03-03 09:15:24 -05:00
Irmo van den Berge ab5fb40f8f Replace ThreadLocal scheduleProcessPackets with queue, fixes #763 2020-03-01 13:07:14 +01:00
libraryaddict 4baa4aa724 AttributeModifier$Operation only to be fetched if viable (#773) 2020-02-18 16:12:24 -05:00
Dan Mulloy 7a4a285935 Add some more useful metrics 2020-01-11 13:49:36 -05:00
Dan Mulloy f38c393d6f Use new Spigot updater
Fixes #746
2020-01-11 13:47:49 -05:00
Dan Mulloy 22c2a4abcc Fix compatibility with CraftBukkit
Still recommend Spigot, for what it's worth
2019-12-26 11:39:23 -05:00
Dan Mulloy 1a434e9ea2 Try changing visibility on ProtocolLogger#init
Addresses #740
2019-12-26 11:34:33 -05:00
Dan Mulloy 25a5f1d07f Update version to 4.5.1-SNAPSHOT 2019-12-26 11:28:14 -05:00
22 changed files with 309 additions and 109 deletions

No files matched your search

+2 -2
View File
@@ -4,7 +4,7 @@
<groupId>com.comphenix.protocol</groupId>
<artifactId>ProtocolLib</artifactId>
<name>ProtocolLib</name>
<version>4.5.0</version>
<version>4.5.1</version>
<description>Provides read/write access to the Minecraft protocol.</description>
<url>https://github.com/dmulloy2/ProtocolLib</url>
@@ -17,7 +17,7 @@
<project.fullVersion>${project.version}</project.fullVersion>
<powermock.version>2.0.4</powermock.version>
<spigot.version>1.15.1-R0.1-SNAPSHOT</spigot.version>
<spigot.version>1.15.2-R0.1-SNAPSHOT</spigot.version>
</properties>
<build>
@@ -654,6 +654,7 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
private boolean forceAsync;
private boolean dynamic;
private int hashCode;
/**
* Retrieve the current packet/legacy lookup.
@@ -1191,7 +1192,14 @@ public class PacketType implements Serializable, Cloneable, Comparable<PacketTyp
@Override
public int hashCode() {
return Objects.hashCode(protocol, sender, currentId);
int hash = hashCode;
if (hash == 0) {
hash = protocol.hashCode();
hash = 31 * hash + sender.hashCode();
hash = 31 * hash + Integer.hashCode(currentId);
hashCode = hash;
}
return hash;
}
@Override
@@ -29,7 +29,12 @@ public class ProtocolLogger {
private static boolean debugEnabled = false;
private static Logger logger = Logger.getLogger("Minecraft");
protected static void init(Plugin plugin) {
/**
* Don't call this method from any plugin. Currently only public to test if it fixes a weird error.
* See GH-740
* @param plugin ProtocolLib
*/
public static void init(ProtocolLib plugin) {
logger = plugin.getLogger();
try {
@@ -30,10 +30,8 @@ import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.*;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import com.comphenix.protocol.utility.EnhancerFactory;
@@ -109,6 +107,50 @@ class SerializedOfflinePlayer implements OfflinePlayer, Serializable {
return bedSpawnLocation;
}
// TODO do we need to implement this?
public void incrementStatistic(Statistic statistic) throws IllegalArgumentException { }
public void decrementStatistic(Statistic statistic) throws IllegalArgumentException { }
public void incrementStatistic(Statistic statistic, int i) throws IllegalArgumentException { }
public void decrementStatistic(Statistic statistic, int i) throws IllegalArgumentException { }
public void setStatistic(Statistic statistic, int i) throws IllegalArgumentException { }
public int getStatistic(Statistic statistic) throws IllegalArgumentException {
return 0;
}
public void incrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { }
public void decrementStatistic(Statistic statistic, Material material) throws IllegalArgumentException { }
public int getStatistic(Statistic statistic, Material material) throws IllegalArgumentException {
return 0;
}
public void incrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { }
public void decrementStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { }
public void setStatistic(Statistic statistic, Material material, int i) throws IllegalArgumentException { }
public void incrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { }
public void decrementStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException { }
public int getStatistic(Statistic statistic, EntityType entityType) throws IllegalArgumentException {
return 0;
}
public void incrementStatistic(Statistic statistic, EntityType entityType, int i) throws IllegalArgumentException { }
public void decrementStatistic(Statistic statistic, EntityType entityType, int i) { }
public void setStatistic(Statistic statistic, EntityType entityType, int i) { }
@Override
public long getFirstPlayed() {
return firstPlayed;
@@ -79,23 +79,23 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Versioning
private static Class<?> PACKET_SET_PROTOCOL = null;
private static AtomicInteger keyId = new AtomicInteger();
private static AttributeKey<Integer> PROTOCOL_KEY;
private static final AtomicInteger keyId = new AtomicInteger();
private static final AttributeKey<Integer> PROTOCOL_KEY;
static {
PROTOCOL_KEY = AttributeKey.valueOf("PROTOCOL-" + keyId.getAndIncrement());
}
// Saved accessors
private static Method DECODE_BUFFER;
private static Method ENCODE_BUFFER;
private Method decodeBuffer;
private Method encodeBuffer;
private static FieldAccessor ENCODER_TYPE_MATCHER;
// For retrieving the protocol
private static FieldAccessor PROTOCOL_ACCESSOR;
// The factory that created this injector
private InjectionFactory factory;
private final InjectionFactory factory;
// The player, or temporary player
private Player player;
@@ -108,10 +108,10 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// The current network manager and channel
private final Object networkManager;
private final Channel originalChannel;
private VolatileField channelField;
private final VolatileField channelField;
// Known network markers
private Map<Object, NetworkMarker> packetMarker = new WeakHashMap<>();
private final Map<Object, NetworkMarker> packetMarker = new WeakHashMap<>();
/**
* Indicate that this packet has been processed by event listeners.
@@ -126,21 +126,21 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
private PacketEvent finalEvent;
/**
* A flag set by the main thread to indiciate that a packet should not be processed.
* A queue of packets that were sent with filtered=false
*/
private final ThreadLocal<Boolean> scheduleProcessPackets = ThreadLocal.withInitial(() -> true);
private final PacketFilterQueue unfilteredProcessedPackets = new PacketFilterQueue();
// Other handlers
private ByteToMessageDecoder vanillaDecoder;
private MessageToByteEncoder<Object> vanillaEncoder;
private Deque<PacketEvent> finishQueue = new ArrayDeque<>();
private final Deque<PacketEvent> finishQueue = new ArrayDeque<>();
// The channel listener
private ChannelListener channelListener;
private final ChannelListener channelListener;
// Processing network markers
private NetworkProcessor processor;
private final NetworkProcessor processor;
// Closed
private boolean injected;
@@ -178,6 +178,24 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
return value != null ? value : MinecraftProtocolVersion.getCurrentVersion();
}
private void updateBufferMethods() {
try {
decodeBuffer = vanillaDecoder.getClass().getDeclaredMethod("decode",
ChannelHandlerContext.class, ByteBuf.class, List.class);
decodeBuffer.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find decode method in " + vanillaDecoder.getClass());
}
try {
encodeBuffer = vanillaEncoder.getClass().getDeclaredMethod("encode",
ChannelHandlerContext.class, Object.class, ByteBuf.class);
encodeBuffer.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find encode method in " + vanillaEncoder.getClass());
}
}
@Override
@SuppressWarnings("unchecked")
public boolean inject() {
@@ -212,25 +230,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
throw new IllegalArgumentException("Unable to find vanilla encoder in " + originalChannel.pipeline());
patchEncoder(vanillaEncoder);
if (DECODE_BUFFER == null) {
try {
DECODE_BUFFER = vanillaDecoder.getClass().getDeclaredMethod("decode",
ChannelHandlerContext.class, ByteBuf.class, List.class);
DECODE_BUFFER.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find decode method in " + vanillaDecoder.getClass());
}
}
if (ENCODE_BUFFER == null) {
try {
ENCODE_BUFFER = vanillaEncoder.getClass().getDeclaredMethod("encode",
ChannelHandlerContext.class, Object.class, ByteBuf.class);
ENCODE_BUFFER.setAccessible(true);
} catch (NoSuchMethodException ex) {
throw new IllegalArgumentException("Unable to find encode method in " + vanillaEncoder.getClass());
}
}
updateBufferMethods();
// Intercept sent packets
MessageToByteEncoder<Object> protocolEncoder = new MessageToByteEncoder<Object>() {
@@ -328,7 +328,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
Object original = accessor.get(instance);
// See if we've been instructed not to process packets
if (!scheduleProcessPackets.get()) {
if (unfilteredProcessedPackets.contains(original)) {
NetworkMarker marker = getMarker(original);
if (marker != null) {
@@ -416,7 +416,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
try {
// Skip every kind of non-filtered packet
if (!scheduleProcessPackets.get()) {
if (unfilteredProcessedPackets.remove(packet)) {
return;
}
@@ -447,7 +447,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Process output handler
if (packet != null && event != null && NetworkMarker.hasOutputHandlers(marker)) {
ByteBuf packetBuffer = ctx.alloc().buffer();
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, packetBuffer);
encodeBuffer.invoke(vanillaEncoder, ctx, packet, packetBuffer);
// Let each handler prepare the actual output
byte[] data = processor.processOutput(event, marker, getBytes(packetBuffer));
@@ -470,7 +470,7 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
// Attempt to handle the packet nevertheless
if (packet != null) {
try {
ENCODE_BUFFER.invoke(vanillaEncoder, ctx, packet, output);
encodeBuffer.invoke(vanillaEncoder, ctx, packet, output);
} catch (InvocationTargetException ex) {
if (ex.getCause() instanceof Exception) {
//noinspection ThrowFromFinallyBlock
@@ -510,7 +510,12 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuffer, List<Object> packets) throws Exception {
try {
DECODE_BUFFER.invoke(vanillaDecoder, ctx, byteBuffer, packets);
try {
decodeBuffer.invoke(vanillaDecoder, ctx, byteBuffer, packets);
} catch (IllegalArgumentException ex) {
updateBufferMethods();
decodeBuffer.invoke(vanillaDecoder, ctx, byteBuffer, packets);
}
// Reset queue
finishQueue.clear();
@@ -663,12 +668,11 @@ public class ChannelInjector extends ByteToMessageDecoder implements Injector {
public void sendServerPacket(Object packet, NetworkMarker marker, boolean filtered) {
saveMarker(packet, marker);
try {
scheduleProcessPackets.set(filtered);
invokeSendPacket(packet);
} finally {
scheduleProcessPackets.set(true);
if (!filtered) {
unfilteredProcessedPackets.add(packet);
}
invokeSendPacket(packet);
}
/**
@@ -0,0 +1,83 @@
/**
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
* Copyright (C) 2015 dmulloy2
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program;
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307 USA
*/
package com.comphenix.protocol.injector.netty;
import java.util.ArrayDeque;
import java.util.Queue;
/**
* Stores packets that need to be sent without being handled by the listeners (filtered=false).
* When other packets sent after sending the packet are removed, the packet is removed as well
* to prevent a memory leak, assuming a consistent send order is in place.
*
* @author bergerkiller
*/
public class PacketFilterQueue {
private Queue<Object> queue = new ArrayDeque<>();
/**
* Adds a packet to this queue, indicating further on that it should not be filtered.
*
* @param packet
*/
public synchronized void add(Object packet) {
queue.add(packet);
}
/**
* Checks whether a packet is contained inside this queue, indicating
* it should not be filtered.
*
* @param packet
* @return True if contained and packet should not be filtered (filtered=false)
*/
public synchronized boolean contains(Object packet) {
return queue.contains(packet);
}
/**
* Checks whether a packet is contained inside this queue and removes it if so.
* Other packets marked in this queue that were sent before this packet are
* removed from the queue also, avoiding memory leaks because of dropped packets.
*
* @param packet
* @return True if contained and packet should not be filtered (filtered=false)
*/
public synchronized boolean remove(Object packet) {
if (queue.isEmpty()) {
// Nothing in the queue
return false;
} else if (queue.peek() == packet) {
// First in the queue (expected)
queue.poll();
return true;
} else if (!queue.contains(packet)) {
// There are unfiltered packets, but this one is not
return false;
} else {
// We have skipped over some packets (unexpected)
// Poll packets until we find it
while (queue.poll() != packet) {
if (queue.isEmpty()) {
// This should never happen! But to avoid infinite loop.
return false;
}
}
return true;
}
}
}
@@ -297,9 +297,7 @@ public class ProtocolInjector implements ChannelListener {
PacketContainer container = new PacketContainer(PacketRegistry.getPacketType(clazz), packet);
return packetQueued(container, injector.getPlayer(), marker);
} catch (LinkageError e) {
// So far this has been seen when the jar is shared
System.err.println("[ProtocolLib] Encountered a LinkageError. Make sure you\'re not using this jar for multiple server instances!");
System.err.println("[ProtocolLib] If you\'re getting this error for other reasons, please report it!");
System.err.println("[ProtocolLib] Encountered a LinkageError (likely a misbehaving wrapper), please report this!");
e.printStackTrace();
}
}
@@ -174,10 +174,10 @@ public class Metrics {
JSONObject data = new JSONObject();
String pluginName = plugin.getDescription().getName();
Pair<String, String> pluginVersion = Statistics.splitVersion(); // ProtocolLib - remove build number
String pluginVersion = Statistics.getVersion(); // ProtocolLib - remove build number
data.put("pluginName", pluginName); // Append the name of the plugin
data.put("pluginVersion", pluginVersion.getLeft()); // Append the version of the plugin
data.put("pluginVersion", pluginVersion); // Append the version of the plugin
JSONArray customCharts = new JSONArray();
for (CustomChart customChart : charts) {
// Add the data of the custom charts
@@ -21,6 +21,9 @@ import com.comphenix.protocol.ProtocolLib;
import com.comphenix.protocol.ProtocolLibrary;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketListener;
import com.comphenix.protocol.utility.Util;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.libs.org.apache.commons.lang3.tuple.Pair;
import java.io.IOException;
@@ -36,22 +39,45 @@ public class Statistics {
metrics = new Metrics(plugin);
metrics.logFailedRequests(plugin.getProtocolConfig().isDebug());
// Determine who is using this library
addPluginUserGraph(metrics);
addCustomGraphs(metrics);
}
private void addPluginUserGraph(Metrics metrics) {
metrics.addCustomChart(new Metrics.AdvancedPie("Plugin Users", this::getPluginUsers));
metrics.addCustomChart(new Metrics.SimplePie("buildVersion", () -> splitVersion().getRight()));
private void addCustomGraphs(Metrics metrics) {
metrics.addCustomChart(new Metrics.AdvancedPie("pluginUsers", this::getPluginUsers));
metrics.addCustomChart(new Metrics.SimplePie("buildVersion", this::getBuildNumber));
metrics.addCustomChart(new Metrics.SimplePie("serverBrand", this::getServerBrand));
}
public static Pair<String, String> splitVersion() {
private String getServerBrand() {
// spigot doesn't overwrite the serverName, but paper does
if (!Bukkit.getServer().getName().equals("CraftBukkit")) {
return Bukkit.getServer().getName();
} else if (Util.isUsingSpigot()) {
return "Spigot";
} else {
return "CraftBukkit";
}
}
private String getBuildNumber() {
String version = ProtocolLibrary.getPlugin().getDescription().getVersion();
if (version.contains("-b")) {
String[] split = version.split("-b");
return Pair.of(split[0], split[1]);
return split[1];
} else if (!version.contains("SNAPSHOT")) {
return "Release";
} else {
return Pair.of(version, "Unknown");
return "Unknown";
}
}
public static String getVersion() {
String version = ProtocolLibrary.getPlugin().getDescription().getVersion();
if (version.contains("-b")) {
String[] split = version.split("-b");
return split[0];
} else {
return version;
}
}
@@ -47,16 +47,17 @@ public class BukkitCloner implements Cloner {
if (nmsClass != null) {
CLONERS.put(nmsClass, nmsObject -> fromHandle.apply(nmsObject).deepClone().getHandle());
}
} catch (RuntimeException ignored) { }
} catch (Throwable ignored) { }
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static void fromConverter(Supplier<Class<?>> getClass, EquivalentConverter converter) {
try {
Class<?> nmsClass = getClass.get();
if (nmsClass != null) {
CLONERS.put(nmsClass, nmsObject -> converter.getGeneric(converter.getSpecific(nmsObject)));
}
} catch (RuntimeException ignored) { }
} catch (Throwable ignored) { }
}
private static void fromManual(Supplier<Class<?>> getClass, Function<Object, Object> cloner) {
@@ -65,7 +66,7 @@ public class BukkitCloner implements Cloner {
if (nmsClass != null) {
CLONERS.put(nmsClass, cloner);
}
} catch (RuntimeException ignored) { }
} catch (Throwable ignored) { }
}
static {
@@ -80,9 +81,12 @@ public class BukkitCloner implements Cloner {
fromManual(MinecraftReflection::getNonNullListClass, source -> nonNullListCloner().clone(source));
fromWrapper(MinecraftReflection::getNBTBaseClass, NbtFactory::fromNMS);
fromWrapper(MinecraftReflection::getIChatBaseComponentClass, WrappedChatComponent::fromHandle);
fromManual(ComponentConverter::getBaseComponentArrayClass, source ->
ComponentConverter.clone((BaseComponent[]) source));
fromWrapper(WrappedVillagerData::getNmsClass, WrappedVillagerData::fromHandle);
try {
fromManual(ComponentConverter::getBaseComponentArrayClass, source ->
ComponentConverter.clone((BaseComponent[]) source));
} catch (Throwable ignored) { }
}
private Function<Object, Object> findCloner(Class<?> type) {
@@ -88,20 +88,15 @@ public final class SpigotUpdater extends Updater {
}
}
private static final String PROTOCOL = "https://";
private static final String RESOURCE_URL = PROTOCOL + "www.spigotmc.org/resources/protocollib.1997/";
private static final String API_URL = PROTOCOL + "www.spigotmc.org/api/general.php";
private static final String ACTION = "POST";
private static final int ID = 1997;
private static final byte[] API_KEY = ("key=98BE0FE67F88AB82B4C197FAF1DC3B69206EFDCC4D3B80FC83A00037510B99B4&resource=" + ID).getBytes(Charsets.UTF_8);
private static final String RESOURCE_URL = "https://www.spigotmc.org/resources/protocollib.1997/";
private static final String UPDATE_URL = "https://api.spigotmc.org/legacy/update.php?resource=1997";
private static final String ACTION = "GET";
public String getSpigotVersion() throws IOException {
try (Closer closer = Closer.create()) {
HttpURLConnection con = (HttpURLConnection) new URL(API_URL).openConnection();
HttpURLConnection con = (HttpURLConnection) new URL(UPDATE_URL).openConnection();
con.setDoOutput(true);
con.setRequestMethod(ACTION);
con.getOutputStream().write(API_KEY);
InputStreamReader isr = closer.register(new InputStreamReader(con.getInputStream()));
BufferedReader br = closer.register(new BufferedReader(isr));
@@ -271,21 +271,21 @@ public abstract class Updater {
private final String description;
private UpdateResult(String description) {
UpdateResult(String description) {
this.description = description;
}
@Override
public String toString() {
return description;
}
}
public static Updater create(ProtocolLib protocolLib, int id, File file, UpdateType type, boolean announce) {
public static Updater create(Plugin plugin, int id, File file, UpdateType type, boolean announce) {
if (Util.isUsingSpigot()) {
return new SpigotUpdater(protocolLib, type, announce);
return new SpigotUpdater(plugin, type, announce);
} else {
return new BukkitUpdater(protocolLib, id, file, type, announce);
return new BukkitUpdater(plugin, id, file, type, announce);
}
}
@@ -2,6 +2,7 @@ package com.comphenix.protocol.utility;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
@@ -12,7 +13,6 @@ import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.concurrent.GenericFutureListener;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
@@ -85,7 +85,7 @@ public class MinecraftMethods {
* @param playerConnection - the player connection.
* @return The
*/
public static Method getDisconnectMethod(Class<? extends Object> playerConnection) {
public static Method getDisconnectMethod(Class<?> playerConnection) {
try {
return FuzzyReflection.fromClass(playerConnection).getMethodByName("disconnect.*");
} catch (IllegalArgumentException e) {
@@ -95,7 +95,7 @@ public class MinecraftMethods {
}
/**
* Retrieve the handle(Packet, GenericFutureListener[]) method of network manager.
* Retrieve the handle/send packet method of network manager.
* <p>
* This only exists in version 1.7.2 and above.
* @return The handle method.
@@ -104,7 +104,12 @@ public class MinecraftMethods {
if (networkManagerHandle == null) {
networkManagerHandle = FuzzyReflection
.fromClass(MinecraftReflection.getNetworkManagerClass(), true)
.getMethodByParameters("handle", MinecraftReflection.getPacketClass());
.getMethod(FuzzyMethodContract.newBuilder()
.banModifier(Modifier.STATIC)
.returnTypeVoid()
.parameterCount(1)
.parameterExactType(MinecraftReflection.getPacketClass())
.build());
networkManagerHandle.setAccessible(true);
}
@@ -112,7 +117,7 @@ public class MinecraftMethods {
}
/**
* Retrieve the packetRead(ChannelHandlerContext, Packet) method of NetworkMananger.
* Retrieve the packetRead(ChannelHandlerContext, Packet) method of NetworkManager.
* <p>
* This only exists in version 1.7.2 and above.
* @return The packetRead method.
@@ -17,6 +17,7 @@
package com.comphenix.protocol.utility;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Bukkit;
@@ -44,20 +45,28 @@ public class Util {
*/
@SafeVarargs
public static <E> List<E> asList(E... elements) {
List<E> list = new ArrayList<E>(elements.length);
for (E element : elements) {
list.add(element);
}
List<E> list = new ArrayList<>(elements.length);
list.addAll(Arrays.asList(elements));
return list;
}
public static boolean classExists(String className) {
try {
Class.forName(className);
return true;
} catch (ClassNotFoundException ex) {
return false;
}
}
private static final boolean spigot = classExists("org.spigotmc.SpigotConfig");
/**
* Whether or not this server is running Spigot or a Spigot fork. This works by checking
* the server version for the Strings "Spigot" or "Paper".
* if the SpigotConfig exists, which should be true of all forks.
* @return True if it is, false if not.
*/
public static boolean isUsingSpigot() {
return Bukkit.getServer().getVersion().contains("Spigot") || Bukkit.getServer().getVersion().contains("Paper");
return spigot;
}
}
@@ -1133,8 +1133,7 @@ public class BukkitConverters {
private static MethodAccessor idFromDimension = null;
public static EquivalentConverter<Integer> getDimensionIDConverter() {
return new EquivalentConverter<Integer>() {
return ignoreNull(new EquivalentConverter<Integer>() {
@Override
public Object getGeneric(Integer specific) {
if (dimensionFromId == null) {
@@ -1149,7 +1148,7 @@ public class BukkitConverters {
dimensionFromId = Accessors.getMethodAccessor(reflection.getMethod(contract));
}
return dimensionFromId.invoke(null, (int) specific);
return dimensionFromId.invoke(null, specific);
}
@Override
@@ -1173,6 +1172,6 @@ public class BukkitConverters {
public Class<Integer> getSpecificType() {
return Integer.class;
}
};
});
}
}
@@ -422,7 +422,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);
DIRECTION_CLASS = getEnum(PacketType.Play.Server.SPAWN_ENTITY_PAINTING.getPacketClass(), 0);
CHAT_TYPE_CLASS = getEnum(PacketType.Play.Server.CHAT.getPacketClass(), 0);
associate(PROTOCOL_CLASS, Protocol.class, getClientCommandConverter());
@@ -22,9 +22,9 @@ import com.google.common.base.Preconditions;
* @author Kristian
*/
public class WrappedAttributeModifier extends AbstractWrapper {
private static final Class<?> OPERATION_CLASS = MinecraftReflection.getMinecraftClass("AttributeModifier$Operation");
private static final boolean OPERATION_ENUM = MinecraftVersion.atOrAbove(MinecraftVersion.VILLAGE_UPDATE);
private static final EquivalentConverter<Operation> OPERATION_CONVERTER = new IndexedEnumConverter<>(Operation.class, OPERATION_CLASS);
private static final Class<?> OPERATION_CLASS;
private static final EquivalentConverter<Operation> OPERATION_CONVERTER;
private static class IndexedEnumConverter<T extends Enum<T>> implements EquivalentConverter<T> {
private Class<T> specificClass;
@@ -65,6 +65,11 @@ public class WrappedAttributeModifier extends AbstractWrapper {
}
}
static {
OPERATION_CLASS = OPERATION_ENUM ? MinecraftReflection.getMinecraftClass("AttributeModifier$Operation") : null;
OPERATION_CONVERTER = OPERATION_ENUM ? new IndexedEnumConverter<>(Operation.class, OPERATION_CLASS) : null;
}
/**
* Represents the different modifier operations.
* <p>
@@ -235,8 +235,7 @@ public abstract class WrappedBlockData extends AbstractWrapper implements Clonab
}
private static WrappedBlockData createOldData(Material type) {
Object blockData = GET_BLOCK.invoke(null, type);
return new OldBlockData(blockData);
return createOldData(type, 0);
}
private static WrappedBlockData createOldData(Material type, int data) {
@@ -243,7 +243,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
* @return True if it does, false if not
*/
public boolean hasIndex(int index) {
return getObject(index) != null;
return getMap().containsKey(index);
}
/**
@@ -388,7 +388,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
* @param value New value
* @param update Whether or not to inform the client
*
* @see {@link #setObject(WrappedDataWatcherObject, Object, boolean)}
* @see WrappedDataWatcher#setObject(WrappedDataWatcherObject, Object, boolean)
* @throws IllegalArgumentException in 1.9 and up if there isn't already an
* object at this index
*/
@@ -415,7 +415,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
* @param value New value
* @param update Whether or not to inform the client
*
* @see {@link #setObject(WrappedDataWatcherObject, Object)}
* @see WrappedDataWatcher#setObject(WrappedDataWatcherObject, Object)
*/
public void setObject(int index, Serializer serializer, Object value, boolean update) {
setObject(new WrappedDataWatcherObject(index, serializer), value, update);
@@ -435,7 +435,7 @@ public class WrappedDataWatcher extends AbstractWrapper implements Iterable<Wrap
* @param value New value
* @param update Whether or not to inform the client
*
* @see {@link #setObject(int, Object, boolean)}
* @see WrappedDataWatcher#setObject(int, Object, boolean)
*/
public void setObject(int index, WrappedWatchableObject value, boolean update) {
setObject(index, value.getRawValue(), update);
@@ -448,7 +448,7 @@ public class PacketContainerTest {
int e = 0;
if (effect.isAmbient()) e |= 1;
if (effect.hasParticles()) e |= 2;
if (mobEffect.f()) e |= 4;
if (effect.hasIcon()) e |= 4;
assertEquals(e, (byte) packet.getBytes().read(2));
}
@@ -3,6 +3,7 @@
*/
package com.comphenix.protocol.updater;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -12,6 +13,8 @@ import java.util.logging.Logger;
import org.bukkit.Server;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.PluginDescriptionFile;
import org.junit.BeforeClass;
import org.junit.Test;
import com.comphenix.protocol.updater.Updater.UpdateType;
@@ -30,12 +33,17 @@ public class UpdaterTest {
plugin = mock(Plugin.class);
String version = System.getProperty("projectVersion");
if (version == null) version = "4.2.1";
if (version == null) version = "4.4.0";
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
public void testUpdaterType() {
assertEquals(Updater.create(plugin, BUKKIT_DEV_ID, null, UpdateType.NO_DOWNLOAD, true).getClass(), SpigotUpdater.class);
}
// @Test
public void testSpigotUpdater() {
@@ -40,7 +40,7 @@ public class WrappedDataWatcherTest {
@BeforeClass
public static void prepare() {
BukkitInitialization.initializePackage();
BukkitInitialization.initializeItemMeta();
}
@Test
@@ -94,4 +94,14 @@ public class WrappedDataWatcherTest {
// assertNull(Registry.get(ItemStack.class, false));
assertNotNull(Registry.get(UUID.class, true));
}
@Test
public void testHasIndex() {
WrappedDataWatcher watcher = new WrappedDataWatcher();
Serializer serializer = Registry.get(Integer.class);
assertFalse(watcher.hasIndex(0));
watcher.setObject(0, serializer, 1);
assertTrue(watcher.hasIndex(0));
}
}