Add method to get Protocol by supported versions, some cleanup

This commit is contained in:
KennyTV 2021-05-29 20:53:47 +02:00
parent ff140c421a
commit 3618914ce9
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
7 changed files with 110 additions and 87 deletions

View File

@ -53,6 +53,28 @@ public interface ProtocolManager {
*/
@Nullable <T extends Protocol> T getProtocol(Class<T> protocolClass);
/**
* Returns a protocol transforming packets for server version to the given client version.
*
* @param clientVersion client protocol version
* @param serverVersion server protocol version
* @return protocol if present, else null
* @see #getProtocolPath(int, int) to get a full path of Protocols between a larger gap of versions
*/
default @Nullable Protocol getProtocol(ProtocolVersion clientVersion, ProtocolVersion serverVersion) {
return getProtocol(clientVersion.getVersion(), serverVersion.getVersion());
}
/**
* Returns a protocol transforming packets for server version to the given client version.
*
* @param clientVersion client protocol version
* @param serverVersion server protocol version
* @return protocol if present, else null
* @see #getProtocolPath(int, int) to get a full path of Protocols between a larger gap of versions
*/
@Nullable Protocol getProtocol(int clientVersion, int serverVersion);
/**
* Returns the base protocol handling serverbound handshake packets.
*
@ -84,37 +106,37 @@ public interface ProtocolManager {
/**
* Register a protocol.
*
* @param protocol protocol to register
* @param supported supported client versions
* @param output output server version the protocol converts to
* @param protocol protocol to register
* @param clientVersion supported client protocol versions
* @param serverVersion output server protocol version the protocol converts to
*/
void registerProtocol(Protocol protocol, ProtocolVersion supported, ProtocolVersion output);
void registerProtocol(Protocol protocol, ProtocolVersion clientVersion, ProtocolVersion serverVersion);
/**
* Register a protocol.
*
* @param protocol protocol to register
* @param supported supported client versions
* @param output output server version the protocol converts to
* @param protocol protocol to register
* @param supportedClientVersion supported client protocol versions
* @param serverVersion output server protocol version the protocol converts to
*/
void registerProtocol(Protocol protocol, List<Integer> supported, int output);
void registerProtocol(Protocol protocol, List<Integer> supportedClientVersion, int serverVersion);
/**
* Registers a base protocol. Base Protocols registered later have higher priority.
* Only base protocol will always be added to pipeline.
*
* @param baseProtocol base protocol to register
* @param supportedProtocols versions supported by the base protocol
* @param supportedProtocols protocol versions supported by the base protocol
* @throws IllegalArgumentException if the protocol is not a base protocol as given by {@link Protocol#isBaseProtocol()}
*/
void registerBaseProtocol(Protocol baseProtocol, Range<Integer> supportedProtocols);
/**
* Calculates and returns the protocol path from a client version to server version.
* Calculates and returns the protocol path from a client protocol version to server protocol version.
* Returns null if no path could be found or the path length exceeds the value given by {@link #getMaxProtocolPathSize()}.
*
* @param clientVersion input client version
* @param serverVersion desired output server version
* @param clientVersion input client protocol version
* @param serverVersion desired output server protocol version
* @return path generated, or null if not supported or the length exceeds {@link #getMaxProtocolPathSize()}
*/
@Nullable List<ProtocolPathEntry> getProtocolPath(int clientVersion, int serverVersion);
@ -135,9 +157,9 @@ public interface ProtocolManager {
void setMaxProtocolPathSize(int maxProtocolPathSize);
/**
* Returns the versions compatible with the server.
* Returns the protocol versions compatible with the server.
*
* @return sorted, immutable set of supported versions
* @return sorted, immutable set of supported protocol versions
*/
SortedSet<Integer> getSupportedVersions();

View File

@ -26,11 +26,12 @@ import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.type.Type;
public abstract class BaseChunkType extends Type<Chunk> {
public BaseChunkType() {
protected BaseChunkType() {
super(Chunk.class);
}
public BaseChunkType(String typeName) {
protected BaseChunkType(String typeName) {
super(typeName, Chunk.class);
}

View File

@ -26,11 +26,12 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
public abstract class BaseItemArrayType extends Type<Item[]> {
public BaseItemArrayType() {
protected BaseItemArrayType() {
super(Item[].class);
}
public BaseItemArrayType(String typeName) {
protected BaseItemArrayType(String typeName) {
super(typeName, Item[].class);
}

View File

@ -26,11 +26,12 @@ import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.type.Type;
public abstract class BaseItemType extends Type<Item> {
public BaseItemType() {
protected BaseItemType() {
super(Item.class);
}
public BaseItemType(String typeName) {
protected BaseItemType(String typeName) {
super(typeName, Item.class);
}

View File

@ -160,12 +160,12 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public void registerProtocol(Protocol protocol, ProtocolVersion supported, ProtocolVersion output) {
registerProtocol(protocol, Collections.singletonList(supported.getVersion()), output.getVersion());
public void registerProtocol(Protocol protocol, ProtocolVersion clientVersion, ProtocolVersion serverVersion) {
registerProtocol(protocol, Collections.singletonList(clientVersion.getVersion()), serverVersion.getVersion());
}
@Override
public void registerProtocol(Protocol protocol, List<Integer> supported, int output) {
public void registerProtocol(Protocol protocol, List<Integer> supportedClientVersion, int serverVersion) {
// Clear cache as this may make new routes.
if (!pathCache.isEmpty()) {
pathCache.clear();
@ -173,9 +173,9 @@ public class ProtocolManagerImpl implements ProtocolManager {
protocols.put(protocol.getClass(), protocol);
for (int version : supported) {
for (int version : supportedClientVersion) {
Int2ObjectMap<Protocol> protocolMap = registryMap.computeIfAbsent(version, s -> new Int2ObjectOpenHashMap<>(2));
protocolMap.put(output, protocol);
protocolMap.put(serverVersion, protocol);
}
if (Via.getPlatform().isPluginEnabled()) {
@ -249,6 +249,7 @@ public class ProtocolManagerImpl implements ProtocolManager {
* @return path that has been generated, null if failed
*/
private @Nullable List<ProtocolPathEntry> getProtocolPath(List<ProtocolPathEntry> current, int clientVersion, int serverVersion) {
//TODO optimize?
if (clientVersion == serverVersion) return null; // We're already there
if (current.size() > maxProtocolPathSize) return null; // Fail safe, protocol too complicated.
@ -297,6 +298,12 @@ public class ProtocolManagerImpl implements ProtocolManager {
return (T) protocols.get(protocolClass);
}
@Override
public @Nullable Protocol getProtocol(int clientVersion, int serverVersion) {
Int2ObjectMap<Protocol> map = registryMap.get(clientVersion);
return map != null ? map.get(serverVersion) : null;
}
@Override
public Protocol getBaseProtocol(int serverVersion) {
for (Pair<Range<Integer>, Protocol> rangeProtocol : Lists.reverse(baseProtocols)) {

View File

@ -63,12 +63,11 @@ public class PacketWrapperImpl implements PacketWrapper {
public <T> T get(Type<T> type, int index) throws Exception {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return (T) packetValue.getValue();
}
currentIndex++;
if (packetValue.getKey() != type) continue;
if (currentIndex == index) {
return (T) packetValue.getValue();
}
currentIndex++;
}
Exception e = new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
@ -79,12 +78,11 @@ public class PacketWrapperImpl implements PacketWrapper {
public boolean is(Type type, int index) {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
if (packetValue.getKey() != type) continue;
if (currentIndex == index) {
return true;
}
currentIndex++;
}
return false;
}
@ -93,12 +91,11 @@ public class PacketWrapperImpl implements PacketWrapper {
public boolean isReadable(Type type, int index) {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : readableObjects) {
if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
if (packetValue.getKey().getBaseClass() != type.getBaseClass()) continue;
if (currentIndex == index) {
return true;
}
currentIndex++;
}
return false;
}
@ -108,13 +105,12 @@ public class PacketWrapperImpl implements PacketWrapper {
public <T> void set(Type<T> type, int index, T value) throws Exception {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
packetValue.setValue(value);
return;
}
currentIndex++;
if (packetValue.getKey() != type) continue;
if (currentIndex == index) {
packetValue.setValue(attemptTransform(type, value));
return;
}
currentIndex++;
}
Exception e = new ArrayIndexOutOfBoundsException("Could not find type " + type.getTypeName() + " at " + index);
throw new InformativeException(e).set("Type", type.getTypeName()).set("Index", index).set("Packet ID", getId());
@ -131,37 +127,44 @@ public class PacketWrapperImpl implements PacketWrapper {
} catch (Exception e) {
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
}
Pair<Type, Object> read = readableObjects.poll();
Type rtype = read.getKey();
if (rtype == type
|| (type.getBaseClass() == rtype.getBaseClass()
&& type.getOutputClass() == rtype.getOutputClass())) {
return (T) read.getValue();
} else if (rtype == Type.NOTHING) {
return read(type); // retry
} else {
Pair<Type, Object> read = readableObjects.poll();
Type rtype = read.getKey();
if (rtype.equals(type)
|| (type.getBaseClass().equals(rtype.getBaseClass())
&& type.getOutputClass().equals(rtype.getOutputClass()))) {
return (T) read.getValue();
} else {
if (rtype == Type.NOTHING) {
return read(type); // retry
} else {
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
}
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
}
@Override
public <T> void write(Type<T> type, T value) {
if (value != null) {
if (!type.getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (type instanceof TypeConverter) {
value = (T) ((TypeConverter) type).from(value);
} else {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
}
packetValues.add(new Pair<>(type, attemptTransform(type, value)));
}
/**
* Returns the value if already matching, else the converted value or possibly unmatched value.
*
* @param expectedType expected type
* @param value value
* @return value if already matching, else the converted value or possibly unmatched value
*/
private @Nullable Object attemptTransform(Type<?> expectedType, @Nullable Object value) {
if (value != null && !expectedType.getOutputClass().isAssignableFrom(value.getClass())) {
// Attempt conversion
if (expectedType instanceof TypeConverter) {
return ((TypeConverter) expectedType).from(value);
}
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + expectedType.getOutputClass());
}
packetValues.add(new Pair<>(type, value));
return value;
}
@Override
@ -195,18 +198,7 @@ public class PacketWrapperImpl implements PacketWrapper {
int index = 0;
for (Pair<Type, Object> packetValue : packetValues) {
try {
Object value = packetValue.getValue();
if (value != null) {
if (!packetValue.getKey().getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (packetValue.getKey() instanceof TypeConverter) {
value = ((TypeConverter) packetValue.getKey()).from(value);
} else {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
}
}
}
packetValue.getKey().write(buffer, value);
packetValue.getKey().write(buffer, packetValue.getValue());
} catch (Exception e) {
throw new InformativeException(e).set("Index", index).set("Type", packetValue.getKey().getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
@ -428,8 +420,7 @@ public class PacketWrapperImpl implements PacketWrapper {
this.id = id;
}
@Nullable
public ByteBuf getInputBuffer() {
public @Nullable ByteBuf getInputBuffer() {
return inputBuffer;
}

View File

@ -55,13 +55,14 @@ public class BaseProtocol extends AbstractSimpleProtocol {
ProtocolInfo info = wrapper.user().getProtocolInfo();
info.setProtocolVersion(protocolVersion);
// Ensure the server has a version provider
if (Via.getManager().getProviders().get(VersionProvider.class) == null) {
VersionProvider versionProvider = Via.getManager().getProviders().get(VersionProvider.class);
if (versionProvider == null) {
wrapper.user().setActive(false);
return;
}
// Choose the pipe
int serverProtocol = Via.getManager().getProviders().get(VersionProvider.class).getClosestServerProtocol(wrapper.user());
int serverProtocol = versionProvider.getClosestServerProtocol(wrapper.user());
info.setServerProtocolVersion(serverProtocol);
List<ProtocolPathEntry> protocolPath = null;
@ -94,8 +95,7 @@ public class BaseProtocol extends AbstractSimpleProtocol {
// Change state
if (state == 1) {
info.setState(State.STATUS);
}
if (state == 2) {
} else if (state == 2) {
info.setState(State.LOGIN);
}
});