2016-03-18 22:18:48 +01:00
|
|
|
package us.myles.ViaVersion.api.protocol;
|
2016-03-17 22:24:25 +01:00
|
|
|
|
2016-05-19 19:56:42 +02:00
|
|
|
import com.google.common.collect.Lists;
|
2018-07-03 14:58:00 +02:00
|
|
|
import com.google.common.collect.Range;
|
2016-05-19 19:56:42 +02:00
|
|
|
import com.google.common.collect.Sets;
|
2016-03-22 19:02:46 +01:00
|
|
|
import us.myles.ViaVersion.api.Pair;
|
2016-09-25 15:39:37 +02:00
|
|
|
import us.myles.ViaVersion.api.Via;
|
2016-04-22 14:28:54 +02:00
|
|
|
import us.myles.ViaVersion.protocols.base.BaseProtocol;
|
2018-07-03 14:58:00 +02:00
|
|
|
import us.myles.ViaVersion.protocols.base.BaseProtocol1_7;
|
2016-06-08 16:38:59 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.Protocol1_10To1_9_3_4;
|
2016-12-20 21:54:28 +01:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_11_1to1_11.Protocol1_11_1To1_11;
|
2016-10-04 20:04:49 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_11to1_10.Protocol1_11To1_10;
|
2019-04-23 16:34:17 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_12_1to1_12.Protocol1_12_1To1_12;
|
|
|
|
import us.myles.ViaVersion.protocols.protocol1_12_2to1_12_1.Protocol1_12_2To1_12_1;
|
2017-06-01 18:49:07 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_12to1_11_1.Protocol1_12To1_11_1;
|
2018-10-17 15:38:59 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_13_2to1_13_1.Protocol1_13_2To1_13_1;
|
2018-08-01 20:20:52 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.Protocol1_13To1_12_2;
|
2019-04-23 16:34:17 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.Protocol1_9_1_2To1_9_3_4;
|
|
|
|
import us.myles.ViaVersion.protocols.protocol1_9_1to1_9.Protocol1_9_1To1_9;
|
|
|
|
import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3To1_9_1_2;
|
|
|
|
import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9To1_8;
|
|
|
|
import us.myles.ViaVersion.protocols.protocol1_9to1_9_1.Protocol1_9To1_9_1;
|
2018-08-22 18:05:24 +02:00
|
|
|
import us.myles.ViaVersion.protocols.protocol1_13_1to1_13.Protocol1_13_1To1_13;
|
2016-03-17 22:24:25 +01:00
|
|
|
|
|
|
|
import java.util.*;
|
2016-05-19 19:56:42 +02:00
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
2016-03-17 22:24:25 +01:00
|
|
|
|
|
|
|
public class ProtocolRegistry {
|
2016-05-19 19:56:42 +02:00
|
|
|
public static final Protocol BASE_PROTOCOL = new BaseProtocol();
|
2016-03-18 22:18:48 +01:00
|
|
|
public static int SERVER_PROTOCOL = -1;
|
2016-03-17 22:24:25 +01:00
|
|
|
// Input Version -> Output Version & Protocol (Allows fast lookup)
|
2016-09-27 18:31:10 +02:00
|
|
|
private static final Map<Integer, Map<Integer, Protocol>> registryMap = new ConcurrentHashMap<>();
|
|
|
|
private static final Map<Pair<Integer, Integer>, List<Pair<Integer, Protocol>>> pathCache = new ConcurrentHashMap<>();
|
|
|
|
private static final List<Protocol> registerList = Lists.newCopyOnWriteArrayList();
|
|
|
|
private static final Set<Integer> supportedVersions = Sets.newConcurrentHashSet();
|
2018-07-03 14:58:00 +02:00
|
|
|
private static final List<Pair<Range<Integer>, Protocol>> baseProtocols = Lists.newCopyOnWriteArrayList();
|
2016-03-17 22:24:25 +01:00
|
|
|
|
|
|
|
static {
|
2016-04-22 14:28:54 +02:00
|
|
|
// Base Protocol
|
2018-07-03 14:58:00 +02:00
|
|
|
registerBaseProtocol(BASE_PROTOCOL, Range.lessThan(Integer.MIN_VALUE));
|
2018-07-16 20:44:56 +02:00
|
|
|
registerBaseProtocol(new BaseProtocol1_7(), Range.<Integer>all());
|
2018-07-03 14:58:00 +02:00
|
|
|
|
2016-03-17 22:24:25 +01:00
|
|
|
// Register built in protocols
|
2019-04-23 16:34:17 +02:00
|
|
|
registerProtocol(new Protocol1_9To1_8(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_8.getId());
|
|
|
|
registerProtocol(new Protocol1_9_1To1_9(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9.getId());
|
|
|
|
registerProtocol(new Protocol1_9_3To1_9_1_2(), Collections.singletonList(ProtocolVersion.v1_9_3.getId()), ProtocolVersion.v1_9_2.getId());
|
2016-05-17 23:48:56 +02:00
|
|
|
// Only supported for 1.9.4 server to 1.9 (nothing else)
|
2019-04-23 16:34:17 +02:00
|
|
|
registerProtocol(new Protocol1_9To1_9_1(), Collections.singletonList(ProtocolVersion.v1_9.getId()), ProtocolVersion.v1_9_2.getId());
|
|
|
|
registerProtocol(new Protocol1_9_1_2To1_9_3_4(), Arrays.asList(ProtocolVersion.v1_9_1.getId(), ProtocolVersion.v1_9_2.getId()), ProtocolVersion.v1_9_3.getId());
|
2016-06-08 18:00:21 +02:00
|
|
|
registerProtocol(new Protocol1_10To1_9_3_4(), Collections.singletonList(ProtocolVersion.v1_10.getId()), ProtocolVersion.v1_9_3.getId());
|
2016-05-17 23:48:56 +02:00
|
|
|
|
2017-02-08 15:10:18 +01:00
|
|
|
registerProtocol(new Protocol1_11To1_10(), Collections.singletonList(ProtocolVersion.v1_11.getId()), ProtocolVersion.v1_10.getId());
|
|
|
|
registerProtocol(new Protocol1_11_1To1_11(), Collections.singletonList(ProtocolVersion.v1_11_1.getId()), ProtocolVersion.v1_11.getId());
|
2017-06-07 17:50:22 +02:00
|
|
|
|
2017-08-01 15:34:22 +02:00
|
|
|
registerProtocol(new Protocol1_12To1_11_1(), Collections.singletonList(ProtocolVersion.v1_12.getId()), ProtocolVersion.v1_11_1.getId());
|
2019-04-23 16:34:17 +02:00
|
|
|
registerProtocol(new Protocol1_12_1To1_12(), Collections.singletonList(ProtocolVersion.v1_12_1.getId()), ProtocolVersion.v1_12.getId());
|
|
|
|
registerProtocol(new Protocol1_12_2To1_12_1(), Collections.singletonList(ProtocolVersion.v1_12_2.getId()), ProtocolVersion.v1_12_1.getId());
|
2017-10-26 15:39:57 +02:00
|
|
|
|
2018-07-18 19:10:43 +02:00
|
|
|
registerProtocol(new Protocol1_13To1_12_2(), Collections.singletonList(ProtocolVersion.v1_13.getId()), ProtocolVersion.v1_12_2.getId());
|
2018-10-27 13:25:42 +02:00
|
|
|
registerProtocol(new Protocol1_13_1To1_13(), Arrays.asList(ProtocolVersion.v1_13_1.getId()), ProtocolVersion.v1_13.getId());
|
|
|
|
registerProtocol(new Protocol1_13_2To1_13_1(), Arrays.asList(ProtocolVersion.v1_13_2.getId()), ProtocolVersion.v1_13_1.getId());
|
2019-04-23 16:40:47 +02:00
|
|
|
|
|
|
|
registerProtocol(new Protocol1_14To1_13_2(), Arrays.asList(ProtocolVersion.v1_14.getId()), ProtocolVersion.v1_13_2.getId());
|
2016-03-17 22:24:25 +01:00
|
|
|
}
|
|
|
|
|
2016-03-22 19:02:46 +01:00
|
|
|
/**
|
|
|
|
* Register a protocol
|
|
|
|
*
|
|
|
|
* @param protocol The protocol to register.
|
|
|
|
* @param supported Supported client versions.
|
|
|
|
* @param output The output server version it converts to.
|
|
|
|
*/
|
2016-03-17 22:24:25 +01:00
|
|
|
public static void registerProtocol(Protocol protocol, List<Integer> supported, Integer output) {
|
2016-03-23 15:00:48 +01:00
|
|
|
// Clear cache as this may make new routes.
|
|
|
|
if (pathCache.size() > 0)
|
|
|
|
pathCache.clear();
|
|
|
|
|
2016-03-17 22:24:25 +01:00
|
|
|
for (Integer version : supported) {
|
|
|
|
if (!registryMap.containsKey(version)) {
|
|
|
|
registryMap.put(version, new HashMap<Integer, Protocol>());
|
|
|
|
}
|
|
|
|
|
|
|
|
registryMap.get(version).put(output, protocol);
|
|
|
|
}
|
2016-04-04 00:30:10 +02:00
|
|
|
|
2016-09-25 15:39:37 +02:00
|
|
|
if (Via.getPlatform().isPluginEnabled()) {
|
2016-04-04 00:30:10 +02:00
|
|
|
protocol.registerListeners();
|
2016-09-25 21:05:58 +02:00
|
|
|
protocol.register(Via.getManager().getProviders());
|
2016-05-19 19:56:42 +02:00
|
|
|
refreshVersions();
|
2016-04-04 00:30:10 +02:00
|
|
|
} else {
|
|
|
|
registerList.add(protocol);
|
|
|
|
}
|
2016-03-17 22:24:25 +01:00
|
|
|
}
|
|
|
|
|
2018-07-03 14:58:00 +02:00
|
|
|
/**
|
|
|
|
* Registers a base protocol.
|
|
|
|
* Base Protocols registered later have higher priority
|
|
|
|
* Only one base protocol will be added to pipeline
|
|
|
|
*
|
2018-10-27 13:25:42 +02:00
|
|
|
* @param baseProtocol Base Protocol to register
|
2018-07-03 14:58:00 +02:00
|
|
|
* @param supportedProtocols Versions that baseProtocol supports
|
|
|
|
*/
|
|
|
|
public static void registerBaseProtocol(Protocol baseProtocol, Range<Integer> supportedProtocols) {
|
|
|
|
baseProtocols.add(new Pair<>(supportedProtocols, baseProtocol));
|
|
|
|
if (Via.getPlatform().isPluginEnabled()) {
|
|
|
|
baseProtocol.registerListeners();
|
|
|
|
baseProtocol.register(Via.getManager().getProviders());
|
|
|
|
refreshVersions();
|
|
|
|
} else {
|
|
|
|
registerList.add(baseProtocol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-19 19:56:42 +02:00
|
|
|
public static void refreshVersions() {
|
|
|
|
supportedVersions.clear();
|
|
|
|
|
|
|
|
supportedVersions.add(ProtocolRegistry.SERVER_PROTOCOL);
|
|
|
|
for (ProtocolVersion versions : ProtocolVersion.getProtocols()) {
|
|
|
|
List<Pair<Integer, Protocol>> paths = getProtocolPath(versions.getId(), ProtocolRegistry.SERVER_PROTOCOL);
|
|
|
|
if (paths == null) continue;
|
|
|
|
supportedVersions.add(versions.getId());
|
|
|
|
for (Pair<Integer, Protocol> path : paths)
|
|
|
|
supportedVersions.add(path.getKey());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-07-01 17:36:19 +02:00
|
|
|
/**
|
|
|
|
* Get the versions compatible with the server.
|
|
|
|
*
|
|
|
|
* @return Read-only set of the versions.
|
|
|
|
*/
|
2016-05-19 19:56:42 +02:00
|
|
|
public static SortedSet<Integer> getSupportedVersions() {
|
|
|
|
return Collections.unmodifiableSortedSet(new TreeSet<>(supportedVersions));
|
|
|
|
}
|
|
|
|
|
2016-03-22 19:02:46 +01:00
|
|
|
/**
|
|
|
|
* Check if this plugin is useful to the server.
|
|
|
|
*
|
|
|
|
* @return True if there is a useful pipe
|
|
|
|
*/
|
2016-03-17 22:24:25 +01:00
|
|
|
public static boolean isWorkingPipe() {
|
|
|
|
for (Map<Integer, Protocol> maps : registryMap.values()) {
|
|
|
|
if (maps.containsKey(SERVER_PROTOCOL)) return true;
|
|
|
|
}
|
|
|
|
return false; // No destination for protocol
|
|
|
|
}
|
|
|
|
|
2016-04-04 00:30:10 +02:00
|
|
|
/**
|
|
|
|
* Called when the server is enabled, to register any non registered listeners.
|
|
|
|
*/
|
2016-09-25 19:06:04 +02:00
|
|
|
public static void onServerLoaded() {
|
2016-04-04 00:30:10 +02:00
|
|
|
for (Protocol protocol : registerList) {
|
|
|
|
protocol.registerListeners();
|
2016-09-25 21:05:58 +02:00
|
|
|
protocol.register(Via.getManager().getProviders());
|
2016-04-04 00:30:10 +02:00
|
|
|
}
|
|
|
|
registerList.clear();
|
|
|
|
}
|
|
|
|
|
2016-03-22 19:02:46 +01:00
|
|
|
/**
|
|
|
|
* Calculate a path to get from an input protocol to the servers protocol.
|
|
|
|
*
|
|
|
|
* @param current The current items in the path
|
|
|
|
* @param clientVersion The current input version
|
|
|
|
* @param serverVersion The desired output version
|
|
|
|
* @return The path which has been generated, null if failed.
|
|
|
|
*/
|
2016-03-17 22:24:25 +01:00
|
|
|
private static List<Pair<Integer, Protocol>> getProtocolPath(List<Pair<Integer, Protocol>> current, int clientVersion, int serverVersion) {
|
2016-05-19 19:56:42 +02:00
|
|
|
if (clientVersion == serverVersion) return null; // We're already there
|
2016-03-17 22:24:25 +01:00
|
|
|
if (current.size() > 50) return null; // Fail safe, protocol too complicated.
|
|
|
|
|
|
|
|
// First check if there is any protocols for this
|
2018-09-30 20:48:23 +02:00
|
|
|
Map<Integer, Protocol> inputMap = registryMap.get(clientVersion);
|
|
|
|
if (inputMap == null) {
|
2016-03-17 22:24:25 +01:00
|
|
|
return null; // Not supported
|
|
|
|
}
|
|
|
|
// Next check there isn't an obvious path
|
2018-09-30 20:48:23 +02:00
|
|
|
Protocol protocol = inputMap.get(serverVersion);
|
|
|
|
if (protocol != null) {
|
|
|
|
current.add(new Pair<>(serverVersion, protocol));
|
2016-03-17 22:24:25 +01:00
|
|
|
return current; // Easy solution
|
|
|
|
}
|
|
|
|
// There might be a more advanced solution... So we'll see if any of the others can get us there
|
2016-05-17 23:48:56 +02:00
|
|
|
List<Pair<Integer, Protocol>> shortest = null;
|
|
|
|
|
2016-03-17 22:24:25 +01:00
|
|
|
for (Map.Entry<Integer, Protocol> entry : inputMap.entrySet()) {
|
|
|
|
// Ensure it wasn't caught by the other loop
|
|
|
|
if (!entry.getKey().equals(serverVersion)) {
|
|
|
|
Pair<Integer, Protocol> pair = new Pair<>(entry.getKey(), entry.getValue());
|
|
|
|
// Ensure no recursion
|
|
|
|
if (!current.contains(pair)) {
|
|
|
|
// Create a copy
|
|
|
|
List<Pair<Integer, Protocol>> newCurrent = new ArrayList<>(current);
|
|
|
|
newCurrent.add(pair);
|
|
|
|
// Calculate the rest of the protocol using the current
|
|
|
|
newCurrent = getProtocolPath(newCurrent, entry.getKey(), serverVersion);
|
|
|
|
if (newCurrent != null) {
|
2016-05-17 23:48:56 +02:00
|
|
|
// If it's shorter then choose it
|
|
|
|
if (shortest == null || shortest.size() > newCurrent.size()) {
|
|
|
|
shortest = newCurrent;
|
|
|
|
}
|
2016-03-17 22:24:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-17 23:48:56 +02:00
|
|
|
return shortest; // null if none found
|
2016-03-17 22:24:25 +01:00
|
|
|
}
|
|
|
|
|
2016-03-22 19:02:46 +01:00
|
|
|
/**
|
|
|
|
* Calculate a path from a client version to server version
|
|
|
|
*
|
|
|
|
* @param clientVersion The input client version
|
|
|
|
* @param serverVersion The desired output server version
|
|
|
|
* @return The path it generated, null if it failed.
|
|
|
|
*/
|
2016-03-17 22:24:25 +01:00
|
|
|
public static List<Pair<Integer, Protocol>> getProtocolPath(int clientVersion, int serverVersion) {
|
2016-03-23 15:00:48 +01:00
|
|
|
Pair<Integer, Integer> protocolKey = new Pair<>(clientVersion, serverVersion);
|
|
|
|
// Check cache
|
2018-09-30 20:48:23 +02:00
|
|
|
List<Pair<Integer, Protocol>> protocolList = pathCache.get(protocolKey);
|
|
|
|
if (protocolList != null) {
|
|
|
|
return protocolList;
|
2016-03-23 15:00:48 +01:00
|
|
|
}
|
|
|
|
// Generate path
|
|
|
|
List<Pair<Integer, Protocol>> outputPath = getProtocolPath(new ArrayList<Pair<Integer, Protocol>>(), clientVersion, serverVersion);
|
|
|
|
// If it found a path, cache it.
|
|
|
|
if (outputPath != null) {
|
|
|
|
pathCache.put(protocolKey, outputPath);
|
|
|
|
}
|
|
|
|
return outputPath;
|
2016-03-17 22:24:25 +01:00
|
|
|
}
|
2018-07-03 14:58:00 +02:00
|
|
|
|
|
|
|
public static Protocol getBaseProtocol(int serverVersion) {
|
2018-07-03 16:26:00 +02:00
|
|
|
for (Pair<Range<Integer>, Protocol> rangeProtocol : Lists.reverse(baseProtocols)) {
|
|
|
|
if (rangeProtocol.getKey().contains(serverVersion)) {
|
2018-07-03 14:58:00 +02:00
|
|
|
return rangeProtocol.getValue();
|
2018-07-03 16:26:00 +02:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 14:58:00 +02:00
|
|
|
throw new IllegalStateException("No Base Protocol for " + serverVersion);
|
|
|
|
}
|
2018-07-03 16:19:32 +02:00
|
|
|
|
|
|
|
public static boolean isBaseProtocol(Protocol protocol) {
|
2018-07-03 16:26:00 +02:00
|
|
|
for (Pair<Range<Integer>, Protocol> p : baseProtocols) {
|
|
|
|
if (p.getValue() == protocol) {
|
2018-07-03 16:19:32 +02:00
|
|
|
return true;
|
2018-07-03 16:26:00 +02:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 16:19:32 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-03-17 22:24:25 +01:00
|
|
|
}
|