diff --git a/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManager.java b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManager.java index 904d8fa94..a8aa831ee 100644 --- a/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManager.java +++ b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManager.java @@ -24,7 +24,6 @@ package us.myles.ViaVersion.api.protocol; import com.google.common.collect.Range; import org.jetbrains.annotations.Nullable; -import us.myles.ViaVersion.api.Pair; import java.util.List; import java.util.SortedSet; @@ -87,10 +86,10 @@ public interface ProtocolManager { * * @param clientVersion input client version * @param serverVersion desired output server version - * @return path it generated, null if it failed + * @return path it generated, null if not supported */ @Nullable - List> getProtocolPath(int clientVersion, int serverVersion); + List getProtocolPath(int clientVersion, int serverVersion); /** * Returns the maximum protocol path size applied to {@link #getProtocolPath(int, int)}. diff --git a/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathEntry.java b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathEntry.java new file mode 100644 index 000000000..eb077d4b6 --- /dev/null +++ b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathEntry.java @@ -0,0 +1,41 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2021 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package us.myles.ViaVersion.api.protocol; + +public interface ProtocolPathEntry { + + /** + * Returns the resulting protocol after transformation using + * the {@link #getProtocol()} protocol handlers. + * + * @return output protocol version after transformation + */ + int getOutputProtocolVersion(); + + /** + * Returns the protocol to be applied with this entry. + * + * @return protocol to be applied with this entry + */ + Protocol getProtocol(); +} diff --git a/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathKey.java b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathKey.java new file mode 100644 index 000000000..0fbde00fe --- /dev/null +++ b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathKey.java @@ -0,0 +1,36 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2021 ViaVersion and contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package us.myles.ViaVersion.api.protocol; + +public interface ProtocolPathKey { + + /** + * @return client protocol version + */ + int getClientProtocolVersion(); + + /** + * @return server protocol version + */ + int getServerProtocolVersion(); +} diff --git a/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java index 64af827e7..b4dc3e5ad 100644 --- a/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java +++ b/api/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolRegistry.java @@ -28,6 +28,7 @@ import us.myles.ViaVersion.ViaManager; import us.myles.ViaVersion.api.Pair; import us.myles.ViaVersion.api.Via; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.SortedSet; @@ -104,7 +105,16 @@ public class ProtocolRegistry { */ @Nullable public static List> getProtocolPath(int clientVersion, int serverVersion) { - return Via.getManager().getProtocolManager().getProtocolPath(clientVersion, serverVersion); + List pathList = Via.getManager().getProtocolManager().getProtocolPath(clientVersion, serverVersion); + if (pathList == null) { + return null; + } + + List> list = new ArrayList<>(); + for (ProtocolPathEntry entry : pathList) { + list.add(new Pair<>(entry.getOutputProtocolVersion(), entry.getProtocol())); + } + return list; } /** diff --git a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeServerHandler.java b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeServerHandler.java index fae6f112f..212ededf7 100644 --- a/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeServerHandler.java +++ b/bungee/src/main/java/us/myles/ViaVersion/bungee/handlers/BungeeServerHandler.java @@ -26,12 +26,12 @@ import net.md_5.bungee.api.score.Team; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.protocol.packet.PluginMessage; import us.myles.ViaVersion.api.PacketWrapper; -import us.myles.ViaVersion.api.Pair; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.ExternalJoinGameListener; import us.myles.ViaVersion.api.data.StoredObject; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.protocol.Protocol; +import us.myles.ViaVersion.api.protocol.ProtocolPathEntry; import us.myles.ViaVersion.api.protocol.ProtocolPipeline; import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.api.type.Type; @@ -92,7 +92,7 @@ public class BungeeServerHandler implements Listener { } int protocolId = ProtocolDetectorService.getProtocolId(e.getTarget().getName()); - List> protocols = Via.getManager().getProtocolManager().getProtocolPath(user.getProtocolInfo().getProtocolVersion(), protocolId); + List protocols = Via.getManager().getProtocolManager().getProtocolPath(user.getProtocolInfo().getProtocolVersion(), protocolId); // Check if ViaVersion can support that version try { @@ -175,7 +175,7 @@ public class BungeeServerHandler implements Listener { int previousServerProtocol = info.getServerProtocolVersion(); // Refresh the pipes - List> protocols = Via.getManager().getProtocolManager().getProtocolPath(info.getProtocolVersion(), protocolId); + List protocols = Via.getManager().getProtocolManager().getProtocolPath(info.getProtocolVersion(), protocolId); ProtocolPipeline pipeline = user.getProtocolInfo().getPipeline(); user.clearStoredObjects(); pipeline.cleanPipes(); @@ -183,8 +183,8 @@ public class BungeeServerHandler implements Listener { // TODO Check Bungee Supported Protocols? *shrugs* protocolId = info.getProtocolVersion(); } else { - for (Pair prot : protocols) { - pipeline.add(prot.getValue()); + for (ProtocolPathEntry prot : protocols) { + pipeline.add(prot.getProtocol()); } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManagerImpl.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManagerImpl.java index b56520187..32f87a5af 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManagerImpl.java +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolManagerImpl.java @@ -85,7 +85,7 @@ public class ProtocolManagerImpl implements ProtocolManager { // Input Version -> Output Version & Protocol (Allows fast lookup) private final Int2ObjectMap> registryMap = new Int2ObjectOpenHashMap<>(32); private final Map, Protocol> protocols = new HashMap<>(); - private final Map, List>> pathCache = new ConcurrentHashMap<>(); + private final Map> pathCache = new ConcurrentHashMap<>(); private final Set supportedVersions = new HashSet<>(); private final List, Protocol>> baseProtocols = Lists.newCopyOnWriteArrayList(); private final List registerList = new ArrayList<>(); @@ -201,26 +201,27 @@ public class ProtocolManagerImpl implements ProtocolManager { supportedVersions.add(serverProtocol); for (ProtocolVersion versions : ProtocolVersion.getProtocols()) { - List> paths = getProtocolPath(versions.getVersion(), serverProtocol); + List paths = getProtocolPath(versions.getVersion(), serverProtocol); if (paths == null) continue; supportedVersions.add(versions.getVersion()); - for (Pair path : paths) { - supportedVersions.add(path.getKey()); + for (ProtocolPathEntry path : paths) { + supportedVersions.add(path.getOutputProtocolVersion()); } } } @Nullable @Override - public List> getProtocolPath(int clientVersion, int serverVersion) { - Pair protocolKey = new Pair<>(clientVersion, serverVersion); + public List getProtocolPath(int clientVersion, int serverVersion) { + ProtocolPathKey protocolKey = new ProtocolPathKeyImpl(clientVersion, serverVersion); // Check cache - List> protocolList = pathCache.get(protocolKey); + List protocolList = pathCache.get(protocolKey); if (protocolList != null) { return protocolList; } + // Generate path - List> outputPath = getProtocolPath(new ArrayList<>(), clientVersion, serverVersion); + List outputPath = getProtocolPath(new ArrayList<>(), clientVersion, serverVersion); // If it found a path, cache it. if (outputPath != null) { pathCache.put(protocolKey, outputPath); @@ -237,7 +238,7 @@ public class ProtocolManagerImpl implements ProtocolManager { * @return path that has been generated, null if failed */ @Nullable - private List> getProtocolPath(List> current, int clientVersion, int serverVersion) { + private List getProtocolPath(List current, int clientVersion, int serverVersion) { if (clientVersion == serverVersion) return null; // We're already there if (current.size() > maxProtocolPathSize) return null; // Fail safe, protocol too complicated. @@ -250,30 +251,31 @@ public class ProtocolManagerImpl implements ProtocolManager { // Next check there isn't an obvious path Protocol protocol = inputMap.get(serverVersion); if (protocol != null) { - current.add(new Pair<>(serverVersion, protocol)); + current.add(new ProtocolPathEntryImpl(serverVersion, protocol)); return current; // Easy solution } // There might be a more advanced solution... So we'll see if any of the others can get us there - List> shortest = null; + List shortest = null; for (Int2ObjectMap.Entry entry : inputMap.int2ObjectEntrySet()) { // Ensure it wasn't caught by the other loop - if (entry.getIntKey() == (serverVersion)) continue; + if (entry.getIntKey() == serverVersion) continue; - Pair pair = new Pair<>(entry.getIntKey(), entry.getValue()); + ProtocolPathEntry pathEntry = new ProtocolPathEntryImpl(entry.getIntKey(), entry.getValue()); // Ensure no recursion - if (current.contains(pair)) continue; + if (current.contains(pathEntry)) continue; // Create a copy - List> 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) { - // If it's shorter then choose it - if (shortest == null || shortest.size() > newCurrent.size()) { - shortest = newCurrent; - } + List newCurrent = new ArrayList<>(current); + newCurrent.add(pathEntry); + + // Calculate the rest of the protocol using the current path entry + newCurrent = getProtocolPath(newCurrent, entry.getIntKey(), serverVersion); + + // If it's shorter then choose it + if (newCurrent != null + && (shortest == null || shortest.size() > newCurrent.size())) { + shortest = newCurrent; } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathEntryImpl.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathEntryImpl.java new file mode 100644 index 000000000..5807d4b2c --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathEntryImpl.java @@ -0,0 +1,54 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2021 ViaVersion and contributors + * + * 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 3 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, see . + */ +package us.myles.ViaVersion.api.protocol; + +public class ProtocolPathEntryImpl implements ProtocolPathEntry { + private final int outputProtocolVersion; + private final Protocol protocol; + + public ProtocolPathEntryImpl(int outputProtocolVersion, Protocol protocol) { + this.outputProtocolVersion = outputProtocolVersion; + this.protocol = protocol; + } + + @Override + public int getOutputProtocolVersion() { + return outputProtocolVersion; + } + + @Override + public Protocol getProtocol() { + return protocol; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final ProtocolPathEntryImpl that = (ProtocolPathEntryImpl) o; + if (outputProtocolVersion != that.outputProtocolVersion) return false; + return protocol.equals(that.protocol); + } + + @Override + public int hashCode() { + int result = outputProtocolVersion; + result = 31 * result + protocol.hashCode(); + return result; + } +} \ No newline at end of file diff --git a/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathKeyImpl.java b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathKeyImpl.java new file mode 100644 index 000000000..b0400ebe2 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/protocol/ProtocolPathKeyImpl.java @@ -0,0 +1,54 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2021 ViaVersion and contributors + * + * 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 3 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, see . + */ +package us.myles.ViaVersion.api.protocol; + +public class ProtocolPathKeyImpl implements ProtocolPathKey { + private final int clientProtocolVersion; + private final int serverProtocolVersion; + + public ProtocolPathKeyImpl(int clientProtocolVersion, int serverProtocolVersion) { + this.clientProtocolVersion = clientProtocolVersion; + this.serverProtocolVersion = serverProtocolVersion; + } + + @Override + public int getClientProtocolVersion() { + return clientProtocolVersion; + } + + @Override + public int getServerProtocolVersion() { + return serverProtocolVersion; + } + + @Override + public boolean equals(final Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + final ProtocolPathKeyImpl that = (ProtocolPathKeyImpl) o; + if (clientProtocolVersion != that.clientProtocolVersion) return false; + return serverProtocolVersion == that.serverProtocolVersion; + } + + @Override + public int hashCode() { + int result = clientProtocolVersion; + result = 31 * result + serverProtocolVersion; + return result; + } +} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol.java b/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol.java index 76c80c2af..1d0711d01 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol.java @@ -18,11 +18,10 @@ package us.myles.ViaVersion.protocols.base; import us.myles.ViaVersion.api.PacketWrapper; -import us.myles.ViaVersion.api.Pair; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.platform.providers.ViaProviders; -import us.myles.ViaVersion.api.protocol.Protocol; +import us.myles.ViaVersion.api.protocol.ProtocolPathEntry; import us.myles.ViaVersion.api.protocol.ProtocolPipeline; import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.api.protocol.SimpleProtocol; @@ -60,7 +59,7 @@ public class BaseProtocol extends SimpleProtocol { // Choose the pipe int serverProtocol = Via.getManager().getProviders().get(VersionProvider.class).getServerProtocol(wrapper.user()); info.setServerProtocolVersion(serverProtocol); - List> protocols = null; + List protocols = null; // Only allow newer clients or (1.9.2 on 1.9.4 server if the server supports it) if (info.getProtocolVersion() >= serverProtocol || Via.getPlatform().isOldClientsAllowed()) { @@ -69,10 +68,10 @@ public class BaseProtocol extends SimpleProtocol { ProtocolPipeline pipeline = wrapper.user().getProtocolInfo().getPipeline(); if (protocols != null) { - for (Pair prot : protocols) { - pipeline.add(prot.getValue()); + for (ProtocolPathEntry prot : protocols) { + pipeline.add(prot.getProtocol()); // Ensure mapping data has already been loaded - Via.getManager().getProtocolManager().completeMappingDataLoading(prot.getValue().getClass()); + Via.getManager().getProtocolManager().completeMappingDataLoading(prot.getProtocol().getClass()); } // Set the original snapshot version if present diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol1_7.java b/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol1_7.java index 695cbfddd..f6b1070ab 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol1_7.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/base/BaseProtocol1_7.java @@ -23,10 +23,9 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import io.netty.channel.ChannelFuture; import us.myles.ViaVersion.api.PacketWrapper; -import us.myles.ViaVersion.api.Pair; import us.myles.ViaVersion.api.Via; -import us.myles.ViaVersion.api.protocol.Protocol; import us.myles.ViaVersion.api.protocol.ProtocolManagerImpl; +import us.myles.ViaVersion.api.protocol.ProtocolPathEntry; import us.myles.ViaVersion.api.protocol.ProtocolVersion; import us.myles.ViaVersion.api.protocol.SimpleProtocol; import us.myles.ViaVersion.api.remapper.PacketHandler; @@ -94,7 +93,7 @@ public class BaseProtocol1_7 extends SimpleProtocol { } int protocol = versionProvider.getServerProtocol(wrapper.user()); - List> protocols = null; + List protocols = null; // Only allow newer clients or (1.9.2 on 1.9.4 server if the server supports it) if (info.getProtocolVersion() >= protocol || Via.getPlatform().isOldClientsAllowed()) {