Allow bypassing of packet type restriction in Protocol, amend packet creator

This commit is contained in:
kennytv 2021-07-31 23:17:52 +02:00
parent b81109f512
commit 2094397bca
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
6 changed files with 155 additions and 50 deletions

View File

@ -87,14 +87,14 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
}
protected void registerClientboundChannelIdChanges() {
ClientboundPacketType[] newConstants = newClientboundPacketEnum.getEnumConstants();
Map<String, ClientboundPacketType> newClientboundPackets = new HashMap<>(newConstants.length);
for (ClientboundPacketType newConstant : newConstants) {
C2[] newConstants = newClientboundPacketEnum.getEnumConstants();
Map<String, C2> newClientboundPackets = new HashMap<>(newConstants.length);
for (C2 newConstant : newConstants) {
newClientboundPackets.put(newConstant.getName(), newConstant);
}
for (C1 packet : oldClientboundPacketEnum.getEnumConstants()) {
C2 mappedPacket = (C2) newClientboundPackets.get(packet.getName());
C2 mappedPacket = newClientboundPackets.get(packet.getName());
if (mappedPacket == null) {
// Packet doesn't exist on new client
Preconditions.checkArgument(hasRegisteredClientbound(packet),
@ -109,14 +109,14 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
}
protected void registerServerboundChannelIdChanges() {
ServerboundPacketType[] oldConstants = oldServerboundPacketEnum.getEnumConstants();
Map<String, ServerboundPacketType> oldServerboundConstants = new HashMap<>(oldConstants.length);
for (ServerboundPacketType oldConstant : oldConstants) {
S1[] oldConstants = oldServerboundPacketEnum.getEnumConstants();
Map<String, S1> oldServerboundConstants = new HashMap<>(oldConstants.length);
for (S1 oldConstant : oldConstants) {
oldServerboundConstants.put(oldConstant.getName(), oldConstant);
}
for (S2 packet : newServerboundPacketEnum.getEnumConstants()) {
S1 mappedPacket = (S1) oldServerboundConstants.get(packet.getName());
S1 mappedPacket = oldServerboundConstants.get(packet.getName());
if (mappedPacket == null) {
// Packet doesn't exist on old server
Preconditions.checkArgument(hasRegisteredServerbound(packet),
@ -200,13 +200,13 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
@Override
public void registerClientbound(C1 packetType, @Nullable PacketRemapper packetRemapper) {
checkPacketType(packetType, packetType.getClass() == oldClientboundPacketEnum);
checkPacketType(packetType, oldClientboundPacketEnum == null || packetType.getClass() == oldClientboundPacketEnum);
ClientboundPacketType mappedPacket = oldClientboundPacketEnum == newClientboundPacketEnum ? packetType
C2 mappedPacket = oldClientboundPacketEnum == newClientboundPacketEnum ? (C2) packetType
: Arrays.stream(newClientboundPacketEnum.getEnumConstants()).filter(en -> en.getName().equals(packetType.getName())).findAny().orElse(null);
Preconditions.checkNotNull(mappedPacket, "Packet type " + packetType + " in " + packetType.getClass().getSimpleName() + " could not be automatically mapped!");
registerClientbound(packetType, (C2) mappedPacket, packetRemapper);
registerClientbound(packetType, mappedPacket, packetRemapper);
}
@Override
@ -226,13 +226,13 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
@Override
public void registerServerbound(S2 packetType, @Nullable PacketRemapper packetRemapper) {
checkPacketType(packetType, packetType.getClass() == newServerboundPacketEnum);
checkPacketType(packetType, newServerboundPacketEnum == null || packetType.getClass() == newServerboundPacketEnum);
ServerboundPacketType mappedPacket = oldServerboundPacketEnum == newServerboundPacketEnum ? packetType
S1 mappedPacket = oldServerboundPacketEnum == newServerboundPacketEnum ? (S1) packetType
: Arrays.stream(oldServerboundPacketEnum.getEnumConstants()).filter(en -> en.getName().equals(packetType.getName())).findAny().orElse(null);
Preconditions.checkNotNull(mappedPacket, "Packet type " + packetType + " in " + packetType.getClass().getSimpleName() + " could not be automatically mapped!");
registerServerbound(packetType, (S1) mappedPacket, packetRemapper);
registerServerbound(packetType, mappedPacket, packetRemapper);
}
@Override
@ -253,8 +253,8 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
private void register(Map<Packet, ProtocolPacket> packetMap, PacketType packetType, @Nullable PacketType mappedPacketType,
Class<? extends PacketType> unmappedPacketEnum, Class<? extends PacketType> mappedPacketEnum,
@Nullable PacketRemapper remapper, boolean override) {
checkPacketType(packetType, packetType.getClass() == unmappedPacketEnum);
checkPacketType(mappedPacketType, mappedPacketType == null || mappedPacketType.getClass() == mappedPacketEnum);
checkPacketType(packetType, unmappedPacketEnum == null || packetType.getClass() == unmappedPacketEnum);
checkPacketType(mappedPacketType, mappedPacketType == null || mappedPacketEnum == null || mappedPacketType.getClass() == mappedPacketEnum);
Preconditions.checkArgument(mappedPacketType == null || packetType.state() == mappedPacketType.state(), "Packet type state does not match mapped packet type state");
ProtocolPacket protocolPacket = new ProtocolPacket(packetType.state(), packetType, mappedPacketType, remapper);
@ -277,8 +277,8 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
}
@Override
public boolean hasRegisteredClientbound(State state, int unmappedPacketid) {
Packet packet = new Packet(state, unmappedPacketid);
public boolean hasRegisteredClientbound(State state, int unmappedPacketId) {
Packet packet = new Packet(state, unmappedPacketId);
return clientbound.containsKey(packet);
}
@ -291,7 +291,7 @@ public abstract class AbstractProtocol<C1 extends ClientboundPacketType, C2 exte
@Override
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
Packet statePacket = new Packet(state, packetWrapper.getId());
Map<Packet, ProtocolPacket> packetMap = (direction == Direction.CLIENTBOUND ? this.clientbound : serverbound);
Map<Packet, ProtocolPacket> packetMap = direction == Direction.CLIENTBOUND ? clientbound : serverbound;
ProtocolPacket protocolPacket = packetMap.get(statePacket);
if (protocolPacket == null) {
return;

View File

@ -28,7 +28,7 @@ import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.VersionedPacketCreator;
import com.viaversion.viaversion.api.protocol.packet.VersionedPacketTransformer;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import io.netty.buffer.ByteBuf;
@ -147,18 +147,34 @@ public interface ProtocolManager {
@Nullable List<ProtocolPathEntry> getProtocolPath(int clientVersion, int serverVersion);
/**
* Returns a versioned packet creator to send packets from a given base version to any client version supported by Via.
* Returns a versioned packet transformer to transform and send packets from a given base version to any client version supported by Via.
* The used packet types have to match the given protocol version.
* <p>
* It is important the correct packet type classes are passed. The ViaVersion given packet type enums
* are found in the common module. Examples for correct invocations are:
* <pre>
* createPacketTransformer(ProtocolVersion.v1_17_1, ClientboundPackets1_17_1.class, ServerboundPackets1_17.class);
* createPacketTransformer(ProtocolVersion.v1_12_2, ClientboundPackets1_12_1.class, ServerboundPackets1_12_1.class);
* createPacketTransformer(ProtocolVersion.v1_8, ClientboundPackets1_8.class, ServerboundPackets1_8.class);
* </pre>
* If only clientbound <b>or</b> serverbound packets are used, the other class can be passed as null, see:
* <pre>
* VersionedPacketTransformer&lt;?, ServerboundHandshakePackets&gt; creator
* = createPacketTransformer(ProtocolVersion.v1_17_1, null, ServerboundHandshakePackets.class);
* </pre>
*
* @param inputVersion input protocol version
* @param clientboundPacketsClass clientbound packets class
* @param serverboundPacketsClass serverbound packets class
* @return versioned packet creator
* @param clientboundPacketsClass clientbound packets class, or null if no clientbound packets will be sent or transformed with this
* @param serverboundPacketsClass serverbound packets class, or null if no serverbound packets will be sent or transformed with this
* @return versioned packet transformer to transform and send packets from a given protocol version
* @throws IllegalArgumentException if either of the packet classes are the base {@link ClientboundPacketType} or {@link ServerboundPacketType} interfaces
* @throws IllegalArgumentException if both packet classes are null
*/
VersionedPacketCreator createVersionedPacketCreator(ProtocolVersion inputVersion,
Class<? extends ClientboundPacketType> clientboundPacketsClass,
Class<? extends ServerboundPacketType> serverboundPacketsClass);
<C extends ClientboundPacketType,
S extends ServerboundPacketType
> VersionedPacketTransformer<C, S> createPacketTransformer(ProtocolVersion inputVersion,
@Nullable Class<C> clientboundPacketsClass,
@Nullable Class<S> serverboundPacketsClass);
/**
* Returns whether protocol path calculation expects the path to come closer to the expected version with each entry, true by default.

View File

@ -219,8 +219,10 @@ public interface PacketWrapper {
*/
ChannelFuture sendFuture(Class<? extends Protocol> packetProtocol) throws Exception;
@Deprecated
/**
* @deprecated misleading; use {@link #sendRaw()}. This method will be removed in 5.0.0
*/
@Deprecated/*(forRemoval = true)*/
default void send() throws Exception {
sendRaw();
}
@ -328,8 +330,9 @@ public interface PacketWrapper {
* (Ensure the ID is suitable for viaversion)
*
* @throws Exception If it failed to write
* @deprecated misleading; use {@link #sendToServerRaw()}. This method will be removed in 5.0.0
*/
@Deprecated
@Deprecated/*(forRemoval = true)*/
default void sendToServer() throws Exception {
sendToServerRaw();
}

View File

@ -23,12 +23,18 @@
package com.viaversion.viaversion.api.protocol.packet;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.function.Consumer;
/**
* Utility to send packets from a given base version to or from any client version supported by Via.
*
* @param <C> clientbound packet type
* @param <S> serverbound packet type
*/
public interface VersionedPacketCreator {
public interface VersionedPacketTransformer<C extends ClientboundPacketType, S extends ServerboundPacketType> {
/**
* Sends a packet to the user or server, depending on the packet type given by {@link PacketWrapper#getPacketType()}.
@ -38,33 +44,63 @@ public interface VersionedPacketCreator {
* @throws IllegalArgumentException if the packet type is not of the expected clientbound or serverbound packets class
* @throws IllegalArgumentException if {@link PacketWrapper#user()} returns null
* @throws RuntimeException if no path from the input version to the required client version exists
* @throws Exception if an error occurred while constructing the packet or sending it
* @throws Exception if an error occurred while transforming or sending the packet
*/
boolean send(PacketWrapper packet) throws Exception;
/**
* @see #send(PacketWrapper)
*/
boolean send(UserConnection connection, C packetType, Consumer<PacketWrapper> packetWriter) throws Exception;
/**
* @see #send(PacketWrapper)
*/
boolean send(UserConnection connection, S packetType, Consumer<PacketWrapper> packetWriter) throws Exception;
/**
* Sends a packet to the user or server, depending on the packet type given by {@link PacketWrapper#getPacketType()}, submitted to the netty event loop.
* Returns false if the packet has been cancelled at some point, but does not indicate whether a replacement has been constructed.
*
* @param packet packet wrapper
* @return whether this packet specifically has been sent, false if cancelled
* @throws IllegalArgumentException if the packet type is not of the expected clientbound packets class
* @throws IllegalArgumentException if the packet type is not of the expected clientbound or serverbound packets class
* @throws IllegalArgumentException if {@link PacketWrapper#user()} returns null
* @throws RuntimeException if no path from the input version to the required client version exists
* @throws Exception if an error occurred while constructing the packet or sending it
* @throws Exception if an error occurred while transforming or sending the packet
*/
boolean scheduleSend(PacketWrapper packet) throws Exception;
/**
* @see #scheduleSend(PacketWrapper)
*/
boolean scheduleSend(UserConnection connection, C packetType, Consumer<PacketWrapper> packetWriter) throws Exception;
/**
* @see #scheduleSend(PacketWrapper)
*/
boolean scheduleSend(UserConnection connection, S packetType, Consumer<PacketWrapper> packetWriter) throws Exception;
/**
* Transforms a packet to the protocol version of the given connection or server, or null if cancelled at some point.
* The target version is given by {@link ProtocolInfo#getProtocolVersion()} or {@link ProtocolInfo#getServerProtocolVersion()}.
*
* @param packet packet wrapper
* @return created and transformed packet wrapper, or null if cancelled at some point
* @throws IllegalArgumentException if the packet type is not of the expected clientbound packets class
* @throws IllegalArgumentException if the packet type is not of the expected clientbound or serverbound packets class
* @throws IllegalArgumentException if {@link PacketWrapper#user()} returns null
* @throws RuntimeException if no path from the input version to the required client version exists
* @throws Exception if an error occurred while constructing the packet
* @throws Exception if an error occurred while transforming the packet
*/
@Nullable PacketWrapper transform(PacketWrapper packet) throws Exception;
/**
* @see #transform(PacketWrapper)
*/
@Nullable PacketWrapper transform(UserConnection connection, C packetType, Consumer<PacketWrapper> packetWriter) throws Exception;
/**
* @see #transform(PacketWrapper)
*/
@Nullable PacketWrapper transform(UserConnection connection, S packetType, Consumer<PacketWrapper> packetWriter) throws Exception;
}

View File

@ -32,11 +32,11 @@ import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.VersionedPacketCreator;
import com.viaversion.viaversion.api.protocol.packet.VersionedPacketTransformer;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
import com.viaversion.viaversion.protocol.packet.VersionedPacketCreatorImpl;
import com.viaversion.viaversion.protocol.packet.VersionedPacketTransformerImpl;
import com.viaversion.viaversion.protocols.base.BaseProtocol;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_16;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_7;
@ -267,11 +267,13 @@ public class ProtocolManagerImpl implements ProtocolManager {
}
@Override
public VersionedPacketCreator createVersionedPacketCreator(ProtocolVersion inputVersion,
Class<? extends ClientboundPacketType> clientboundPacketsClass,
Class<? extends ServerboundPacketType> serverboundPacketsClass) {
public <C extends ClientboundPacketType,
S extends ServerboundPacketType
> VersionedPacketTransformer<C, S> createPacketTransformer(ProtocolVersion inputVersion,
@Nullable Class<C> clientboundPacketsClass,
@Nullable Class<S> serverboundPacketsClass) {
Preconditions.checkArgument(clientboundPacketsClass != ClientboundPacketType.class && serverboundPacketsClass != ServerboundPacketType.class);
return new VersionedPacketCreatorImpl(inputVersion, clientboundPacketsClass, serverboundPacketsClass);
return new VersionedPacketTransformerImpl<>(inputVersion, clientboundPacketsClass, serverboundPacketsClass);
}
/**

View File

@ -28,24 +28,24 @@ import com.viaversion.viaversion.api.protocol.packet.PacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.State;
import com.viaversion.viaversion.api.protocol.packet.VersionedPacketCreator;
import com.viaversion.viaversion.api.protocol.packet.VersionedPacketTransformer;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
public class VersionedPacketCreatorImpl implements VersionedPacketCreator {
public class VersionedPacketTransformerImpl<C extends ClientboundPacketType, S extends ServerboundPacketType> implements VersionedPacketTransformer<C, S> {
private final int inputProtocolVersion;
private final Class<? extends ClientboundPacketType> clientboundPacketsClass;
private final Class<? extends ServerboundPacketType> serverboundPacketsClass;
private final Class<C> clientboundPacketsClass;
private final Class<S> serverboundPacketsClass;
public VersionedPacketCreatorImpl(ProtocolVersion inputVersion,
Class<? extends ClientboundPacketType> clientboundPacketsClass, Class<? extends ServerboundPacketType> serverboundPacketsClass) {
public VersionedPacketTransformerImpl(ProtocolVersion inputVersion, @Nullable Class<C> clientboundPacketsClass, @Nullable Class<S> serverboundPacketsClass) {
Preconditions.checkNotNull(inputVersion);
Preconditions.checkNotNull(clientboundPacketsClass);
Preconditions.checkNotNull(serverboundPacketsClass);
Preconditions.checkArgument(clientboundPacketsClass != null || serverboundPacketsClass != null,
"Either the clientbound or serverbound packets class has to be non-null");
this.inputProtocolVersion = inputVersion.getVersion();
this.clientboundPacketsClass = clientboundPacketsClass;
this.serverboundPacketsClass = serverboundPacketsClass;
@ -57,12 +57,32 @@ public class VersionedPacketCreatorImpl implements VersionedPacketCreator {
return transformAndSendPacket(packet, true);
}
@Override
public boolean send(UserConnection connection, C packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
return createAndSend(connection, packetType, packetWriter);
}
@Override
public boolean send(UserConnection connection, S packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
return createAndSend(connection, packetType, packetWriter);
}
@Override
public boolean scheduleSend(PacketWrapper packet) throws Exception {
validatePacket(packet);
return transformAndSendPacket(packet, false);
}
@Override
public boolean scheduleSend(UserConnection connection, C packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
return scheduleCreateAndSend(connection, packetType, packetWriter);
}
@Override
public boolean scheduleSend(UserConnection connection, S packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
return scheduleCreateAndSend(connection, packetType, packetWriter);
}
@Override
public @Nullable PacketWrapper transform(PacketWrapper packet) throws Exception {
validatePacket(packet);
@ -70,6 +90,16 @@ public class VersionedPacketCreatorImpl implements VersionedPacketCreator {
return packet.isCancelled() ? null : packet;
}
@Override
public @Nullable PacketWrapper transform(UserConnection connection, C packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
return createAndTransform(connection, packetType, packetWriter);
}
@Override
public @Nullable PacketWrapper transform(UserConnection connection, S packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
return createAndTransform(connection, packetType, packetWriter);
}
private void validatePacket(PacketWrapper packet) {
if (packet.user() == null) {
throw new IllegalArgumentException("PacketWrapper does not have a targetted UserConnection");
@ -140,4 +170,22 @@ public class VersionedPacketCreatorImpl implements VersionedPacketCreator {
}
}
}
private boolean createAndSend(UserConnection connection, PacketType packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
PacketWrapper packet = PacketWrapper.create(packetType, connection);
packetWriter.accept(packet);
return send(packet);
}
private boolean scheduleCreateAndSend(UserConnection connection, PacketType packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
PacketWrapper packet = PacketWrapper.create(packetType, connection);
packetWriter.accept(packet);
return scheduleSend(packet);
}
private @Nullable PacketWrapper createAndTransform(UserConnection connection, PacketType packetType, Consumer<PacketWrapper> packetWriter) throws Exception {
PacketWrapper packet = PacketWrapper.create(packetType, connection);
packetWriter.accept(packet);
return transform(packet);
}
}