Reimplement auto updater, fix legacy packets
Also a few minor bug fixes and improvements Fixes #127
Dieser Commit ist enthalten in:
Ursprung
e84fca699d
Commit
395d77e721
@ -1,4 +1,4 @@
|
|||||||
/*
|
/**
|
||||||
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
* ProtocolLib - Bukkit server library that allows access to the Minecraft protocol.
|
||||||
* Copyright (C) 2012 Kristian S. Stangeland
|
* Copyright (C) 2012 Kristian S. Stangeland
|
||||||
*
|
*
|
||||||
@ -14,7 +14,6 @@
|
|||||||
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
* if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
|
||||||
* 02111-1307 USA
|
* 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.comphenix.protocol;
|
package com.comphenix.protocol;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -36,7 +35,9 @@ import com.comphenix.protocol.error.ErrorReporter;
|
|||||||
import com.comphenix.protocol.events.PacketListener;
|
import com.comphenix.protocol.events.PacketListener;
|
||||||
import com.comphenix.protocol.timing.TimedListenerManager;
|
import com.comphenix.protocol.timing.TimedListenerManager;
|
||||||
import com.comphenix.protocol.timing.TimingReportGenerator;
|
import com.comphenix.protocol.timing.TimingReportGenerator;
|
||||||
import com.google.common.io.Closer;
|
import com.comphenix.protocol.updater.Updater;
|
||||||
|
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||||
|
import com.comphenix.protocol.utility.Closer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the "protocol" administration command.
|
* Handles the "protocol" administration command.
|
||||||
@ -50,10 +51,14 @@ class CommandProtocol extends CommandBase {
|
|||||||
public static final String NAME = "protocol";
|
public static final String NAME = "protocol";
|
||||||
|
|
||||||
private Plugin plugin;
|
private Plugin plugin;
|
||||||
|
private Updater updater;
|
||||||
|
private ProtocolConfig config;
|
||||||
|
|
||||||
public CommandProtocol(ErrorReporter reporter, Plugin plugin) {
|
public CommandProtocol(ErrorReporter reporter, Plugin plugin, Updater updater, ProtocolConfig config) {
|
||||||
super(reporter, CommandBase.PERMISSION_ADMIN, NAME, 1);
|
super(reporter, CommandBase.PERMISSION_ADMIN, NAME, 1);
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
|
this.updater = updater;
|
||||||
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -61,23 +66,37 @@ class CommandProtocol extends CommandBase {
|
|||||||
String subCommand = args[0];
|
String subCommand = args[0];
|
||||||
|
|
||||||
// Only return TRUE if we executed the correct command
|
// Only return TRUE if we executed the correct command
|
||||||
if (subCommand.equalsIgnoreCase("config") || subCommand.equalsIgnoreCase("reload"))
|
if (subCommand.equalsIgnoreCase("config") || subCommand.equalsIgnoreCase("reload")) {
|
||||||
reloadConfiguration(sender);
|
reloadConfiguration(sender);
|
||||||
else if (subCommand.equalsIgnoreCase("timings"))
|
} else if (subCommand.equalsIgnoreCase("check")) {
|
||||||
|
checkVersion(sender);
|
||||||
|
} else if (subCommand.equalsIgnoreCase("update")) {
|
||||||
|
updateVersion(sender);
|
||||||
|
} else if (subCommand.equalsIgnoreCase("timings")) {
|
||||||
toggleTimings(sender, args);
|
toggleTimings(sender, args);
|
||||||
else if (subCommand.equalsIgnoreCase("listeners"))
|
} else if (subCommand.equalsIgnoreCase("listeners")) {
|
||||||
printListeners(sender);
|
printListeners(sender, args);
|
||||||
else if (subCommand.equalsIgnoreCase("version"))
|
} else if (subCommand.equalsIgnoreCase("version")) {
|
||||||
printVersion(sender);
|
printVersion(sender);
|
||||||
else if (subCommand.equalsIgnoreCase("dump"))
|
} else if (subCommand.equalsIgnoreCase("dump")) {
|
||||||
dump(sender);
|
dump(sender);
|
||||||
else
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void checkVersion(final CommandSender sender) {
|
||||||
|
performUpdate(sender, UpdateType.NO_DOWNLOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateVersion(final CommandSender sender) {
|
||||||
|
performUpdate(sender, UpdateType.DEFAULT);
|
||||||
|
}
|
||||||
|
|
||||||
// Display every listener on the server
|
// Display every listener on the server
|
||||||
private void printListeners(final CommandSender sender) {
|
private void printListeners(final CommandSender sender, String[] args) {
|
||||||
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
|
ProtocolManager manager = ProtocolLibrary.getProtocolManager();
|
||||||
|
|
||||||
sender.sendMessage(ChatColor.GOLD + "Packet listeners:");
|
sender.sendMessage(ChatColor.GOLD + "Packet listeners:");
|
||||||
@ -92,6 +111,28 @@ class CommandProtocol extends CommandBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void performUpdate(final CommandSender sender, UpdateType type) {
|
||||||
|
if (updater.isChecking()) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Already checking for an update.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform on an async thread
|
||||||
|
Runnable notify = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (updater.shouldNotify() || config.isDebug()) {
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "[ProtocolLib] " + updater.getResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
updater.removeListener(this);
|
||||||
|
updateFinished();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
updater.start(type);
|
||||||
|
updater.addListener(notify);
|
||||||
|
}
|
||||||
|
|
||||||
private void toggleTimings(CommandSender sender, String[] args) {
|
private void toggleTimings(CommandSender sender, String[] args) {
|
||||||
TimedListenerManager manager = TimedListenerManager.getInstance();
|
TimedListenerManager manager = TimedListenerManager.getInstance();
|
||||||
boolean state = !manager.isTiming(); // toggle
|
boolean state = !manager.isTiming(); // toggle
|
||||||
@ -135,11 +176,27 @@ class CommandProtocol extends CommandBase {
|
|||||||
// Print to a text file
|
// Print to a text file
|
||||||
generator.saveTo(destination, manager);
|
generator.saveTo(destination, manager);
|
||||||
manager.clear();
|
manager.clear();
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
reporter.reportMinimal(plugin, "saveTimings()", e);
|
reporter.reportMinimal(plugin, "saveTimings()", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent further automatic updates until the next delay.
|
||||||
|
*/
|
||||||
|
public void updateFinished() {
|
||||||
|
long currentTime = System.currentTimeMillis() / ProtocolLibrary.MILLI_PER_SECOND;
|
||||||
|
|
||||||
|
config.setAutoLastTime(currentTime);
|
||||||
|
config.saveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reloadConfiguration(CommandSender sender) {
|
||||||
|
plugin.reloadConfig();
|
||||||
|
sender.sendMessage(ChatColor.YELLOW + "Reloaded configuration!");
|
||||||
|
}
|
||||||
|
|
||||||
private void printVersion(CommandSender sender) {
|
private void printVersion(CommandSender sender) {
|
||||||
PluginDescriptionFile desc = plugin.getDescription();
|
PluginDescriptionFile desc = plugin.getDescription();
|
||||||
|
|
||||||
@ -148,11 +205,6 @@ class CommandProtocol extends CommandBase {
|
|||||||
sender.sendMessage(ChatColor.WHITE + "Issues: " + ChatColor.GREEN + "https://github.com/dmulloy2/ProtocolLib/issues");
|
sender.sendMessage(ChatColor.WHITE + "Issues: " + ChatColor.GREEN + "https://github.com/dmulloy2/ProtocolLib/issues");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reloadConfiguration(CommandSender sender) {
|
|
||||||
plugin.reloadConfig();
|
|
||||||
sender.sendMessage(ChatColor.YELLOW + "Reloaded configuration!");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static SimpleDateFormat FILE_FORMAT;
|
private static SimpleDateFormat FILE_FORMAT;
|
||||||
private static SimpleDateFormat TIMESTAMP_FORMAT;
|
private static SimpleDateFormat TIMESTAMP_FORMAT;
|
||||||
|
|
||||||
@ -207,10 +259,7 @@ class CommandProtocol extends CommandBase {
|
|||||||
ProtocolLibrary.getStaticLogger().log(Level.SEVERE, "Failed to create dump:", ex);
|
ProtocolLibrary.getStaticLogger().log(Level.SEVERE, "Failed to create dump:", ex);
|
||||||
sender.sendMessage(ChatColor.RED + "Failed to create dump! Check console!");
|
sender.sendMessage(ChatColor.RED + "Failed to create dump! Check console!");
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
closer.close();
|
||||||
closer.close();
|
|
||||||
} catch (IOException ex1) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import java.io.Serializable;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
@ -11,6 +12,7 @@ import java.util.concurrent.Future;
|
|||||||
import org.apache.commons.lang.WordUtils;
|
import org.apache.commons.lang.WordUtils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketTypeLookup.ClassLookup;
|
||||||
import com.comphenix.protocol.events.ConnectionSide;
|
import com.comphenix.protocol.events.ConnectionSide;
|
||||||
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
import com.comphenix.protocol.injector.packet.PacketRegistry;
|
||||||
import com.comphenix.protocol.reflect.ObjectEnum;
|
import com.comphenix.protocol.reflect.ObjectEnum;
|
||||||
@ -635,7 +637,9 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
|||||||
* @param packetId - the packet ID.
|
* @param packetId - the packet ID.
|
||||||
* @return The corresponding packet type.
|
* @return The corresponding packet type.
|
||||||
* @throws IllegalArgumentException If the current packet could not be found.
|
* @throws IllegalArgumentException If the current packet could not be found.
|
||||||
|
* @deprecated IDs are no longer reliable
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static PacketType findCurrent(Protocol protocol, Sender sender, int packetId) {
|
public static PacketType findCurrent(Protocol protocol, Sender sender, int packetId) {
|
||||||
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
|
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
|
||||||
|
|
||||||
@ -645,13 +649,34 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
|||||||
"(Protocol: " + protocol + ", Sender: " + sender + ")");
|
"(Protocol: " + protocol + ", Sender: " + sender + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PacketType findCurrent(Protocol protocol, Sender sender, String name) {
|
||||||
|
name = format(protocol, sender, name);
|
||||||
|
PacketType type = getLookup().getFromCurrent(protocol, sender, name);
|
||||||
|
|
||||||
|
if (type != null) {
|
||||||
|
return type;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Cannot find packet " + name +
|
||||||
|
"(Protocol: " + protocol + ", Sender: " + sender + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private 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);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the given packet exists.
|
* Determine if the given packet exists.
|
||||||
* @param protocol - the protocol.
|
* @param protocol - the protocol.
|
||||||
* @param sender - the sender.
|
* @param sender - the sender.
|
||||||
* @param packetId - the packet ID.
|
* @param packetId - the packet ID.
|
||||||
* @return TRUE if it exists, FALSE otherwise.
|
* @return TRUE if it exists, FALSE otherwise.
|
||||||
|
* @deprecated IDs are no longer reliable
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static boolean hasCurrent(Protocol protocol, Sender sender, int packetId) {
|
public static boolean hasCurrent(Protocol protocol, Sender sender, int packetId) {
|
||||||
return getLookup().getFromCurrent(protocol, sender, packetId) != null;
|
return getLookup().getFromCurrent(protocol, sender, packetId) != null;
|
||||||
}
|
}
|
||||||
@ -680,7 +705,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a packet type from a protocol, sender and packet ID.
|
* Retrieve a packet type from a protocol, sender and packet ID, for pre-1.8.
|
||||||
* <p>
|
* <p>
|
||||||
* The packet will automatically be registered if its missing.
|
* The packet will automatically be registered if its missing.
|
||||||
* @param protocol - the current protocol.
|
* @param protocol - the current protocol.
|
||||||
@ -689,21 +714,59 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
|||||||
* @param packetClass - the packet class
|
* @param packetClass - the packet class
|
||||||
* @return The corresponding packet type.
|
* @return The corresponding packet type.
|
||||||
*/
|
*/
|
||||||
public static PacketType fromCurrent(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
|
public static PacketType fromID(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
|
||||||
String className = packetClass.getSimpleName();
|
PacketType type = getLookup().getFromCurrent(protocol, sender, packetId);
|
||||||
for (PacketType type : PacketType.values()) {
|
|
||||||
for (String name : type.classNames) {
|
if (type == null) {
|
||||||
if (className.equals(name)) {
|
type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, packetClass.getName());
|
||||||
return type;
|
type.dynamic = true;
|
||||||
}
|
|
||||||
}
|
// Many may be scheduled, but only the first will be executed
|
||||||
|
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
PacketType type = new PacketType(protocol, sender, packetId, -1, PROTOCOL_VERSION, className);
|
return type;
|
||||||
type.dynamic = true;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a packet type from a protocol, sender, ID, and class for 1.8+
|
||||||
|
* <p>
|
||||||
|
* The packet will automatically be registered if its missing.
|
||||||
|
* @param protocol - the current protocol.
|
||||||
|
* @param sender - the sender.
|
||||||
|
* @param packetId - the packet ID. Can be UNKNOWN_PACKET.
|
||||||
|
* @param packetClass - the packet class.
|
||||||
|
* @return The corresponding packet type.
|
||||||
|
*/
|
||||||
|
public static PacketType fromCurrent(Protocol protocol, Sender sender, int packetId, Class<?> packetClass) {
|
||||||
|
ClassLookup lookup = getLookup().getClassLookup();
|
||||||
|
Map<String, PacketType> map = lookup.getMap(protocol, sender);
|
||||||
|
|
||||||
|
// Check the map first
|
||||||
|
String className = packetClass.getSimpleName();
|
||||||
|
PacketType type = map.get(className);
|
||||||
|
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.dynamic = true;
|
||||||
|
|
||||||
|
// Many may be scheduled, but only the first will be executed
|
||||||
|
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
|
||||||
|
}
|
||||||
|
|
||||||
// Many may be scheduled, but only the first will be executed
|
|
||||||
scheduleRegister(type, "Dynamic-" + UUID.randomUUID().toString());
|
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -826,7 +889,7 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
|||||||
|
|
||||||
this.classNames = new String[names.length];
|
this.classNames = new String[names.length];
|
||||||
for (int i = 0; i < classNames.length; i++) {
|
for (int i = 0; i < classNames.length; i++) {
|
||||||
classNames[i] = String.format("Packet%s%s%s", protocol.getPacketName(), sender.getPacketName(), names[i]);
|
classNames[i] = format(protocol, sender, names[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -894,6 +957,10 @@ public class PacketType implements Serializable, Comparable<PacketType> {
|
|||||||
return currentId;
|
return currentId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String[] getClassNames() {
|
||||||
|
return classNames;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the equivalent packet class.
|
* Retrieve the equivalent packet class.
|
||||||
* @return The packet class, or NULL if not found.
|
* @return The packet class, or NULL if not found.
|
||||||
|
@ -2,6 +2,8 @@ package com.comphenix.protocol;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType.Protocol;
|
import com.comphenix.protocol.PacketType.Protocol;
|
||||||
import com.comphenix.protocol.PacketType.Sender;
|
import com.comphenix.protocol.PacketType.Sender;
|
||||||
@ -15,7 +17,7 @@ import com.google.common.collect.Multimap;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
class PacketTypeLookup {
|
class PacketTypeLookup {
|
||||||
private static class ProtocolSenderLookup {
|
public static class ProtocolSenderLookup {
|
||||||
// Unroll lookup for performance reasons
|
// Unroll lookup for performance reasons
|
||||||
public final IntegerMap<PacketType> HANDSHAKE_CLIENT = IntegerMap.newMap();
|
public final IntegerMap<PacketType> HANDSHAKE_CLIENT = IntegerMap.newMap();
|
||||||
public final IntegerMap<PacketType> HANDSHAKE_SERVER = IntegerMap.newMap();
|
public final IntegerMap<PacketType> HANDSHAKE_SERVER = IntegerMap.newMap();
|
||||||
@ -48,13 +50,49 @@ class PacketTypeLookup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ClassLookup {
|
||||||
|
// Unroll lookup for performance reasons
|
||||||
|
public final Map<String, PacketType> HANDSHAKE_CLIENT = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> HANDSHAKE_SERVER = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> GAME_CLIENT = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> GAME_SERVER = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> STATUS_CLIENT = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> STATUS_SERVER = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> LOGIN_CLIENT = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
public final Map<String, PacketType> LOGIN_SERVER = new ConcurrentHashMap<String, PacketType>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the correct integer map for a specific protocol and sender.
|
||||||
|
* @param protocol - the protocol.
|
||||||
|
* @param sender - the sender.
|
||||||
|
* @return The integer map of packets.
|
||||||
|
*/
|
||||||
|
public Map<String, PacketType> getMap(Protocol protocol, Sender sender) {
|
||||||
|
switch (protocol) {
|
||||||
|
case HANDSHAKING:
|
||||||
|
return sender == Sender.CLIENT ? HANDSHAKE_CLIENT : HANDSHAKE_SERVER;
|
||||||
|
case PLAY:
|
||||||
|
return sender == Sender.CLIENT ? GAME_CLIENT : GAME_SERVER;
|
||||||
|
case STATUS:
|
||||||
|
return sender == Sender.CLIENT ? STATUS_CLIENT : STATUS_SERVER;
|
||||||
|
case LOGIN:
|
||||||
|
return sender == Sender.CLIENT ? LOGIN_CLIENT : LOGIN_SERVER;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Unable to find protocol " + protocol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Packet IDs from 1.6.4 and below
|
// Packet IDs from 1.6.4 and below
|
||||||
private final IntegerMap<PacketType> legacyLookup = new IntegerMap<PacketType>();
|
private final IntegerMap<PacketType> legacyLookup = new IntegerMap<PacketType>();
|
||||||
private final IntegerMap<PacketType> serverLookup = new IntegerMap<PacketType>();
|
private final IntegerMap<PacketType> serverLookup = new IntegerMap<PacketType>();
|
||||||
private final IntegerMap<PacketType> clientLookup = new IntegerMap<PacketType>();
|
private final IntegerMap<PacketType> clientLookup = new IntegerMap<PacketType>();
|
||||||
|
|
||||||
// Packets for 1.7.2
|
// Packets for 1.7.2
|
||||||
private final ProtocolSenderLookup currentLookup = new ProtocolSenderLookup();
|
private final ProtocolSenderLookup idLookup = new ProtocolSenderLookup();
|
||||||
|
|
||||||
|
// Packets for 1.8+
|
||||||
|
private final ClassLookup classLookup = new ClassLookup();
|
||||||
|
|
||||||
// Packets based on name
|
// Packets based on name
|
||||||
private final Multimap<String, PacketType> nameLookup = HashMultimap.create();
|
private final Multimap<String, PacketType> nameLookup = HashMultimap.create();
|
||||||
@ -79,9 +117,9 @@ class PacketTypeLookup {
|
|||||||
}
|
}
|
||||||
// Skip unknown current packets
|
// Skip unknown current packets
|
||||||
if (type.getCurrentId() != PacketType.UNKNOWN_PACKET) {
|
if (type.getCurrentId() != PacketType.UNKNOWN_PACKET) {
|
||||||
currentLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
|
idLookup.getMap(type.getProtocol(), type.getSender()).put(type.getCurrentId(), type);
|
||||||
|
classLookup.getMap(type.getProtocol(), type.getSender()).put(type.getClassNames()[0], type);
|
||||||
}
|
}
|
||||||
// Save name
|
|
||||||
nameLookup.put(type.name(), type);
|
nameLookup.put(type.name(), type);
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
@ -132,8 +170,18 @@ class PacketTypeLookup {
|
|||||||
* @param sender - the sender.
|
* @param sender - the sender.
|
||||||
* @param packetId - the packet ID.
|
* @param packetId - the packet ID.
|
||||||
* @return The corresponding packet type, or NULL if not found.
|
* @return The corresponding packet type, or NULL if not found.
|
||||||
|
* @deprecated IDs are no longer reliable
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public PacketType getFromCurrent(Protocol protocol, Sender sender, int packetId) {
|
public PacketType getFromCurrent(Protocol protocol, Sender sender, int packetId) {
|
||||||
return currentLookup.getMap(protocol, sender).get(packetId);
|
return idLookup.getMap(protocol, sender).get(packetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PacketType getFromCurrent(Protocol protocol, Sender sender, String name) {
|
||||||
|
return classLookup.getMap(protocol, sender).get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassLookup getClassLookup() {
|
||||||
|
return classLookup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package com.comphenix.protocol;
|
package com.comphenix.protocol;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -25,8 +26,10 @@ import org.bukkit.configuration.ConfigurationSection;
|
|||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the configuration of ProtocolLib.
|
* Represents the configuration of ProtocolLib.
|
||||||
@ -34,7 +37,10 @@ import com.google.common.collect.Lists;
|
|||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
public class ProtocolConfig {
|
public class ProtocolConfig {
|
||||||
|
private static final String LAST_UPDATE_FILE = "lastupdate";
|
||||||
|
|
||||||
private static final String SECTION_GLOBAL = "global";
|
private static final String SECTION_GLOBAL = "global";
|
||||||
|
private static final String SECTION_AUTOUPDATER = "auto updater";
|
||||||
|
|
||||||
private static final String METRICS_ENABLED = "metrics";
|
private static final String METRICS_ENABLED = "metrics";
|
||||||
|
|
||||||
@ -48,16 +54,33 @@ public class ProtocolConfig {
|
|||||||
private static final String SCRIPT_ENGINE_NAME = "script engine";
|
private static final String SCRIPT_ENGINE_NAME = "script engine";
|
||||||
private static final String SUPPRESSED_REPORTS = "suppressed reports";
|
private static final String SUPPRESSED_REPORTS = "suppressed reports";
|
||||||
|
|
||||||
|
private static final String UPDATER_NOTIFY = "notify";
|
||||||
|
private static final String UPDATER_DOWNLAD = "download";
|
||||||
|
private static final String UPDATER_DELAY = "delay";
|
||||||
|
|
||||||
|
// Defaults
|
||||||
|
private static final long DEFAULT_UPDATER_DELAY = 43200;
|
||||||
|
|
||||||
private Plugin plugin;
|
private Plugin plugin;
|
||||||
private Configuration config;
|
private Configuration config;
|
||||||
private ConfigurationSection global;
|
private boolean loadingSections;
|
||||||
|
|
||||||
|
private ConfigurationSection global;
|
||||||
|
private ConfigurationSection updater;
|
||||||
|
|
||||||
|
// Last update time
|
||||||
|
private long lastUpdateTime;
|
||||||
private boolean configChanged;
|
private boolean configChanged;
|
||||||
|
private boolean valuesChanged;
|
||||||
|
|
||||||
// Modifications
|
// Modifications
|
||||||
private int modCount;
|
private int modCount;
|
||||||
|
|
||||||
public ProtocolConfig(Plugin plugin) {
|
public ProtocolConfig(Plugin plugin) {
|
||||||
|
this(plugin, plugin.getConfig());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProtocolConfig(Plugin plugin, Configuration config) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
}
|
}
|
||||||
@ -68,24 +91,118 @@ public class ProtocolConfig {
|
|||||||
public void reloadConfig() {
|
public void reloadConfig() {
|
||||||
// Reset
|
// Reset
|
||||||
configChanged = false;
|
configChanged = false;
|
||||||
|
valuesChanged = false;
|
||||||
modCount++;
|
modCount++;
|
||||||
|
|
||||||
this.config = plugin.getConfig();
|
this.config = plugin.getConfig();
|
||||||
if (config != null) {
|
this.lastUpdateTime = loadLastUpdate();
|
||||||
config.options().copyDefaults(true);
|
loadSections(!loadingSections);
|
||||||
global = config.getConfigurationSection(SECTION_GLOBAL);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the last update time stamp from the file system.
|
||||||
|
*
|
||||||
|
* @return Last update time stamp.
|
||||||
|
*/
|
||||||
|
private long loadLastUpdate() {
|
||||||
|
File dataFile = getLastUpdateFile();
|
||||||
|
|
||||||
|
if (dataFile.exists()) {
|
||||||
|
try {
|
||||||
|
return Long.parseLong(Files.toString(dataFile, Charsets.UTF_8));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
plugin.getLogger().warning("Cannot parse " + dataFile + " as a number.");
|
||||||
|
} catch (IOException e) {
|
||||||
|
plugin.getLogger().warning("Cannot read " + dataFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Default last update
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the given time stamp.
|
||||||
|
*
|
||||||
|
* @param value - time stamp to store.
|
||||||
|
*/
|
||||||
|
private void saveLastUpdate(long value) {
|
||||||
|
File dataFile = getLastUpdateFile();
|
||||||
|
|
||||||
|
// The data folder must exist
|
||||||
|
dataFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
if (dataFile.exists())
|
||||||
|
dataFile.delete();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.write(Long.toString(value), dataFile, Charsets.UTF_8);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Cannot write " + dataFile, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the file that is used to store the update time stamp.
|
||||||
|
*
|
||||||
|
* @return File storing the update time stamp.
|
||||||
|
*/
|
||||||
|
private File getLastUpdateFile() {
|
||||||
|
return new File(plugin.getDataFolder(), LAST_UPDATE_FILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load data sections.
|
||||||
|
*
|
||||||
|
* @param copyDefaults - whether or not to copy configuration defaults.
|
||||||
|
*/
|
||||||
|
private void loadSections(boolean copyDefaults) {
|
||||||
|
if (config != null) {
|
||||||
|
global = config.getConfigurationSection(SECTION_GLOBAL);
|
||||||
|
}
|
||||||
|
if (global != null) {
|
||||||
|
updater = global.getConfigurationSection(SECTION_AUTOUPDATER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Automatically copy defaults
|
||||||
|
if (copyDefaults && (!getFile().exists() || global == null || updater == null)) {
|
||||||
|
loadingSections = true;
|
||||||
|
|
||||||
|
if (config != null)
|
||||||
|
config.options().copyDefaults(true);
|
||||||
|
plugin.saveDefaultConfig();
|
||||||
|
plugin.reloadConfig();
|
||||||
|
loadingSections = false;
|
||||||
|
|
||||||
|
// Inform the user
|
||||||
|
ProtocolLibrary.log("Created default configuration.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a particular configuration key value pair.
|
||||||
|
*
|
||||||
|
* @param section - the configuration root.
|
||||||
|
* @param path - the path to the key.
|
||||||
|
* @param value - the value to set.
|
||||||
|
*/
|
||||||
private void setConfig(ConfigurationSection section, String path, Object value) {
|
private void setConfig(ConfigurationSection section, String path, Object value) {
|
||||||
configChanged = true;
|
configChanged = true;
|
||||||
section.set(path, value);
|
section.set(path, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <T> T getGlobalValue(String name, T def) {
|
private <T> T getGlobalValue(String path, T def) {
|
||||||
try {
|
try {
|
||||||
return (T) global.get(name, def);
|
return (T) global.get(path, def);
|
||||||
|
} catch (Throwable ex) {
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private <T> T getUpdaterValue(String path, T def) {
|
||||||
|
try {
|
||||||
|
return (T) updater.get(path, def);
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
return def;
|
return def;
|
||||||
}
|
}
|
||||||
@ -118,6 +235,44 @@ public class ProtocolConfig {
|
|||||||
global.set(DETAILED_ERROR, value);
|
global.set(DETAILED_ERROR, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve whether or not ProtocolLib should determine if a new version has been released.
|
||||||
|
*
|
||||||
|
* @return TRUE if it should do this automatically, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isAutoNotify() {
|
||||||
|
return getUpdaterValue(UPDATER_NOTIFY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not ProtocolLib should determine if a new version has been released.
|
||||||
|
*
|
||||||
|
* @param value - TRUE to do this automatically, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public void setAutoNotify(boolean value) {
|
||||||
|
setConfig(updater, UPDATER_NOTIFY, value);
|
||||||
|
modCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve whether or not ProtocolLib should automatically download the new version.
|
||||||
|
*
|
||||||
|
* @return TRUE if it should, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isAutoDownload() {
|
||||||
|
return updater != null && getUpdaterValue(UPDATER_DOWNLAD, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set whether or not ProtocolLib should automatically download the new version.
|
||||||
|
*
|
||||||
|
* @param value - TRUE if it should. FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public void setAutoDownload(boolean value) {
|
||||||
|
setConfig(updater, UPDATER_DOWNLAD, value);
|
||||||
|
modCount++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine whether or not debug mode is enabled.
|
* Determine whether or not debug mode is enabled.
|
||||||
* <p>
|
* <p>
|
||||||
@ -158,6 +313,31 @@ public class ProtocolConfig {
|
|||||||
modCount++;
|
modCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the amount of time to wait until checking for a new update.
|
||||||
|
*
|
||||||
|
* @return The amount of time to wait.
|
||||||
|
*/
|
||||||
|
public long getAutoDelay() {
|
||||||
|
// Note that the delay must be greater than 59 seconds
|
||||||
|
return Math.max(getUpdaterValue(UPDATER_DELAY, 0), DEFAULT_UPDATER_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the amount of time to wait until checking for a new update.
|
||||||
|
* <p>
|
||||||
|
* This time must be greater than 59 seconds.
|
||||||
|
*
|
||||||
|
* @param delaySeconds - the amount of time to wait.
|
||||||
|
*/
|
||||||
|
public void setAutoDelay(long delaySeconds) {
|
||||||
|
// Silently fix the delay
|
||||||
|
if (delaySeconds < DEFAULT_UPDATER_DELAY)
|
||||||
|
delaySeconds = DEFAULT_UPDATER_DELAY;
|
||||||
|
setConfig(updater, UPDATER_DELAY, delaySeconds);
|
||||||
|
modCount++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The version of Minecraft to ignore the built-in safety feature.
|
* The version of Minecraft to ignore the built-in safety feature.
|
||||||
*
|
*
|
||||||
@ -221,13 +401,34 @@ public class ProtocolConfig {
|
|||||||
modCount++;
|
modCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the last time we updated, in seconds since 1970.01.01 00:00.
|
||||||
|
*
|
||||||
|
* @return Last update time.
|
||||||
|
*/
|
||||||
|
public long getAutoLastTime() {
|
||||||
|
return lastUpdateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the last time we updated, in seconds since 1970.01.01 00:00.
|
||||||
|
* <p>
|
||||||
|
* Note that this is not considered to modify the configuration, so the modification count will not be incremented.
|
||||||
|
*
|
||||||
|
* @param lastTimeSeconds - new last update time.
|
||||||
|
*/
|
||||||
|
public void setAutoLastTime(long lastTimeSeconds) {
|
||||||
|
this.valuesChanged = true;
|
||||||
|
this.lastUpdateTime = lastTimeSeconds;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the unique name of the script engine to use for filtering.
|
* Retrieve the unique name of the script engine to use for filtering.
|
||||||
*
|
*
|
||||||
* @return Script engine to use.
|
* @return Script engine to use.
|
||||||
*/
|
*/
|
||||||
public String getScriptEngineName() {
|
public String getScriptEngineName() {
|
||||||
return global.getString(SCRIPT_ENGINE_NAME, "JavaScript");
|
return getGlobalValue(SCRIPT_ENGINE_NAME, "JavaScript");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -271,7 +472,7 @@ public class ProtocolConfig {
|
|||||||
/**
|
/**
|
||||||
* Set the starting injection method to use.
|
* Set the starting injection method to use.
|
||||||
*
|
*
|
||||||
* @param hook Injection method
|
* @return Injection method.
|
||||||
*/
|
*/
|
||||||
public void setInjectionMethod(PlayerInjectHooks hook) {
|
public void setInjectionMethod(PlayerInjectHooks hook) {
|
||||||
setConfig(global, INJECTION_METHOD, hook.name());
|
setConfig(global, INJECTION_METHOD, hook.name());
|
||||||
@ -291,10 +492,13 @@ public class ProtocolConfig {
|
|||||||
* Save the current configuration file.
|
* Save the current configuration file.
|
||||||
*/
|
*/
|
||||||
public void saveAll() {
|
public void saveAll() {
|
||||||
|
if (valuesChanged)
|
||||||
|
saveLastUpdate(lastUpdateTime);
|
||||||
if (configChanged)
|
if (configChanged)
|
||||||
plugin.saveConfig();
|
plugin.saveConfig();
|
||||||
|
|
||||||
// And we're done
|
// And we're done
|
||||||
|
valuesChanged = false;
|
||||||
configChanged = false;
|
configChanged = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -50,6 +50,8 @@ import com.comphenix.protocol.injector.PacketFilterManager;
|
|||||||
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
import com.comphenix.protocol.injector.PacketFilterManager.PlayerInjectHooks;
|
||||||
import com.comphenix.protocol.metrics.Statistics;
|
import com.comphenix.protocol.metrics.Statistics;
|
||||||
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
|
||||||
|
import com.comphenix.protocol.updater.Updater;
|
||||||
|
import com.comphenix.protocol.updater.Updater.UpdateType;
|
||||||
import com.comphenix.protocol.utility.ChatExtensions;
|
import com.comphenix.protocol.utility.ChatExtensions;
|
||||||
import com.comphenix.protocol.utility.EnhancerFactory;
|
import com.comphenix.protocol.utility.EnhancerFactory;
|
||||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
@ -97,6 +99,10 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
*/
|
*/
|
||||||
public static final String MINECRAFT_LAST_RELEASE_DATE = "2015-07-27";
|
public static final String MINECRAFT_LAST_RELEASE_DATE = "2015-07-27";
|
||||||
|
|
||||||
|
// Update information
|
||||||
|
static final String BUKKIT_DEV_SLUG = "protocollib";
|
||||||
|
static final int BUKKIT_DEV_ID = 45564;
|
||||||
|
|
||||||
// Different commands
|
// Different commands
|
||||||
private enum ProtocolCommand {
|
private enum ProtocolCommand {
|
||||||
FILTER,
|
FILTER,
|
||||||
@ -142,6 +148,10 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
// Settings/options
|
// Settings/options
|
||||||
private int configExpectedMod = -1;
|
private int configExpectedMod = -1;
|
||||||
|
|
||||||
|
// Updater
|
||||||
|
private Updater updater;
|
||||||
|
private static boolean UPDATES_DISABLED;
|
||||||
|
|
||||||
// Logger
|
// Logger
|
||||||
private static Logger logger;
|
private static Logger logger;
|
||||||
private Handler redirectHandler;
|
private Handler redirectHandler;
|
||||||
@ -205,6 +215,9 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
// Handle unexpected Minecraft versions
|
// Handle unexpected Minecraft versions
|
||||||
MinecraftVersion version = verifyMinecraftVersion();
|
MinecraftVersion version = verifyMinecraftVersion();
|
||||||
|
|
||||||
|
// Set updater - this will not perform any update automatically
|
||||||
|
updater = Updater.create(this, BUKKIT_DEV_ID, getFile(), UpdateType.NO_DOWNLOAD, true);
|
||||||
|
|
||||||
unhookTask = new DelayedSingleTask(this);
|
unhookTask = new DelayedSingleTask(this);
|
||||||
protocolManager = PacketFilterManager.newBuilder()
|
protocolManager = PacketFilterManager.newBuilder()
|
||||||
.classLoader(getClassLoader())
|
.classLoader(getClassLoader())
|
||||||
@ -254,7 +267,7 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
try {
|
try {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case PROTOCOL:
|
case PROTOCOL:
|
||||||
commandProtocol = new CommandProtocol(reporter, this);
|
commandProtocol = new CommandProtocol(reporter, this, updater, config);
|
||||||
break;
|
break;
|
||||||
case FILTER:
|
case FILTER:
|
||||||
commandFilter = new CommandFilter(reporter, this, config);
|
commandFilter = new CommandFilter(reporter, this, config);
|
||||||
@ -559,6 +572,11 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
|
|
||||||
// House keeping
|
// House keeping
|
||||||
updateConfiguration();
|
updateConfiguration();
|
||||||
|
|
||||||
|
// Check for updates too
|
||||||
|
if (!UPDATES_DISABLED && (tickCounter % 20) == 0) {
|
||||||
|
checkUpdates();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, ASYNC_MANAGER_DELAY, ASYNC_MANAGER_DELAY);
|
}, ASYNC_MANAGER_DELAY, ASYNC_MANAGER_DELAY);
|
||||||
} catch (OutOfMemoryError e) {
|
} catch (OutOfMemoryError e) {
|
||||||
@ -581,6 +599,29 @@ public class ProtocolLibrary extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkUpdates() {
|
||||||
|
// Ignore milliseconds - it's pointless
|
||||||
|
long currentTime = System.currentTimeMillis() / MILLI_PER_SECOND;
|
||||||
|
|
||||||
|
try {
|
||||||
|
long updateTime = config.getAutoLastTime() + config.getAutoDelay();
|
||||||
|
|
||||||
|
// Should we update?
|
||||||
|
if (currentTime > updateTime && !updater.isChecking()) {
|
||||||
|
// Initiate the update as if it came from the console
|
||||||
|
if (config.isAutoDownload())
|
||||||
|
commandProtocol.updateVersion(getServer().getConsoleSender());
|
||||||
|
else if (config.isAutoNotify())
|
||||||
|
commandProtocol.checkVersion(getServer().getConsoleSender());
|
||||||
|
else
|
||||||
|
commandProtocol.updateFinished();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
reporter.reportDetailed(this, Report.newBuilder(REPORT_CANNOT_UPDATE_PLUGIN).error(e));
|
||||||
|
UPDATES_DISABLED = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
if (skipDisable) {
|
if (skipDisable) {
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* 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.compat.netty;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.PacketType.Protocol;
|
||||||
|
import com.comphenix.protocol.PacketType.Sender;
|
||||||
|
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||||
|
import com.comphenix.protocol.injector.packet.MapContainer;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class LegacyProtocolRegistry extends ProtocolRegistry {
|
||||||
|
|
||||||
|
public LegacyProtocolRegistry() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initialize() {
|
||||||
|
final Object[] protocols = enumProtocol.getEnumConstants();
|
||||||
|
List<Map<Integer, Class<?>>> serverMaps = Lists.newArrayList();
|
||||||
|
List<Map<Integer, Class<?>>> clientMaps = Lists.newArrayList();
|
||||||
|
StructureModifier<Object> modifier = null;
|
||||||
|
|
||||||
|
// Result
|
||||||
|
Register result = new Register();
|
||||||
|
|
||||||
|
for (Object protocol : protocols) {
|
||||||
|
if (modifier == null)
|
||||||
|
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
|
||||||
|
StructureModifier<Map<Integer, Class<?>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
||||||
|
|
||||||
|
serverMaps.add(maps.read(0));
|
||||||
|
clientMaps.add(maps.read(1));
|
||||||
|
}
|
||||||
|
// Maps we have to occationally check have changed
|
||||||
|
for (Map<Integer, Class<?>> map : Iterables.concat(serverMaps, clientMaps)) {
|
||||||
|
result.containers.add(new MapContainer(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heuristic - there are more server packets than client packets
|
||||||
|
if (sum(clientMaps) > sum(serverMaps)) {
|
||||||
|
// Swap if this is violated
|
||||||
|
List<Map<Integer, Class<?>>> temp = serverMaps;
|
||||||
|
serverMaps = clientMaps;
|
||||||
|
clientMaps = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < protocols.length; i++) {
|
||||||
|
Enum<?> enumProtocol = (Enum<?>) protocols[i];
|
||||||
|
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
|
||||||
|
|
||||||
|
// Associate known types
|
||||||
|
associatePackets(result, serverMaps.get(i), equivalent, Sender.SERVER);
|
||||||
|
associatePackets(result, clientMaps.get(i), equivalent, Sender.CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchange (thread safe, as we have only one writer)
|
||||||
|
this.register = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
|
||||||
|
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
||||||
|
PacketType type = PacketType.fromID(protocol, sender, entry.getKey(), entry.getValue());
|
||||||
|
|
||||||
|
try {
|
||||||
|
register.typeToClass.put(type, entry.getValue());
|
||||||
|
|
||||||
|
if (sender == Sender.SERVER)
|
||||||
|
register.serverPackets.add(type);
|
||||||
|
if (sender == Sender.CLIENT)
|
||||||
|
register.clientPackets.add(type);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// Sometimes this happens with fake packets, just ignore it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* 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.compat.netty.independent;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.PacketType.Protocol;
|
||||||
|
import com.comphenix.protocol.PacketType.Sender;
|
||||||
|
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||||
|
import com.comphenix.protocol.injector.packet.MapContainer;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.google.common.collect.Maps;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author dmulloy2
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class NettyProtocolRegistry extends ProtocolRegistry {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void initialize() {
|
||||||
|
Object[] protocols = enumProtocol.getEnumConstants();
|
||||||
|
|
||||||
|
// ID to Packet class maps
|
||||||
|
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
|
||||||
|
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
|
||||||
|
|
||||||
|
Register result = new Register();
|
||||||
|
StructureModifier<Object> modifier = null;
|
||||||
|
|
||||||
|
// Iterate through the protocols
|
||||||
|
for (Object protocol : protocols) {
|
||||||
|
if (modifier == null)
|
||||||
|
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
|
||||||
|
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
||||||
|
for (Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
|
||||||
|
String direction = entry.getKey().toString();
|
||||||
|
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
||||||
|
serverMaps.put(protocol, entry.getValue());
|
||||||
|
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
|
||||||
|
clientMaps.put(protocol, entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maps we have to occationally check have changed
|
||||||
|
for (Map<Integer, Class<?>> map : serverMaps.values()) {
|
||||||
|
result.containers.add(new MapContainer(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map<Integer, Class<?>> map : clientMaps.values()) {
|
||||||
|
result.containers.add(new MapContainer(map));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < protocols.length; i++) {
|
||||||
|
Object protocol = protocols[i];
|
||||||
|
Enum<?> enumProtocol = (Enum<?>) protocol;
|
||||||
|
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
|
||||||
|
|
||||||
|
// Associate known types
|
||||||
|
if (serverMaps.containsKey(protocol))
|
||||||
|
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
|
||||||
|
if (clientMaps.containsKey(protocol))
|
||||||
|
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exchange (thread safe, as we have only one writer)
|
||||||
|
this.register = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
|
||||||
|
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
||||||
|
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
|
||||||
|
|
||||||
|
try {
|
||||||
|
register.typeToClass.put(type, entry.getValue());
|
||||||
|
|
||||||
|
if (sender == Sender.SERVER)
|
||||||
|
register.serverPackets.add(type);
|
||||||
|
if (sender == Sender.CLIENT)
|
||||||
|
register.clientPackets.add(type);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// Sometimes this happens with fake packets, just ignore it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,246 +0,0 @@
|
|||||||
package com.comphenix.protocol.injector.netty;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.PacketType.Protocol;
|
|
||||||
import com.comphenix.protocol.PacketType.Sender;
|
|
||||||
import com.comphenix.protocol.compat.netty.Netty;
|
|
||||||
import com.comphenix.protocol.injector.packet.MapContainer;
|
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.HashBiMap;
|
|
||||||
import com.google.common.collect.Iterables;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Maps;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a way of accessing the new netty Protocol enum.
|
|
||||||
* @author Kristian
|
|
||||||
*/
|
|
||||||
// TODO: Handle modifications to the BiMap
|
|
||||||
public class NettyProtocolRegistry {
|
|
||||||
/**
|
|
||||||
* Represents a register we are currently building.
|
|
||||||
* @author Kristian
|
|
||||||
*/
|
|
||||||
private static class Register {
|
|
||||||
// The main lookup table
|
|
||||||
public BiMap<PacketType, Class<?>> typeToClass = HashBiMap.create();
|
|
||||||
public volatile Set<PacketType> serverPackets = Sets.newHashSet();
|
|
||||||
public volatile Set<PacketType> clientPackets = Sets.newHashSet();
|
|
||||||
public List<MapContainer> containers = Lists.newArrayList();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if the current register is outdated.
|
|
||||||
* @return TRUE if it is, FALSE otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isOutdated() {
|
|
||||||
for (MapContainer container : containers) {
|
|
||||||
if (container.hasChanged()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Class<?> enumProtocol;
|
|
||||||
|
|
||||||
// Current register
|
|
||||||
private volatile Register register;
|
|
||||||
|
|
||||||
public NettyProtocolRegistry() {
|
|
||||||
enumProtocol = MinecraftReflection.getEnumProtocolClass();
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an immutable view of the packet type lookup.
|
|
||||||
* @return The packet type lookup.
|
|
||||||
*/
|
|
||||||
public Map<PacketType, Class<?>> getPacketTypeLookup() {
|
|
||||||
return Collections.unmodifiableMap(register.typeToClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve an immutable view of the class to packet type lookup.
|
|
||||||
* @return The packet type lookup.
|
|
||||||
*/
|
|
||||||
public Map<Class<?>, PacketType> getPacketClassLookup() {
|
|
||||||
return Collections.unmodifiableMap(register.typeToClass.inverse());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve every known client packet, from every protocol.
|
|
||||||
* @return Every client packet.
|
|
||||||
*/
|
|
||||||
public Set<PacketType> getClientPackets() {
|
|
||||||
return Collections.unmodifiableSet(register.clientPackets);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve every known server packet, from every protocol.
|
|
||||||
* @return Every server packet.
|
|
||||||
*/
|
|
||||||
public Set<PacketType> getServerPackets() {
|
|
||||||
return Collections.unmodifiableSet(register.serverPackets);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure that our local register is up-to-date with Minecraft.
|
|
||||||
* <p>
|
|
||||||
* This operation may block the calling thread.
|
|
||||||
*/
|
|
||||||
public synchronized void synchronize() {
|
|
||||||
// See if the register is outdated
|
|
||||||
if (register.isOutdated()) {
|
|
||||||
initialize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load the packet lookup tables in each protocol.
|
|
||||||
*/
|
|
||||||
private synchronized void initialize() {
|
|
||||||
if (!Netty.isIndependent()) { // Check for 1.7
|
|
||||||
initialize17();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Object[] protocols = enumProtocol.getEnumConstants();
|
|
||||||
|
|
||||||
// ID to Packet class maps
|
|
||||||
Map<Object, Map<Integer, Class<?>>> serverMaps = Maps.newLinkedHashMap();
|
|
||||||
Map<Object, Map<Integer, Class<?>>> clientMaps = Maps.newLinkedHashMap();
|
|
||||||
|
|
||||||
Register result = new Register();
|
|
||||||
StructureModifier<Object> modifier = null;
|
|
||||||
|
|
||||||
// Iterate through the protocols
|
|
||||||
for (Object protocol : protocols) {
|
|
||||||
if (modifier == null)
|
|
||||||
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
|
|
||||||
StructureModifier<Map<Object, Map<Integer, Class<?>>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
|
||||||
for (Entry<Object, Map<Integer, Class<?>>> entry : maps.read(0).entrySet()) {
|
|
||||||
String direction = entry.getKey().toString();
|
|
||||||
if (direction.contains("CLIENTBOUND")) { // Sent by Server
|
|
||||||
serverMaps.put(protocol, entry.getValue());
|
|
||||||
} else if (direction.contains("SERVERBOUND")) { // Sent by Client
|
|
||||||
clientMaps.put(protocol, entry.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maps we have to occationally check have changed
|
|
||||||
for (Map<Integer, Class<?>> map : serverMaps.values()) {
|
|
||||||
result.containers.add(new MapContainer(map));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map<Integer, Class<?>> map : clientMaps.values()) {
|
|
||||||
result.containers.add(new MapContainer(map));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Heuristic - there are more server packets than client packets
|
|
||||||
/* if (sum(clientMaps) > sum(serverMaps)) {
|
|
||||||
// Swap if this is violated
|
|
||||||
List<Map<Integer, Class<?>>> temp = serverMaps;
|
|
||||||
serverMaps = clientMaps;
|
|
||||||
clientMaps = temp;
|
|
||||||
} */
|
|
||||||
|
|
||||||
for (int i = 0; i < protocols.length; i++) {
|
|
||||||
Object protocol = protocols[i];
|
|
||||||
Enum<?> enumProtocol = (Enum<?>) protocol;
|
|
||||||
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
|
|
||||||
|
|
||||||
// Associate known types
|
|
||||||
if (serverMaps.containsKey(protocol))
|
|
||||||
associatePackets(result, serverMaps.get(protocol), equivalent, Sender.SERVER);
|
|
||||||
if (clientMaps.containsKey(protocol))
|
|
||||||
associatePackets(result, clientMaps.get(protocol), equivalent, Sender.CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange (thread safe, as we have only one writer)
|
|
||||||
this.register = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private synchronized void initialize17() {
|
|
||||||
final Object[] protocols = enumProtocol.getEnumConstants();
|
|
||||||
List<Map<Integer, Class<?>>> serverMaps = Lists.newArrayList();
|
|
||||||
List<Map<Integer, Class<?>>> clientMaps = Lists.newArrayList();
|
|
||||||
StructureModifier<Object> modifier = null;
|
|
||||||
|
|
||||||
// Result
|
|
||||||
Register result = new Register();
|
|
||||||
|
|
||||||
for (Object protocol : protocols) {
|
|
||||||
if (modifier == null)
|
|
||||||
modifier = new StructureModifier<Object>(protocol.getClass().getSuperclass(), false);
|
|
||||||
StructureModifier<Map<Integer, Class<?>>> maps = modifier.withTarget(protocol).withType(Map.class);
|
|
||||||
|
|
||||||
serverMaps.add(maps.read(0));
|
|
||||||
clientMaps.add(maps.read(1));
|
|
||||||
}
|
|
||||||
// Maps we have to occationally check have changed
|
|
||||||
for (Map<Integer, Class<?>> map : Iterables.concat(serverMaps, clientMaps)) {
|
|
||||||
result.containers.add(new MapContainer(map));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Heuristic - there are more server packets than client packets
|
|
||||||
if (sum(clientMaps) > sum(serverMaps)) {
|
|
||||||
// Swap if this is violated
|
|
||||||
List<Map<Integer, Class<?>>> temp = serverMaps;
|
|
||||||
serverMaps = clientMaps;
|
|
||||||
clientMaps = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < protocols.length; i++) {
|
|
||||||
Enum<?> enumProtocol = (Enum<?>) protocols[i];
|
|
||||||
Protocol equivalent = Protocol.fromVanilla(enumProtocol);
|
|
||||||
|
|
||||||
// Associate known types
|
|
||||||
associatePackets(result, serverMaps.get(i), equivalent, Sender.SERVER);
|
|
||||||
associatePackets(result, clientMaps.get(i), equivalent, Sender.CLIENT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exchange (thread safe, as we have only one writer)
|
|
||||||
this.register = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender) {
|
|
||||||
for (Entry<Integer, Class<?>> entry : lookup.entrySet()) {
|
|
||||||
PacketType type = PacketType.fromCurrent(protocol, sender, entry.getKey(), entry.getValue());
|
|
||||||
|
|
||||||
try {
|
|
||||||
register.typeToClass.put(type, entry.getValue());
|
|
||||||
|
|
||||||
if (sender == Sender.SERVER)
|
|
||||||
register.serverPackets.add(type);
|
|
||||||
if (sender == Sender.CLIENT)
|
|
||||||
register.clientPackets.add(type);
|
|
||||||
} catch (IllegalArgumentException ex) {
|
|
||||||
// Sometimes this happens with fake packets, just ignore it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the number of mapping in all the maps.
|
|
||||||
* @param maps - iterable of maps.
|
|
||||||
* @return The sum of all the entries.
|
|
||||||
*/
|
|
||||||
private int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
for (Map<Integer, Class<?>> map : maps)
|
|
||||||
count += map.size();
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,125 @@
|
|||||||
|
package com.comphenix.protocol.injector.netty;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.PacketType.Protocol;
|
||||||
|
import com.comphenix.protocol.PacketType.Sender;
|
||||||
|
import com.comphenix.protocol.injector.packet.MapContainer;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.google.common.collect.BiMap;
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a way of accessing the new netty Protocol enum.
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
// TODO: Handle modifications to the BiMap
|
||||||
|
public abstract class ProtocolRegistry {
|
||||||
|
/**
|
||||||
|
* Represents a register we are currently building.
|
||||||
|
* @author Kristian
|
||||||
|
*/
|
||||||
|
protected static class Register {
|
||||||
|
// The main lookup table
|
||||||
|
public BiMap<PacketType, Class<?>> typeToClass = HashBiMap.create();
|
||||||
|
public volatile Set<PacketType> serverPackets = Sets.newHashSet();
|
||||||
|
public volatile Set<PacketType> clientPackets = Sets.newHashSet();
|
||||||
|
public List<MapContainer> containers = Lists.newArrayList();
|
||||||
|
|
||||||
|
public Register() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the current register is outdated.
|
||||||
|
* @return TRUE if it is, FALSE otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isOutdated() {
|
||||||
|
for (MapContainer container : containers) {
|
||||||
|
if (container.hasChanged()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<?> enumProtocol;
|
||||||
|
|
||||||
|
// Current register
|
||||||
|
protected volatile Register register;
|
||||||
|
|
||||||
|
public ProtocolRegistry() {
|
||||||
|
enumProtocol = MinecraftReflection.getEnumProtocolClass();
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an immutable view of the packet type lookup.
|
||||||
|
* @return The packet type lookup.
|
||||||
|
*/
|
||||||
|
public Map<PacketType, Class<?>> getPacketTypeLookup() {
|
||||||
|
return Collections.unmodifiableMap(register.typeToClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an immutable view of the class to packet type lookup.
|
||||||
|
* @return The packet type lookup.
|
||||||
|
*/
|
||||||
|
public Map<Class<?>, PacketType> getPacketClassLookup() {
|
||||||
|
return Collections.unmodifiableMap(register.typeToClass.inverse());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every known client packet, from every protocol.
|
||||||
|
* @return Every client packet.
|
||||||
|
*/
|
||||||
|
public Set<PacketType> getClientPackets() {
|
||||||
|
return Collections.unmodifiableSet(register.clientPackets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve every known server packet, from every protocol.
|
||||||
|
* @return Every server packet.
|
||||||
|
*/
|
||||||
|
public Set<PacketType> getServerPackets() {
|
||||||
|
return Collections.unmodifiableSet(register.serverPackets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that our local register is up-to-date with Minecraft.
|
||||||
|
* <p>
|
||||||
|
* This operation may block the calling thread.
|
||||||
|
*/
|
||||||
|
public synchronized void synchronize() {
|
||||||
|
// See if the register is outdated
|
||||||
|
if (register.isOutdated()) {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the packet lookup tables in each protocol.
|
||||||
|
*/
|
||||||
|
protected abstract void initialize();
|
||||||
|
|
||||||
|
protected abstract void associatePackets(Register register, Map<Integer, Class<?>> lookup, Protocol protocol, Sender sender);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the number of mapping in all the maps.
|
||||||
|
* @param maps - iterable of maps.
|
||||||
|
* @return The sum of all the entries.
|
||||||
|
*/
|
||||||
|
protected final int sum(Iterable<? extends Map<Integer, Class<?>>> maps) {
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (Map<Integer, Class<?>> map : maps)
|
||||||
|
count += map.size();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
@ -25,12 +25,15 @@ import java.util.Set;
|
|||||||
import com.comphenix.protocol.PacketType;
|
import com.comphenix.protocol.PacketType;
|
||||||
import com.comphenix.protocol.PacketType.Sender;
|
import com.comphenix.protocol.PacketType.Sender;
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.compat.netty.LegacyProtocolRegistry;
|
||||||
|
import com.comphenix.protocol.compat.netty.independent.NettyProtocolRegistry;
|
||||||
import com.comphenix.protocol.error.Report;
|
import com.comphenix.protocol.error.Report;
|
||||||
import com.comphenix.protocol.error.ReportType;
|
import com.comphenix.protocol.error.ReportType;
|
||||||
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
|
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||||
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.InsufficientPacketsException;
|
import com.comphenix.protocol.injector.packet.LegacyPacketRegistry.InsufficientPacketsException;
|
||||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||||
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
import com.comphenix.protocol.wrappers.TroveWrapper.CannotFindTroveNoEntryValue;
|
import com.comphenix.protocol.wrappers.TroveWrapper.CannotFindTroveNoEntryValue;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
@ -49,7 +52,7 @@ public class PacketRegistry {
|
|||||||
|
|
||||||
// Two different packet registry
|
// Two different packet registry
|
||||||
private static volatile LegacyPacketRegistry LEGACY;
|
private static volatile LegacyPacketRegistry LEGACY;
|
||||||
private static volatile NettyProtocolRegistry NETTY;
|
private static volatile ProtocolRegistry NETTY;
|
||||||
|
|
||||||
// Cached for legacy
|
// Cached for legacy
|
||||||
private static volatile Set<PacketType> NETTY_SERVER_PACKETS;
|
private static volatile Set<PacketType> NETTY_SERVER_PACKETS;
|
||||||
@ -77,7 +80,11 @@ public class PacketRegistry {
|
|||||||
// Check for netty
|
// Check for netty
|
||||||
if (MinecraftReflection.isUsingNetty()) {
|
if (MinecraftReflection.isUsingNetty()) {
|
||||||
if (NETTY == null) {
|
if (NETTY == null) {
|
||||||
NETTY = new NettyProtocolRegistry();
|
if (MinecraftVersion.getCurrentVersion().isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE)) {
|
||||||
|
NETTY = new NettyProtocolRegistry();
|
||||||
|
} else {
|
||||||
|
NETTY = new LegacyProtocolRegistry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
initializeLegacy();
|
initializeLegacy();
|
||||||
|
@ -36,20 +36,12 @@ import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
|||||||
public class Util {
|
public class Util {
|
||||||
private static MethodAccessor getOnlinePlayers;
|
private static MethodAccessor getOnlinePlayers;
|
||||||
private static boolean reflectionRequired;
|
private static boolean reflectionRequired;
|
||||||
private static boolean isUsingSpigot;
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
Method method = Bukkit.class.getMethod("getOnlinePlayers");
|
Method method = Bukkit.class.getMethod("getOnlinePlayers");
|
||||||
getOnlinePlayers = Accessors.getMethodAccessor(method);
|
getOnlinePlayers = Accessors.getMethodAccessor(method);
|
||||||
reflectionRequired = !method.getReturnType().isAssignableFrom(Collection.class);
|
reflectionRequired = !method.getReturnType().isAssignableFrom(Collection.class);
|
||||||
|
|
||||||
try {
|
|
||||||
Class.forName("org.bukkit.entity.Player.Spigot");
|
|
||||||
isUsingSpigot = true;
|
|
||||||
} catch (ClassNotFoundException ex) {
|
|
||||||
isUsingSpigot = false;
|
|
||||||
}
|
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
throw new RuntimeException("Failed to obtain getOnlinePlayers method.", ex);
|
throw new RuntimeException("Failed to obtain getOnlinePlayers method.", ex);
|
||||||
}
|
}
|
||||||
@ -87,10 +79,10 @@ public class Util {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether or not this server is running Spigot. This works by checking
|
* Whether or not this server is running Spigot. This works by checking
|
||||||
* for a Spigot-specific API class, in this case {@link Player.Spigot}.
|
* the server version for the String "Spigot"
|
||||||
* @return True if it is, false if not.
|
* @return True if it is, false if not.
|
||||||
*/
|
*/
|
||||||
public static boolean isUsingSpigot() {
|
public static boolean isUsingSpigot() {
|
||||||
return isUsingSpigot;
|
return Bukkit.getServer().getVersion().contains("Spigot");
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -295,6 +295,8 @@ public abstract class EnumWrappers {
|
|||||||
if (INITIALIZED)
|
if (INITIALIZED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
INITIALIZED = true;
|
||||||
|
|
||||||
PROTOCOL_CLASS = getEnum(PacketType.Handshake.Client.SET_PROTOCOL.getPacketClass(), 0);
|
PROTOCOL_CLASS = getEnum(PacketType.Handshake.Client.SET_PROTOCOL.getPacketClass(), 0);
|
||||||
CLIENT_COMMAND_CLASS = getEnum(PacketType.Play.Client.CLIENT_COMMAND.getPacketClass(), 0);
|
CLIENT_COMMAND_CLASS = getEnum(PacketType.Play.Client.CLIENT_COMMAND.getPacketClass(), 0);
|
||||||
CHAT_VISIBILITY_CLASS = getEnum(PacketType.Play.Client.SETTINGS.getPacketClass(), 0);
|
CHAT_VISIBILITY_CLASS = getEnum(PacketType.Play.Client.SETTINGS.getPacketClass(), 0);
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
global:
|
global:
|
||||||
|
# Settings for the automatic version updater
|
||||||
|
auto updater:
|
||||||
|
notify: true
|
||||||
|
download: false
|
||||||
|
|
||||||
|
# Number of seconds to wait until a new update is downloaded
|
||||||
|
delay: 43200 # 12 hours
|
||||||
|
|
||||||
metrics: true
|
metrics: true
|
||||||
|
|
||||||
# Automatically compile structure modifiers
|
# Automatically compile structure modifiers
|
||||||
|
@ -10,7 +10,7 @@ database: false
|
|||||||
commands:
|
commands:
|
||||||
protocol:
|
protocol:
|
||||||
description: Performs administrative tasks regarding ProtocolLib.
|
description: Performs administrative tasks regarding ProtocolLib.
|
||||||
usage: /<command> config|timings|listeners|version|dump
|
usage: /<command> config|check|update|timings|listeners|version|dump
|
||||||
permission: protocol.admin
|
permission: protocol.admin
|
||||||
permission-message: You don't have <permission>
|
permission-message: You don't have <permission>
|
||||||
packet:
|
packet:
|
||||||
|
@ -24,7 +24,6 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||||
import com.comphenix.protocol.utility.SnapshotVersion;
|
|
||||||
|
|
||||||
public class MinecraftVersionTest {
|
public class MinecraftVersionTest {
|
||||||
@Test
|
@Test
|
||||||
@ -35,20 +34,27 @@ public class MinecraftVersionTest {
|
|||||||
MinecraftVersion lower = new MinecraftVersion(1, 0, 0);
|
MinecraftVersion lower = new MinecraftVersion(1, 0, 0);
|
||||||
MinecraftVersion highest = new MinecraftVersion(1, 4, 5);
|
MinecraftVersion highest = new MinecraftVersion(1, 4, 5);
|
||||||
|
|
||||||
|
MinecraftVersion atLeast = new MinecraftVersion(1, 8, 8);
|
||||||
|
|
||||||
// Make sure this is valid
|
// Make sure this is valid
|
||||||
assertTrue(lower.compareTo(within) < 0 && within.compareTo(highest) < 0);
|
assertTrue(lower.compareTo(within) < 0 && within.compareTo(highest) < 0);
|
||||||
assertFalse(outside.compareTo(within) < 0 && outside.compareTo(highest) < 0);
|
assertFalse(outside.compareTo(within) < 0 && outside.compareTo(highest) < 0);
|
||||||
|
assertTrue(atLeast.isAtLeast(MinecraftVersion.BOUNTIFUL_UPDATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
/* @Test
|
||||||
public void testSnapshotVersion() {
|
public void testSnapshotVersion() {
|
||||||
MinecraftVersion version = MinecraftVersion.fromServerVersion("git-Spigot-1119 (MC: 13w39b)");
|
MinecraftVersion version = MinecraftVersion.fromServerVersion("git-Spigot-1119 (MC: 13w39b)");
|
||||||
assertEquals(version.getSnapshot(), new SnapshotVersion("13w39b"));
|
assertEquals(version.getSnapshot(), new SnapshotVersion("13w39b"));
|
||||||
}
|
} */
|
||||||
|
|
||||||
|
@Test
|
||||||
public void testParsing() {
|
public void testParsing() {
|
||||||
assertEquals(MinecraftVersion.extractVersion("CraftBukkit R3.0 (MC: 1.4.3)"), "1.4.3");
|
assertEquals(MinecraftVersion.extractVersion("CraftBukkit R3.0 (MC: 1.4.3)"), "1.4.3");
|
||||||
assertEquals(MinecraftVersion.extractVersion("CraftBukkit Test Beta 1 (MC: 1.10.01 )"), "1.10.01");
|
assertEquals(MinecraftVersion.extractVersion("CraftBukkit Test Beta 1 (MC: 1.10.01 )"), "1.10.01");
|
||||||
assertEquals(MinecraftVersion.extractVersion("Hello (MC: 2.3.4 ) "), "2.3.4");
|
assertEquals(MinecraftVersion.extractVersion("Hello (MC: 2.3.4)"), "2.3.4");
|
||||||
|
|
||||||
|
assertEquals(MinecraftVersion.fromServerVersion("git-Cauldron-Reloaded-1.7.10-1.1388.1.0 (MC: 1.7.10)"), new MinecraftVersion(1, 7, 10));
|
||||||
|
assertEquals(MinecraftVersion.fromServerVersion("git-Bukkit-18fbb24 (MC: 1.8.8)"), new MinecraftVersion(1, 8, 8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,8 @@ import org.junit.Test;
|
|||||||
|
|
||||||
import com.comphenix.protocol.PacketType.Protocol;
|
import com.comphenix.protocol.PacketType.Protocol;
|
||||||
import com.comphenix.protocol.PacketType.Sender;
|
import com.comphenix.protocol.PacketType.Sender;
|
||||||
import com.comphenix.protocol.injector.netty.NettyProtocolRegistry;
|
import com.comphenix.protocol.compat.netty.independent.NettyProtocolRegistry;
|
||||||
|
import com.comphenix.protocol.injector.netty.ProtocolRegistry;
|
||||||
|
|
||||||
public class PacketTypeTest {
|
public class PacketTypeTest {
|
||||||
|
|
||||||
@ -22,12 +23,12 @@ public class PacketTypeTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFindCurrent() {
|
public void testFindCurrent() {
|
||||||
assertEquals(PacketType.Play.Client.STEER_VEHICLE, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, 12));
|
assertEquals(PacketType.Play.Client.STEER_VEHICLE, PacketType.findCurrent(Protocol.PLAY, Sender.CLIENT, "SteerVehicle"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void ensureAllExist() {
|
public void ensureAllExist() {
|
||||||
NettyProtocolRegistry registry = new NettyProtocolRegistry();
|
ProtocolRegistry registry = new NettyProtocolRegistry();
|
||||||
Map<PacketType, Class<?>> lookup = registry.getPacketTypeLookup();
|
Map<PacketType, Class<?>> lookup = registry.getPacketTypeLookup();
|
||||||
for (Entry<PacketType, Class<?>> entry : lookup.entrySet()) {
|
for (Entry<PacketType, Class<?>> entry : lookup.entrySet()) {
|
||||||
PacketType type = entry.getKey();
|
PacketType type = entry.getKey();
|
||||||
|
In neuem Issue referenzieren
Einen Benutzer sperren