Reduce boxing in protocol path getting

More of its implementation should probably be cleaned up later
This commit is contained in:
KennyTV 2021-03-25 22:34:30 +01:00
parent 63356207a3
commit d918fd27b6
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
10 changed files with 235 additions and 41 deletions

View File

@ -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<Pair<Integer, Protocol>> getProtocolPath(int clientVersion, int serverVersion);
List<ProtocolPathEntry> getProtocolPath(int clientVersion, int serverVersion);
/**
* Returns the maximum protocol path size applied to {@link #getProtocolPath(int, int)}.

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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<Pair<Integer, Protocol>> getProtocolPath(int clientVersion, int serverVersion) {
return Via.getManager().getProtocolManager().getProtocolPath(clientVersion, serverVersion);
List<ProtocolPathEntry> pathList = Via.getManager().getProtocolManager().getProtocolPath(clientVersion, serverVersion);
if (pathList == null) {
return null;
}
List<Pair<Integer, Protocol>> list = new ArrayList<>();
for (ProtocolPathEntry entry : pathList) {
list.add(new Pair<>(entry.getOutputProtocolVersion(), entry.getProtocol()));
}
return list;
}
/**

View File

@ -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<Pair<Integer, Protocol>> protocols = Via.getManager().getProtocolManager().getProtocolPath(user.getProtocolInfo().getProtocolVersion(), protocolId);
List<ProtocolPathEntry> 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<Pair<Integer, Protocol>> protocols = Via.getManager().getProtocolManager().getProtocolPath(info.getProtocolVersion(), protocolId);
List<ProtocolPathEntry> 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<Integer, Protocol> prot : protocols) {
pipeline.add(prot.getValue());
for (ProtocolPathEntry prot : protocols) {
pipeline.add(prot.getProtocol());
}
}

View File

@ -85,7 +85,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
// Input Version -> Output Version & Protocol (Allows fast lookup)
private final Int2ObjectMap<Int2ObjectMap<Protocol>> registryMap = new Int2ObjectOpenHashMap<>(32);
private final Map<Class<? extends Protocol>, Protocol> protocols = new HashMap<>();
private final Map<Pair<Integer, Integer>, List<Pair<Integer, Protocol>>> pathCache = new ConcurrentHashMap<>();
private final Map<ProtocolPathKey, List<ProtocolPathEntry>> pathCache = new ConcurrentHashMap<>();
private final Set<Integer> supportedVersions = new HashSet<>();
private final List<Pair<Range<Integer>, Protocol>> baseProtocols = Lists.newCopyOnWriteArrayList();
private final List<Protocol> registerList = new ArrayList<>();
@ -201,26 +201,27 @@ public class ProtocolManagerImpl implements ProtocolManager {
supportedVersions.add(serverProtocol);
for (ProtocolVersion versions : ProtocolVersion.getProtocols()) {
List<Pair<Integer, Protocol>> paths = getProtocolPath(versions.getVersion(), serverProtocol);
List<ProtocolPathEntry> paths = getProtocolPath(versions.getVersion(), serverProtocol);
if (paths == null) continue;
supportedVersions.add(versions.getVersion());
for (Pair<Integer, Protocol> path : paths) {
supportedVersions.add(path.getKey());
for (ProtocolPathEntry path : paths) {
supportedVersions.add(path.getOutputProtocolVersion());
}
}
}
@Nullable
@Override
public List<Pair<Integer, Protocol>> getProtocolPath(int clientVersion, int serverVersion) {
Pair<Integer, Integer> protocolKey = new Pair<>(clientVersion, serverVersion);
public List<ProtocolPathEntry> getProtocolPath(int clientVersion, int serverVersion) {
ProtocolPathKey protocolKey = new ProtocolPathKeyImpl(clientVersion, serverVersion);
// Check cache
List<Pair<Integer, Protocol>> protocolList = pathCache.get(protocolKey);
List<ProtocolPathEntry> protocolList = pathCache.get(protocolKey);
if (protocolList != null) {
return protocolList;
}
// Generate path
List<Pair<Integer, Protocol>> outputPath = getProtocolPath(new ArrayList<>(), clientVersion, serverVersion);
List<ProtocolPathEntry> 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<Pair<Integer, Protocol>> getProtocolPath(List<Pair<Integer, Protocol>> current, int clientVersion, int serverVersion) {
private List<ProtocolPathEntry> getProtocolPath(List<ProtocolPathEntry> 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,32 +251,33 @@ 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<Pair<Integer, Protocol>> shortest = null;
List<ProtocolPathEntry> shortest = null;
for (Int2ObjectMap.Entry<Protocol> entry : inputMap.int2ObjectEntrySet()) {
// Ensure it wasn't caught by the other loop
if (entry.getIntKey() == (serverVersion)) continue;
if (entry.getIntKey() == serverVersion) continue;
Pair<Integer, Protocol> 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<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) {
List<ProtocolPathEntry> 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 (shortest == null || shortest.size() > newCurrent.size()) {
if (newCurrent != null
&& (shortest == null || shortest.size() > newCurrent.size())) {
shortest = newCurrent;
}
}
}
return shortest; // null if none found
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -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<Pair<Integer, Protocol>> protocols = null;
List<ProtocolPathEntry> 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<Integer, Protocol> 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

View File

@ -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<Pair<Integer, Protocol>> protocols = null;
List<ProtocolPathEntry> 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()) {