Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a65ddbc43 | ||
|
|
54c252a354 | ||
|
|
e92abda187 | ||
|
|
3f7b7f4bb3 | ||
|
|
944b3f8280 | ||
|
|
b04fca8324 | ||
|
|
bfa0eee91e | ||
|
|
308e3d3417 | ||
|
|
42e48aa9b8 | ||
|
|
18d0193288 | ||
|
|
0ab552a6ef | ||
|
|
d9fef94bc6 | ||
|
|
ab5fb40f8f | ||
|
|
4baa4aa724 | ||
|
|
7a4a285935 | ||
|
|
f38c393d6f | ||
|
|
22c2a4abcc | ||
|
|
1a434e9ea2 | ||
|
|
25a5f1d07f |
No files matched your search
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user