From 30d122e7fa25608d3e881d89a528721dac26218d Mon Sep 17 00:00:00 2001 From: KennyTV Date: Mon, 26 Apr 2021 22:54:43 +0200 Subject: [PATCH] Create some fancy interfaces --- .../com/viaversion/viaversion/api/ViaAPI.java | 4 +- .../viaversion/viaversion/api/ViaManager.java | 4 +- .../api/connection/ConnectionManager.java | 92 ++++ .../api/connection/ProtocolInfo.java | 82 +--- .../api/connection/StoredObject.java | 4 +- .../api/connection/UserConnection.java | 324 ++----------- .../api/protocol/AbstractSimpleProtocol.java | 29 ++ .../viaversion/api/protocol/Protocol.java | 196 ++------ .../api/protocol/ProtocolManager.java | 19 +- .../api/protocol/ProtocolPathEntry.java | 2 + .../api/protocol/ProtocolPipeline.java | 165 +------ .../api/protocol/base/Protocol.java | 247 ++++++++++ .../protocol/{ => base}/SimpleProtocol.java | 11 +- .../api/protocol/packet/PacketWrapper.java | 419 +++-------------- .../api/protocol/remapper/PacketRemapper.java | 2 +- .../protocol1_9to1_8/ArmorListener.java | 2 +- .../protocol1_9to1_8/DeathListener.java | 2 +- .../handlers/BukkitChannelInitializer.java | 7 +- .../EntityToggleGlideListener.java | 2 +- .../handlers/BungeeChannelInitializer.java | 7 +- .../bungee/handlers/BungeeServerHandler.java | 38 +- .../bungee/listeners/ElytraPatch.java | 2 +- .../providers/BungeeMovementTransmitter.java | 2 +- .../viaversion/viaversion/ViaManagerImpl.java | 17 +- .../viaversion/boss/CommonBoss.java | 2 +- .../connection/ConnectionManagerImpl.java | 70 +-- .../connection/ProtocolInfoImpl.java | 120 +++++ .../connection/UserConnectionImpl.java | 385 +++++++++++++++ .../protocol/ProtocolManagerImpl.java | 27 +- .../protocol/ProtocolPathEntryImpl.java | 2 +- .../protocol/ProtocolPipelineImpl.java | 193 ++++++++ .../protocol/packet/PacketWrapperImpl.java | 443 ++++++++++++++++++ .../protocols/base/BaseProtocol.java | 18 +- .../protocols/base/BaseProtocol1_7.java | 6 +- .../metadata/MetadataRewriter1_11To1_10.java | 2 +- .../blockconnections/ConnectionData.java | 4 +- .../providers/BlockEntityProvider.java | 2 +- .../storage/TabCompleteTracker.java | 2 +- .../MetadataRewriter1_14To1_13_2.java | 2 +- .../storage/EntityTracker1_14.java | 2 +- .../chunks/BlockEntity.java | 2 +- .../protocol1_9to1_8/Protocol1_9To1_8.java | 2 +- .../packets/SpawnPackets.java | 2 +- .../packets/WorldPackets.java | 4 +- .../BulkChunkTranslatorProvider.java | 2 +- .../providers/CommandBlockProvider.java | 2 +- .../storage/EntityTracker1_9.java | 8 +- .../sponge4/Sponge4ArmorListener.java | 2 +- .../handlers/SpongeChannelInitializer.java | 7 +- .../protocol1_9to1_8/DeathListener.java | 2 +- .../sponge5/Sponge5ArmorListener.java | 2 +- .../handlers/VelocityChannelInitializer.java | 7 +- .../VelocityMovementTransmitter.java | 2 +- 53 files changed, 1839 insertions(+), 1164 deletions(-) create mode 100644 api/src/main/java/com/viaversion/viaversion/api/connection/ConnectionManager.java create mode 100644 api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractSimpleProtocol.java create mode 100644 api/src/main/java/com/viaversion/viaversion/api/protocol/base/Protocol.java rename api/src/main/java/com/viaversion/viaversion/api/protocol/{ => base}/SimpleProtocol.java (79%) rename api/src/main/java/com/viaversion/viaversion/api/connection/ViaConnectionManager.java => common/src/main/java/com/viaversion/viaversion/connection/ConnectionManagerImpl.java (59%) create mode 100644 common/src/main/java/com/viaversion/viaversion/connection/ProtocolInfoImpl.java create mode 100644 common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java create mode 100644 common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java create mode 100644 common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java diff --git a/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java b/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java index 3d3ec4c16..53491fe83 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java +++ b/api/src/main/java/com/viaversion/viaversion/api/ViaAPI.java @@ -22,7 +22,7 @@ */ package com.viaversion.viaversion.api; -import com.viaversion.viaversion.api.connection.ViaConnectionManager; +import com.viaversion.viaversion.api.connection.ConnectionManager; import io.netty.buffer.ByteBuf; import com.viaversion.viaversion.api.boss.BossBar; import com.viaversion.viaversion.api.boss.BossColor; @@ -40,7 +40,7 @@ import java.util.UUID; * @param The player type for the specific platform, for bukkit it's {@code ViaAPI} * @see ViaManager * @see ProtocolManager - * @see ViaConnectionManager + * @see ConnectionManager * @see ViaPlatform */ public interface ViaAPI { diff --git a/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java b/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java index b4bcfeb20..5c75cc596 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java +++ b/api/src/main/java/com/viaversion/viaversion/api/ViaManager.java @@ -28,7 +28,7 @@ import com.viaversion.viaversion.api.platform.ViaPlatform; import com.viaversion.viaversion.api.platform.ViaPlatformLoader; import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.protocol.ProtocolManager; -import com.viaversion.viaversion.api.connection.ViaConnectionManager; +import com.viaversion.viaversion.api.connection.ConnectionManager; import java.util.Set; @@ -53,7 +53,7 @@ public interface ViaManager { * * @return userconnection manager */ - ViaConnectionManager getConnectionManager(); + ConnectionManager getConnectionManager(); /** * Returns the manager for Via providers. diff --git a/api/src/main/java/com/viaversion/viaversion/api/connection/ConnectionManager.java b/api/src/main/java/com/viaversion/viaversion/api/connection/ConnectionManager.java new file mode 100644 index 000000000..7a1418baa --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/connection/ConnectionManager.java @@ -0,0 +1,92 @@ +/* + * 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 com.viaversion.viaversion.api.connection; + +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +/** + * Handles injected UserConnections + */ +public interface ConnectionManager { + + /** + * Returns if Via injected into this player connection. + * + * @param playerId player uuid + * @return true if the player is handled by Via + */ + boolean isClientConnected(UUID playerId); + + /** + * Frontend connections will have the UUID stored. Override this if your platform isn't always frontend. + * UUIDs can't be duplicate between frontend connections. + */ + boolean isFrontEnd(UserConnection connection); + + /** + * Returns the frontend UserConnection from the player connected to this proxy server + * Returns null when there isn't a server or connection was not found + * When ViaVersion is reloaded, this method may not return some players. + * May not return ProtocolSupport players. + *

+ * Note that connections are removed as soon as their channel is closed, + * so avoid using this method during player quits for example. + */ + @Nullable UserConnection getConnectedClient(UUID clientIdentifier); + + /** + * Returns the UUID from the frontend connection to this proxy server + * Returns null when there isn't a server or this connection isn't frontend or it doesn't have an id + * When ViaVersion is reloaded, this method may not return some players. + * May not return ProtocolSupport players. + *

+ * Note that connections are removed as soon as their channel is closed, + * so avoid using this method during player quits for example. + */ + @Nullable UUID getConnectedClientId(UserConnection connection); + + /** + * Returns all UserConnections which are registered + * May contain duplicated UUIDs on multiple ProtocolInfo. + * May contain frontend, backend and/or client-sided connections. + * When ViaVersion is reloaded, this method may not return some players. + * May not contain ProtocolSupport players. + */ + Set getConnections(); + + /** + * Returns a map containing the UUIDs and frontend UserConnections from players connected to this proxy server + * Returns empty list when there isn't a server + * When ViaVersion is reloaded, this method may not return some players. + * May not contain ProtocolSupport players. + */ + Map getConnectedClients(); + + void onLoginSuccess(UserConnection connection); + + void onDisconnect(UserConnection connection); +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/connection/ProtocolInfo.java b/api/src/main/java/com/viaversion/viaversion/api/connection/ProtocolInfo.java index eeff33b04..837e70088 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/connection/ProtocolInfo.java +++ b/api/src/main/java/com/viaversion/viaversion/api/connection/ProtocolInfo.java @@ -23,36 +23,21 @@ package com.viaversion.viaversion.api.connection; import com.viaversion.viaversion.api.protocol.ProtocolPipeline; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import com.viaversion.viaversion.api.protocol.packet.State; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import java.util.UUID; -public class ProtocolInfo extends StoredObject { - private State state = State.HANDSHAKE; - private int protocolVersion = -1; - private int serverProtocolVersion = -1; - private String username; - private UUID uuid; - private ProtocolPipeline pipeline; - - public ProtocolInfo(UserConnection user) { - super(user); - } +public interface ProtocolInfo { /** * Returns the protocol state the user is currently in. * * @return protocol state */ - public State getState() { - return state; - } + State getState(); - public void setState(State state) { - this.state = state; - } + void setState(State state); /** * Returns the user's protocol version, or -1 if not set. @@ -60,15 +45,9 @@ public class ProtocolInfo extends StoredObject { * * @return protocol version, or -1 if not set */ - public int getProtocolVersion() { - return protocolVersion; - } + int getProtocolVersion(); - public void setProtocolVersion(int protocolVersion) { - // Map snapshot versions to the higher/orderer release version - ProtocolVersion protocol = ProtocolVersion.getProtocol(protocolVersion); - this.protocolVersion = protocol.getVersion(); - } + void setProtocolVersion(int protocolVersion); /** * Returns the server protocol version the user is connected to, or -1 if not set. @@ -76,14 +55,9 @@ public class ProtocolInfo extends StoredObject { * * @return server protocol version, or -1 if not set */ - public int getServerProtocolVersion() { - return serverProtocolVersion; - } + int getServerProtocolVersion(); - public void setServerProtocolVersion(int serverProtocolVersion) { - ProtocolVersion protocol = ProtocolVersion.getProtocol(serverProtocolVersion); - this.serverProtocolVersion = protocol.getVersion(); - } + void setServerProtocolVersion(int serverProtocolVersion); /** * Returns the username associated with this connection. @@ -91,13 +65,9 @@ public class ProtocolInfo extends StoredObject { * * @return username, set when entering the {@link State#PLAY} state */ - public @MonotonicNonNull String getUsername() { - return username; - } + @MonotonicNonNull String getUsername(); - public void setUsername(String username) { - this.username = username; - } + void setUsername(String username); /** * Returns the uuid associated with this connection. @@ -105,35 +75,23 @@ public class ProtocolInfo extends StoredObject { * * @return uuid, set when entering the {@link State#PLAY} state */ - public UUID getUuid() { - return uuid; - } + UUID getUuid(); - public void setUuid(UUID uuid) { - this.uuid = uuid; - } + void setUuid(UUID uuid); /** * Returns the user's pipeline. * * @return protocol pipeline */ - public ProtocolPipeline getPipeline() { - return pipeline; - } + ProtocolPipeline getPipeline(); - public void setPipeline(ProtocolPipeline pipeline) { - this.pipeline = pipeline; - } + void setPipeline(ProtocolPipeline pipeline); - @Override - public String toString() { - return "ProtocolInfo{" + - "state=" + state + - ", protocolVersion=" + protocolVersion + - ", serverProtocolVersion=" + serverProtocolVersion + - ", username='" + username + '\'' + - ", uuid=" + uuid + - '}'; - } + /** + * Returns the user connection this info represents. + * + * @return user connection + */ + UserConnection getUser(); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/connection/StoredObject.java b/api/src/main/java/com/viaversion/viaversion/api/connection/StoredObject.java index cacaf800f..7c8bfd11c 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/connection/StoredObject.java +++ b/api/src/main/java/com/viaversion/viaversion/api/connection/StoredObject.java @@ -22,10 +22,10 @@ */ package com.viaversion.viaversion.api.connection; -public class StoredObject { +public abstract class StoredObject { private final UserConnection user; - public StoredObject(UserConnection user) { + protected StoredObject(UserConnection user) { this.user = user; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/connection/UserConnection.java b/api/src/main/java/com/viaversion/viaversion/api/connection/UserConnection.java index 5bc2f6f94..b33a6cb6c 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/connection/UserConnection.java +++ b/api/src/main/java/com/viaversion/viaversion/api/connection/UserConnection.java @@ -22,63 +22,21 @@ */ package com.viaversion.viaversion.api.connection; -import com.google.common.cache.CacheBuilder; +import com.viaversion.viaversion.api.configuration.ViaVersionConfig; import com.viaversion.viaversion.api.protocol.packet.PacketTracker; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.exception.CancelException; +import com.viaversion.viaversion.exception.InformativeException; import io.netty.buffer.ByteBuf; import io.netty.channel.Channel; import io.netty.channel.ChannelFuture; -import io.netty.channel.ChannelHandlerContext; import org.checkerframework.checker.nullness.qual.Nullable; -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.configuration.ViaVersionConfig; -import com.viaversion.viaversion.api.type.Type; -import com.viaversion.viaversion.exception.CancelException; -import com.viaversion.viaversion.exception.InformativeException; -import com.viaversion.viaversion.api.protocol.packet.Direction; -import com.viaversion.viaversion.util.ChatColorUtil; -import com.viaversion.viaversion.util.PipelineUtil; -import java.util.Collections; import java.util.Map; -import java.util.Set; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; -public class UserConnection { - private static final AtomicLong IDS = new AtomicLong(); - private final long id = IDS.incrementAndGet(); - private final Map, StoredObject> storedObjects = new ConcurrentHashMap<>(); - private final PacketTracker packetTracker = new PacketTracker(this); - private final Set passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder() - .expireAfterWrite(10, TimeUnit.SECONDS) - .build().asMap()); - private final Channel channel; - private final boolean clientSide; - private ProtocolInfo protocolInfo; - private boolean active = true; - private boolean pendingDisconnect; - - /** - * Creates an UserConnection. When it's a client-side connection, some method behaviors are modified. - * - * @param channel netty channel. - * @param clientSide true if it's a client-side connection - */ - public UserConnection(@Nullable Channel channel, boolean clientSide) { - this.channel = channel; - this.clientSide = clientSide; - } - - /** - * @see #UserConnection(Channel, boolean) - */ - public UserConnection(@Nullable Channel channel) { - this(channel, false); - } +public interface UserConnection { /** * Get an object from the storage. @@ -87,9 +45,7 @@ public class UserConnection { * @param The type of the class you want to get. * @return The requested object */ - public @Nullable T get(Class objectClass) { - return (T) storedObjects.get(objectClass); - } + @Nullable T get(Class objectClass); /** * Check if the storage has an object. @@ -97,26 +53,20 @@ public class UserConnection { * @param objectClass The object class to check * @return True if the object is in the storage */ - public boolean has(Class objectClass) { - return storedObjects.containsKey(objectClass); - } + boolean has(Class objectClass); /** * Put an object into the stored objects based on class. * * @param object The object to store. */ - public void put(StoredObject object) { - storedObjects.put(object.getClass(), object); - } + void put(StoredObject object); /** * Clear all the stored objects. * Used for bungee when switching servers. */ - public void clearStoredObjects() { - storedObjects.clear(); - } + void clearStoredObjects(); /** * Send a raw packet to the player. @@ -124,26 +74,7 @@ public class UserConnection { * @param packet The raw packet to send * @param currentThread Should it run in the same thread */ - public void sendRawPacket(final ByteBuf packet, boolean currentThread) { - Runnable act; - if (clientSide) { - // We'll just assume that Via decoder isn't wrapping the original decoder - act = () -> getChannel().pipeline() - .context(Via.getManager().getInjector().getDecoderName()).fireChannelRead(packet); - } else { - act = () -> channel.pipeline().context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet); - } - if (currentThread) { - act.run(); - } else { - try { - channel.eventLoop().submit(act); - } catch (Throwable e) { - packet.release(); // Couldn't schedule - e.printStackTrace(); - } - } - } + void sendRawPacket(ByteBuf packet, boolean currentThread); /** * Send a raw packet to the player with returning the future. @@ -151,57 +82,28 @@ public class UserConnection { * @param packet The raw packet to send * @return ChannelFuture of the packet being sent */ - public ChannelFuture sendRawPacketFuture(final ByteBuf packet) { - if (clientSide) { - return sendRawPacketFutureClientSide(packet); - } else { - return sendRawPacketFutureServerSide(packet); - } - } - - private ChannelFuture sendRawPacketFutureServerSide(final ByteBuf packet) { - return channel.pipeline().context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet); - } - - private ChannelFuture sendRawPacketFutureClientSide(final ByteBuf packet) { - // Assume that decoder isn't wrapping - getChannel().pipeline().context(Via.getManager().getInjector().getDecoderName()).fireChannelRead(packet); - return getChannel().newSucceededFuture(); - } + ChannelFuture sendRawPacketFuture(ByteBuf packet); /** * Send a raw packet to the player (netty thread). * * @param packet The packet to send */ - public void sendRawPacket(ByteBuf packet) { - sendRawPacket(packet, false); - } + void sendRawPacket(ByteBuf packet); /** * Returns the user's packet tracker used for the inbuilt packet-limiter. * * @return packet tracker */ - public PacketTracker getPacketTracker() { - return packetTracker; - } + PacketTracker getPacketTracker(); /** * Disconnect a connection. * * @param reason The reason to use, not used if player is not active. */ - public void disconnect(String reason) { - if (!channel.isOpen() || pendingDisconnect) return; - - pendingDisconnect = true; - Via.getPlatform().runSync(() -> { - if (!Via.getPlatform().disconnect(this, ChatColorUtil.translateAlternateColorCodes(reason))) { - channel.close(); // =) - } - }); - } + void disconnect(String reason); /** * Sends a raw packet to the server. @@ -209,120 +111,35 @@ public class UserConnection { * @param packet Raw packet to be sent * @param currentThread If {@code true} executes immediately, {@code false} submits a task to EventLoop */ - public void sendRawPacketToServer(final ByteBuf packet, boolean currentThread) { - if (clientSide) { - sendRawPacketToServerClientSide(packet, currentThread); - } else { - sendRawPacketToServerServerSide(packet, currentThread); - } - } - - private void sendRawPacketToServerServerSide(final ByteBuf packet, boolean currentThread) { - final ByteBuf buf = packet.alloc().buffer(); - try { - // We'll use passing through because there are some encoder wrappers - ChannelHandlerContext context = PipelineUtil - .getPreviousContext(Via.getManager().getInjector().getDecoderName(), channel.pipeline()); - try { - Type.VAR_INT.writePrimitive(buf, PacketWrapper.PASSTHROUGH_ID); - Type.UUID.write(buf, generatePassthroughToken()); - } catch (Exception shouldNotHappen) { - throw new RuntimeException(shouldNotHappen); - } - buf.writeBytes(packet); - Runnable act = () -> { - if (context != null) { - context.fireChannelRead(buf); - } else { - channel.pipeline().fireChannelRead(buf); - } - }; - if (currentThread) { - act.run(); - } else { - try { - channel.eventLoop().submit(act); - } catch (Throwable t) { - // Couldn't schedule - buf.release(); - throw t; - } - } - } finally { - packet.release(); - } - } - - private void sendRawPacketToServerClientSide(final ByteBuf packet, boolean currentThread) { - Runnable act = () -> getChannel().pipeline() - .context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet); - if (currentThread) { - act.run(); - } else { - try { - getChannel().eventLoop().submit(act); - } catch (Throwable e) { - e.printStackTrace(); - packet.release(); // Couldn't schedule - } - } - } + void sendRawPacketToServer(ByteBuf packet, boolean currentThread); /** * Sends a raw packet to the server. It will submit a task to EventLoop. * * @param packet Raw packet to be sent */ - public void sendRawPacketToServer(ByteBuf packet) { - sendRawPacketToServer(packet, false); - } + void sendRawPacketToServer(ByteBuf packet); /** * Monitors incoming packets * * @return false if this packet should be cancelled */ - public boolean checkIncomingPacket() { - if (clientSide) { - return checkClientbound(); - } else { - return checkServerbound(); - } - } - - private boolean checkClientbound() { - packetTracker.incrementSent(); - return true; - } - - private boolean checkServerbound() { - // Ignore if pending disconnect - if (pendingDisconnect) return false; - // Increment received + Check PPS - return !packetTracker.incrementReceived() || !packetTracker.exceedsMaxPPS(); - } + boolean checkIncomingPacket(); /** * Monitors outgoing packets * * @return false if this packet should be cancelled */ - public boolean checkOutgoingPacket() { - if (clientSide) { - return checkServerbound(); - } else { - return checkClientbound(); - } - } + boolean checkOutgoingPacket(); /** * Checks if packets needs transforming. * * @return if packets should be passed through */ - public boolean shouldTransformPacket() { - return active; - } + boolean shouldTransformPacket(); /** * Transforms the outgoing packet contained in ByteBuf. When clientSide is true, this packet is considered @@ -335,10 +152,7 @@ public class UserConnection { * @throws InformativeException if packet transforming failed * @throws Exception if any other processing outside of transforming fails */ - public void transformOutgoing(ByteBuf buf, Function cancelSupplier) throws Exception { - if (!buf.isReadable()) return; - transform(buf, clientSide ? Direction.INCOMING : Direction.OUTGOING, cancelSupplier); - } + void transformOutgoing(ByteBuf buf, Function cancelSupplier) throws Exception; /** * Transforms the incoming packet contained in ByteBuf. When clientSide is true, this packet is considered @@ -351,71 +165,30 @@ public class UserConnection { * @throws InformativeException if packet transforming failed * @throws Exception if any other processing outside of transforming fails */ - public void transformIncoming(ByteBuf buf, Function cancelSupplier) throws Exception { - if (!buf.isReadable()) return; - transform(buf, clientSide ? Direction.OUTGOING : Direction.INCOMING, cancelSupplier); - } - - private void transform(ByteBuf buf, Direction direction, Function cancelSupplier) throws Exception { - int id = Type.VAR_INT.readPrimitive(buf); - if (id == PacketWrapper.PASSTHROUGH_ID) { - if (!passthroughTokens.remove(Type.UUID.read(buf))) { - throw new IllegalArgumentException("Invalid token"); - } - return; - } - - PacketWrapper wrapper = new PacketWrapper(id, buf, this); - try { - protocolInfo.getPipeline().transform(direction, protocolInfo.getState(), wrapper); - } catch (CancelException ex) { - throw cancelSupplier.apply(ex); - } - - ByteBuf transformed = buf.alloc().buffer(); - try { - wrapper.writeToBuffer(transformed); - buf.clear().writeBytes(transformed); - } finally { - transformed.release(); - } - } + void transformIncoming(ByteBuf buf, Function cancelSupplier) throws Exception; /** * Returns the internal id incremented for each new connection. * * @return internal id */ - public long getId() { - return id; - } + long getId(); /** * Returns the netty channel if present. * * @return netty channel if present */ - public @Nullable Channel getChannel() { - return channel; - } + @Nullable Channel getChannel(); /** * Returns info containing the current protocol state and userdata. * * @return info containing the current protocol state and userdata */ - public @Nullable ProtocolInfo getProtocolInfo() { - return protocolInfo; - } + @Nullable ProtocolInfo getProtocolInfo(); - public void setProtocolInfo(@Nullable ProtocolInfo protocolInfo) { - this.protocolInfo = protocolInfo; - if (protocolInfo != null) { - storedObjects.put(ProtocolInfo.class, protocolInfo); - } else { - storedObjects.remove(ProtocolInfo.class); - } - } + void setProtocolInfo(@Nullable ProtocolInfo protocolInfo); /** * Returns a map of stored objects. @@ -425,35 +198,25 @@ public class UserConnection { * @see #get(Class) * @see #put(StoredObject) */ - public Map, StoredObject> getStoredObjects() { - return storedObjects; - } + Map, StoredObject> getStoredObjects(); /** * Returns whether the connection has protocols other than the base protocol applied. * * @return whether the connection is active */ - public boolean isActive() { - return active; - } + boolean isActive(); - public void setActive(boolean active) { - this.active = active; - } + void setActive(boolean active); /** * Returns whether the connection is pending a disconnect, initiated through {@link #disconnect(String)}. * * @return whether the connection is pending a disconnect */ - public boolean isPendingDisconnect() { - return pendingDisconnect; - } + boolean isPendingDisconnect(); - public void setPendingDisconnect(boolean pendingDisconnect) { - this.pendingDisconnect = pendingDisconnect; - } + void setPendingDisconnect(boolean pendingDisconnect); /** * Returns whether this is a client-side connection. @@ -461,18 +224,14 @@ public class UserConnection { * * @return whether this is a client-side connection */ - public boolean isClientSide() { - return clientSide; - } + boolean isClientSide(); /** * Returns whether {@link ViaVersionConfig#getBlockedProtocols()} should be checked for this connection. * * @return whether blocked protocols should be applied */ - public boolean shouldApplyBlockProtocol() { - return !clientSide; // Don't apply protocol blocking on client-side - } + boolean shouldApplyBlockProtocol(); /** * Returns a newly generated uuid that will let a packet be passed through without @@ -480,22 +239,5 @@ public class UserConnection { * * @return generated passthrough token */ - public UUID generatePassthroughToken() { - UUID token = UUID.randomUUID(); - passthroughTokens.add(token); - return token; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - UserConnection that = (UserConnection) o; - return id == that.id; - } - - @Override - public int hashCode() { - return Long.hashCode(id); - } + UUID generatePassthroughToken(); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractSimpleProtocol.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractSimpleProtocol.java new file mode 100644 index 000000000..09b1b50f6 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/AbstractSimpleProtocol.java @@ -0,0 +1,29 @@ +/* + * 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 com.viaversion.viaversion.api.protocol; + +import com.viaversion.viaversion.api.protocol.base.SimpleProtocol; + +public abstract class AbstractSimpleProtocol extends Protocol implements SimpleProtocol { +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java index ad9cef7fc..72d8cb7e0 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/Protocol.java @@ -23,20 +23,19 @@ package com.viaversion.viaversion.api.protocol; import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.Direction; 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 org.checkerframework.checker.nullness.qual.Nullable; -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.data.MappingData; -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; import com.viaversion.viaversion.exception.CancelException; import com.viaversion.viaversion.exception.InformativeException; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.Arrays; import java.util.HashMap; @@ -44,17 +43,8 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; -/** - * Abstract protocol class handling packet transformation between two protocol versions. - * Clientbound and serverbount packet types can be set to enforce correct usage of them. - * - * @param old clientbound packet types - * @param new clientbound packet types - * @param old serverbound packet types - * @param new serverbound packet types - * @see SimpleProtocol for a helper class if you do not want to define any of the types above - */ -public abstract class Protocol { +public abstract class Protocol + implements com.viaversion.viaversion.api.protocol.base.Protocol { private final Map incoming = new HashMap<>(); private final Map outgoing = new HashMap<>(); private final Map storedObjects = new HashMap<>(); // currently only used for MetadataRewriters @@ -137,26 +127,8 @@ public abstract class Protocol - * To be overridden if needed. - * - * @param providers The current providers - */ + @Override public void register(ViaProviders providers) { } - /** - * Initialise a user for this protocol setting up objects. - * /!\ WARNING - May be called more than once in a single {@link UserConnection} - *

- * To be overridden if needed. - * - * @param userConnection The user to initialise - */ + @Override public void init(UserConnection userConnection) { } - /** - * Register an incoming packet, with simple id transformation. - * - * @param state The state which the packet is sent in. - * @param oldPacketID The old packet ID - * @param newPacketID The new packet ID - */ + @Override public void registerIncoming(State state, int oldPacketID, int newPacketID) { registerIncoming(state, oldPacketID, newPacketID, null); } - /** - * Register an incoming packet, with id transformation and remapper. - * - * @param state The state which the packet is sent in. - * @param oldPacketID The old packet ID - * @param newPacketID The new packet ID - * @param packetRemapper The remapper to use for the packet - */ + @Override public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) { registerIncoming(state, oldPacketID, newPacketID, packetRemapper, false); } + @Override public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override) { ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper); Packet packet = new Packet(state, newPacketID); @@ -236,6 +181,7 @@ public abstract class Protocol packetMap = (direction == Direction.OUTGOING ? outgoing : incoming); @@ -475,39 +367,21 @@ public abstract class Protocol T get(Class objectClass) { return (T) storedObjects.get(objectClass); } + @Override public void put(Object object) { storedObjects.put(object.getClass(), object); } - /** - * Returns true if this Protocol's {@link #loadMappingData()} method should be called. - *

- * This does *not* necessarily mean that {@link #getMappingData()} is non-null, since this may be - * overriden, depending on special cases. - * - * @return true if this Protocol's {@link #loadMappingData()} method should be called - */ + @Override public boolean hasMappingDataToLoad() { return getMappingData() != null; } - public @Nullable MappingData getMappingData() { - return null; // Let the protocols hold the mappings to still have easy, static singleton access there - } - - /** - * Returns whether this protocol is a base protocol. - * - * @return whether this represents a base protocol - */ - public boolean isBaseProtocol() { - return false; - } - @Override public String toString() { return "Protocol:" + getClass().getSimpleName(); diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolManager.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolManager.java index 2b50331a4..917994442 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolManager.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolManager.java @@ -23,8 +23,13 @@ package com.viaversion.viaversion.api.protocol; import com.google.common.collect.Range; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.base.Protocol; +import com.viaversion.viaversion.api.protocol.packet.PacketType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion; +import io.netty.buffer.ByteBuf; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.List; @@ -44,9 +49,10 @@ public interface ProtocolManager { * Returns a protocol instance by its class. * * @param protocolClass class of the protocol + * @param protocol * @return protocol if present */ - @Nullable Protocol getProtocol(Class protocolClass); + @Nullable T getProtocol(Class protocolClass); /** * Returns the base protocol handling incoming handshake packets. @@ -180,4 +186,15 @@ public interface ProtocolManager { * @return data loading future bound to the protocol, or null if all loading is complete */ @Nullable CompletableFuture getMappingLoaderFuture(Class protocolClass); + + /** + * Creates a new packet wrapper instance. + * + * @param packetId packet id + * @param buf input buffer + * @param connection user connection + * @return new packet wrapper instance + * @see PacketWrapper#create(PacketType, ByteBuf, UserConnection) + */ + PacketWrapper createPacketWrapper(int packetId, ByteBuf buf, UserConnection connection); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPathEntry.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPathEntry.java index 50c896623..40cee0908 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPathEntry.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPathEntry.java @@ -22,6 +22,8 @@ */ package com.viaversion.viaversion.api.protocol; +import com.viaversion.viaversion.api.protocol.base.Protocol; + public interface ProtocolPathEntry { /** diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java index 724967540..988445450 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/ProtocolPipeline.java @@ -22,52 +22,14 @@ */ package com.viaversion.viaversion.api.protocol; -import com.google.common.base.Preconditions; -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.connection.ProtocolInfo; import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.platform.ViaPlatform; -import com.viaversion.viaversion.api.protocol.packet.Direction; -import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.base.Protocol; +import com.viaversion.viaversion.api.protocol.base.SimpleProtocol; +import org.checkerframework.checker.nullness.qual.Nullable; -import java.util.ArrayList; import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.logging.Level; -public class ProtocolPipeline extends SimpleProtocol { - /** - * Protocol list ordered from client to server transforation with the base protocols at the end. - */ - private List protocolList; - private UserConnection userConnection; - - public ProtocolPipeline(UserConnection userConnection) { - init(userConnection); - } - - @Override - protected void registerPackets() { - protocolList = new CopyOnWriteArrayList<>(); - // This is a pipeline so we register basic pipes - protocolList.add(Via.getManager().getProtocolManager().getBaseProtocol()); - } - - @Override - public void init(UserConnection userConnection) { - this.userConnection = userConnection; - - ProtocolInfo protocolInfo = new ProtocolInfo(userConnection); - protocolInfo.setPipeline(this); - - userConnection.setProtocolInfo(protocolInfo); - - /* Init through all our pipes */ - for (Protocol protocol : protocolList) { - protocol.init(userConnection); - } - } +public interface ProtocolPipeline extends SimpleProtocol { /** * Adds a protocol to the current pipeline. @@ -75,16 +37,7 @@ public class ProtocolPipeline extends SimpleProtocol { * * @param protocol protocol to add to the end */ - public void add(Protocol protocol) { - Preconditions.checkNotNull(protocolList, "Tried to add protocol too early"); - - protocolList.add(protocol); - protocol.init(userConnection); - - if (!protocol.isBaseProtocol()) { - moveBaseProtocolsToTail(); - } - } + void add(Protocol protocol); /** * Adds a list of protocols to the current pipeline. @@ -92,70 +45,7 @@ public class ProtocolPipeline extends SimpleProtocol { * * @param protocols protocols to add to the end */ - public void add(List protocols) { - Preconditions.checkNotNull(protocolList, "Tried to add protocol too early"); - - protocolList.addAll(protocols); - for (Protocol protocol : protocols) { - protocol.init(userConnection); - } - - moveBaseProtocolsToTail(); - } - - private void moveBaseProtocolsToTail() { - // Move base Protocols to the end, so the login packets can be modified by other protocols - List baseProtocols = null; - for (Protocol protocol : protocolList) { - if (protocol.isBaseProtocol()) { - if (baseProtocols == null) { - baseProtocols = new ArrayList<>(); - } - - baseProtocols.add(protocol); - } - } - - if (baseProtocols != null) { - protocolList.removeAll(baseProtocols); - protocolList.addAll(baseProtocols); - } - } - - @Override - public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception { - int originalID = packetWrapper.getId(); - - // Apply protocols - packetWrapper.apply(direction, state, 0, protocolList, direction == Direction.OUTGOING); - super.transform(direction, state, packetWrapper); - - if (Via.getManager().isDebug()) { - logPacket(direction, state, packetWrapper, originalID); - } - } - - private void logPacket(Direction direction, State state, PacketWrapper packetWrapper, int originalID) { - // Debug packet - int clientProtocol = userConnection.getProtocolInfo().getProtocolVersion(); - ViaPlatform platform = Via.getPlatform(); - - String actualUsername = packetWrapper.user().getProtocolInfo().getUsername(); - String username = actualUsername != null ? actualUsername + " " : ""; - - platform.getLogger().log(Level.INFO, "{0}{1} {2}: {3} (0x{4}) -> {5} (0x{6}) [{7}] {8}", - new Object[]{ - username, - direction, - state, - originalID, - Integer.toHexString(originalID), - packetWrapper.getId(), - Integer.toHexString(packetWrapper.getId()), - Integer.toString(clientProtocol), - packetWrapper - }); - } + void add(List protocols); /** * Check if the pipeline contains a protocol @@ -163,19 +53,18 @@ public class ProtocolPipeline extends SimpleProtocol { * @param pipeClass The class to check * @return True if the protocol class is in the pipeline */ - public boolean contains(Class pipeClass) { - for (Protocol protocol : protocolList) { - if (protocol.getClass().equals(pipeClass)) return true; - } - return false; - } + boolean contains(Class pipeClass); - public

P getProtocol(Class

pipeClass) { - for (Protocol protocol : protocolList) { - if (protocol.getClass() == pipeClass) return (P) protocol; - } - return null; - } + /** + * Returns the protocol from the given class if present in the pipeline. + * + * @param pipeClass protocol class + * @param

protocol + * @return protocol from class + * @see #contains(Class) + * @see ProtocolManager#getProtocol(Class) for a faster alternative + */ + @Nullable

P getProtocol(Class

pipeClass); /** * Use the pipeline to filter a NMS packet @@ -185,27 +74,13 @@ public class ProtocolPipeline extends SimpleProtocol { * @return If it should not write the input object to te list. * @throws Exception If it failed to convert / packet cancelld. */ - public boolean filter(Object o, List list) throws Exception { - for (Protocol protocol : protocolList) { - if (protocol.isFiltered(o.getClass())) { - protocol.filterPacket(userConnection, o, list); - return true; - } - } + boolean filter(Object o, List list) throws Exception; - return false; - } - - public List pipes() { - return protocolList; - } + List pipes(); /** * Cleans the pipe and adds the base protocol. * /!\ WARNING - It doesn't add version-specific base Protocol. */ - public void cleanPipes() { - pipes().clear(); - registerPackets(); - } + void cleanPipes(); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/base/Protocol.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/base/Protocol.java new file mode 100644 index 000000000..773944f50 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/base/Protocol.java @@ -0,0 +1,247 @@ +/* + * 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 com.viaversion.viaversion.api.protocol.base; + +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.MappingData; +import com.viaversion.viaversion.api.platform.providers.ViaProviders; +import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol; +import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; +import com.viaversion.viaversion.api.protocol.packet.Direction; +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.remapper.PacketRemapper; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.List; + +/** + * Abstract protocol class handling packet transformation between two protocol versions. + * Clientbound and serverbount packet types can be set to enforce correct usage of them. + * + * @param old clientbound packet types + * @param new clientbound packet types + * @param old serverbound packet types + * @param new serverbound packet types + * @see AbstractSimpleProtocol for a helper class if you do not want to define any of the types above + */ +public interface Protocol { + + /** + * Should this protocol filter an object packet from this class. + * Default: false + * + * @param packetClass The class of the current input + * @return True if it should handle the filtering + */ + default boolean isFiltered(Class packetClass) { + return false; + } + + /** + * Filter a packet into the output + * + * @param info The current user connection + * @param packet The input packet as an object (NMS) + * @param output The list to put the object into. + * @throws Exception Throws exception if cancelled / error. + */ + void filterPacket(UserConnection info, Object packet, List output) throws Exception; + + /** + * Loads the mappingdata. + */ + void loadMappingData(); + + /** + * Handle protocol registration phase, use this to register providers / tasks. + *

+ * To be overridden if needed. + * + * @param providers The current providers + */ + void register(ViaProviders providers); + + /** + * Initialise a user for this protocol setting up objects. + * /!\ WARNING - May be called more than once in a single {@link UserConnection} + *

+ * To be overridden if needed. + * + * @param userConnection The user to initialise + */ + void init(UserConnection userConnection); + + /** + * Register an incoming packet, with simple id transformation. + * + * @param state The state which the packet is sent in. + * @param oldPacketID The old packet ID + * @param newPacketID The new packet ID + */ + void registerIncoming(State state, int oldPacketID, int newPacketID); + + /** + * Register an incoming packet, with id transformation and remapper. + * + * @param state The state which the packet is sent in. + * @param oldPacketID The old packet ID + * @param newPacketID The new packet ID + * @param packetRemapper The remapper to use for the packet + */ + void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper); + + void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override); + + void cancelIncoming(State state, int oldPacketID, int newPacketID); + + void cancelIncoming(State state, int newPacketID); + + /** + * Register an outgoing packet, with simple id transformation. + * + * @param state The state which the packet is sent in. + * @param oldPacketID The old packet ID + * @param newPacketID The new packet ID + */ + void registerOutgoing(State state, int oldPacketID, int newPacketID); + + /** + * Register an outgoing packet, with id transformation and remapper. + * + * @param state The state which the packet is sent in. + * @param oldPacketID The old packet ID + * @param newPacketID The new packet ID + * @param packetRemapper The remapper to use for the packet + */ + void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper); + + void cancelOutgoing(State state, int oldPacketID, int newPacketID); + + void cancelOutgoing(State state, int oldPacketID); + + void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override); + + /** + * Registers an outgoing protocol and automatically maps it to the new id. + * + * @param packetType clientbound packet type the server sends + * @param packetRemapper remapper + */ + void registerOutgoing(C1 packetType, @Nullable PacketRemapper packetRemapper); + + /** + * Registers an outgoing protocol. + * + * @param packetType clientbound packet type the server initially sends + * @param mappedPacketType clientbound packet type after transforming for the client + * @param packetRemapper remapper + */ + void registerOutgoing(C1 packetType, C2 mappedPacketType, @Nullable PacketRemapper packetRemapper); + + /** + * Maps a packet type to another packet type without a packet handler. + * Note that this should not be called for simple channel mappings of the same packet; this is already done automatically. + * + * @param packetType clientbound packet type the server initially sends + * @param mappedPacketType clientbound packet type after transforming for the client + */ + void registerOutgoing(C1 packetType, C2 mappedPacketType); + + void cancelOutgoing(C1 packetType); + + /** + * Registers an incoming protocol and automatically maps it to the server's id. + * + * @param packetType serverbound packet type the client sends + * @param packetRemapper remapper + */ + void registerIncoming(S2 packetType, @Nullable PacketRemapper packetRemapper); + + /** + * Registers an incoming protocol. + * + * @param packetType serverbound packet type initially sent by the client + * @param mappedPacketType serverbound packet type after transforming for the server + * @param packetRemapper remapper + */ + void registerIncoming(S2 packetType, S1 mappedPacketType, @Nullable PacketRemapper packetRemapper); + + void cancelIncoming(S2 packetType); + + /** + * Checks if an outgoing packet has already been registered. + * + * @param state state which the packet is sent in + * @param oldPacketID old packet ID + * @return true if already registered + */ + boolean hasRegisteredOutgoing(State state, int oldPacketID); + + /** + * Checks if an incoming packet has already been registered. + * + * @param state state which the packet is sent in + * @param newPacketId packet ID + * @return true if already registered + */ + boolean hasRegisteredIncoming(State state, int newPacketId); + + /** + * Transform a packet using this protocol + * + * @param direction The direction the packet is going in + * @param state The current protocol state + * @param packetWrapper The packet wrapper to transform + * @throws Exception Throws exception if it fails to transform + */ + void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception; + + @Nullable T get(Class objectClass); + + void put(Object object); + + /** + * Returns true if this Protocol's {@link #loadMappingData()} method should be called. + *

+ * This does *not* necessarily mean that {@link #getMappingData()} is non-null, since this may be + * overriden, depending on special cases. + * + * @return true if this Protocol's {@link #loadMappingData()} method should be called + */ + boolean hasMappingDataToLoad(); + + default @Nullable MappingData getMappingData() { + return null; + } + + /** + * Returns whether this protocol is a base protocol. + * + * @return whether this represents a base protocol + */ + default boolean isBaseProtocol() { + return false; + } +} diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/SimpleProtocol.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/base/SimpleProtocol.java similarity index 79% rename from api/src/main/java/com/viaversion/viaversion/api/protocol/SimpleProtocol.java rename to api/src/main/java/com/viaversion/viaversion/api/protocol/base/SimpleProtocol.java index e79f7e1ce..5de43eedd 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/SimpleProtocol.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/base/SimpleProtocol.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.viaversion.viaversion.api.protocol; +package com.viaversion.viaversion.api.protocol.base; import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType; import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; @@ -29,13 +29,10 @@ import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; * Dummy protocol class when there is no need of any of the * existing packet type enums or automated channel mappings. * - * @see Protocol + * @see com.viaversion.viaversion.api.protocol.base.Protocol */ -public abstract class SimpleProtocol extends Protocol { +public interface SimpleProtocol extends Protocol { - protected SimpleProtocol() { - } - - public enum DummyPacketTypes implements ClientboundPacketType, ServerboundPacketType { + enum DummyPacketTypes implements ClientboundPacketType, ServerboundPacketType { } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java index 4d521005b..6ef1f2549 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/packet/PacketWrapper.java @@ -22,42 +22,55 @@ */ package com.viaversion.viaversion.api.protocol.packet; -import com.google.common.base.Preconditions; import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.util.Pair; -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelFuture; import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.protocol.base.Protocol; import com.viaversion.viaversion.api.protocol.remapper.ValueCreator; import com.viaversion.viaversion.api.type.Type; -import com.viaversion.viaversion.api.type.TypeConverter; -import com.viaversion.viaversion.exception.CancelException; import com.viaversion.viaversion.exception.InformativeException; -import com.viaversion.viaversion.util.PipelineUtil; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelFuture; +import org.checkerframework.checker.nullness.qual.Nullable; -import java.io.IOException; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; import java.util.List; -import java.util.NoSuchElementException; -public class PacketWrapper { - public static final int PASSTHROUGH_ID = 1000; - private static final Protocol[] PROTOCOL_ARRAY = new Protocol[0]; +public interface PacketWrapper { - private final ByteBuf inputBuffer; - private final UserConnection userConnection; - private boolean send = true; - private int id = -1; - private final Deque> readableObjects = new ArrayDeque<>(); - private final List> packetValues = new ArrayList<>(); + int PASSTHROUGH_ID = 1000; - public PacketWrapper(int packetID, ByteBuf inputBuffer, UserConnection userConnection) { - this.id = packetID; - this.inputBuffer = inputBuffer; - this.userConnection = userConnection; + /** + * Creates a new packet wrapper instance. + * + * @param packetType packet + * @param connection user connection + * @return new packet wrapper + */ + static PacketWrapper create(PacketType packetType, UserConnection connection) { + return create(packetType.ordinal(), null, connection); + } + + /** + * Creates a new packet wrapper instance. + * + * @param packetType packet type + * @param inputBuffer input buffer + * @param connection user connection + * @return new packet wrapper + */ + static PacketWrapper create(PacketType packetType, @Nullable ByteBuf inputBuffer, UserConnection connection) { + return create(packetType.ordinal(), inputBuffer, connection); + } + + /** + * Creates a new packet wrapper instance. + * + * @param packetId packet id + * @param inputBuffer input buffer + * @param connection user connection + * @return new packet wrapper + */ + static PacketWrapper create(int packetId, @Nullable ByteBuf inputBuffer, UserConnection connection) { + return Via.getManager().getProtocolManager().createPacketWrapper(packetId, inputBuffer, connection); } /** @@ -69,20 +82,7 @@ public class PacketWrapper { * @return The requested type or throws ArrayIndexOutOfBounds * @throws InformativeException If it fails to find it, an exception will be thrown. */ - public T get(Type type, int index) throws Exception { - int currentIndex = 0; - for (Pair packetValue : packetValues) { - if (packetValue.getKey() == type) { // Ref check - if (currentIndex == index) { - return (T) packetValue.getValue(); - } - 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()).set("Data", packetValues); - } + T get(Type type, int index) throws Exception; /** * Check if a type is at an index @@ -91,18 +91,7 @@ public class PacketWrapper { * @param index The index of the part (relative to the type) * @return True if the type is at the index */ - public boolean is(Type type, int index) { - int currentIndex = 0; - for (Pair packetValue : packetValues) { - if (packetValue.getKey() == type) { // Ref check - if (currentIndex == index) { - return true; - } - currentIndex++; - } - } - return false; - } + boolean is(Type type, int index); /** * Check if a type is at an index @@ -111,19 +100,7 @@ public class PacketWrapper { * @param index The index of the part (relative to the type) * @return True if the type is at the index */ - public boolean isReadable(Type type, int index) { - int currentIndex = 0; - for (Pair packetValue : readableObjects) { - if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check - if (currentIndex == index) { - return true; - } - currentIndex++; - } - } - return false; - } - + boolean isReadable(Type type, int index); /** * Set a currently existing part in the output @@ -134,20 +111,7 @@ public class PacketWrapper { * @param value The value of the part you wish to set it to. * @throws InformativeException If it fails to set it, an exception will be thrown. */ - public void set(Type type, int index, T value) throws Exception { - int currentIndex = 0; - for (Pair packetValue : packetValues) { - if (packetValue.getKey() == type) { // Ref check - if (currentIndex == index) { - packetValue.setValue(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()); - } + void set(Type type, int index, T value) throws Exception; /** * Read a type from the input. @@ -157,33 +121,7 @@ public class PacketWrapper { * @return The requested type * @throws InformativeException If it fails to read */ - public T read(Type type) throws Exception { - if (type == Type.NOTHING) return null; - if (readableObjects.isEmpty()) { - Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer."); - // We could in the future log input read values, but honestly for things like bulk maps, mem waste D: - try { - return type.read(inputBuffer); - } catch (Exception e) { - throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues); - } - } else { - Pair 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); - } - } - } - } + T read(Type type) throws Exception; /** * Write a type to the output. @@ -192,19 +130,7 @@ public class PacketWrapper { * @param The return type of the type you wish to write. * @param value The value of the type to write. */ - public void write(Type 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, value)); - } + void write(Type type, T value); /** * Take a value from the input and write to the output. @@ -214,26 +140,14 @@ public class PacketWrapper { * @return The type which was read/written. * @throws Exception If it failed to read or write */ - public T passthrough(Type type) throws Exception { - T value = read(type); - write(type, value); - return value; - } + T passthrough(Type type) throws Exception; /** * Take all the inputs and write them to the output. * * @throws Exception If it failed to read or write */ - public void passthroughAll() throws Exception { - // Copy previous objects - packetValues.addAll(readableObjects); - readableObjects.clear(); - // If the buffer has readable bytes, copy them. - if (inputBuffer.isReadable()) { - passthrough(Type.REMAINING_BYTES); - } - } + void passthroughAll() throws Exception; /** * Write the current output to a buffer. @@ -241,61 +155,17 @@ public class PacketWrapper { * @param buffer The buffer to write to. * @throws InformativeException Throws an exception if it fails to write a value. */ - public void writeToBuffer(ByteBuf buffer) throws Exception { - if (id != -1) { - Type.VAR_INT.writePrimitive(buffer, id); - } - if (!readableObjects.isEmpty()) { - packetValues.addAll(readableObjects); - readableObjects.clear(); - } - - int index = 0; - for (Pair 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); - } catch (Exception e) { - throw new InformativeException(e).set("Index", index).set("Type", packetValue.getKey().getTypeName()).set("Packet ID", getId()).set("Data", packetValues); - } - index++; - } - writeRemaining(buffer); - } + void writeToBuffer(ByteBuf buffer) throws Exception; /** * Clear the input buffer / readable objects */ - public void clearInputBuffer() { - if (inputBuffer != null) { - inputBuffer.clear(); - } - readableObjects.clear(); // :( - } + void clearInputBuffer(); /** * Clear the packet, used if you have to change the packet completely */ - public void clearPacket() { - clearInputBuffer(); - packetValues.clear(); - } - - private void writeRemaining(ByteBuf output) { - if (inputBuffer != null) { - output.writeBytes(inputBuffer); - } - } + void clearPacket(); /** * Send this packet to the associated user. @@ -306,9 +176,7 @@ public class PacketWrapper { * @param skipCurrentPipeline Skip the current pipeline * @throws Exception if it fails to write */ - public void send(Class packetProtocol, boolean skipCurrentPipeline) throws Exception { - send(packetProtocol, skipCurrentPipeline, false); - } + void send(Class packetProtocol, boolean skipCurrentPipeline) throws Exception; /** * Send this packet to the associated user. @@ -320,61 +188,7 @@ public class PacketWrapper { * @param currentThread Run in the same thread * @throws Exception if it fails to write */ - public void send(Class packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception { - if (!isCancelled()) { - try { - ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline, Direction.OUTGOING); - user().sendRawPacket(output, currentThread); - } catch (Exception e) { - if (!PipelineUtil.containsCause(e, CancelException.class)) { - throw e; - } - } - } - } - - /** - * Let the packet go through the protocol pipes and write it to ByteBuf - * - * @param packetProtocol The protocol version of the packet. - * @param skipCurrentPipeline Skip the current pipeline - * @return Packet buffer - * @throws Exception if it fails to write - */ - private ByteBuf constructPacket(Class packetProtocol, boolean skipCurrentPipeline, Direction direction) throws Exception { - // Apply current pipeline - for outgoing protocol, the collection will be reversed in the apply method - Protocol[] protocols = user().getProtocolInfo().getPipeline().pipes().toArray(PROTOCOL_ARRAY); - boolean reverse = direction == Direction.OUTGOING; - int index = -1; - for (int i = 0; i < protocols.length; i++) { - if (protocols[i].getClass() == packetProtocol) { - index = i; - break; - } - } - - if (index == -1) { - // The given protocol is not in the pipeline - throw new NoSuchElementException(packetProtocol.getCanonicalName()); - } - - if (skipCurrentPipeline) { - index = reverse ? index - 1 : index + 1; - } - - // Reset reader before we start - resetReader(); - - // Apply other protocols - apply(direction, user().getProtocolInfo().getState(), index, protocols, reverse); - ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); - try { - writeToBuffer(output); - return output.retain(); - } finally { - output.release(); - } - } + void send(Class packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception; /** * Send this packet to the associated user. @@ -384,7 +198,7 @@ public class PacketWrapper { * @param packetProtocol The protocol version of the packet. * @throws Exception if it fails to write */ - public void send(Class packetProtocol) throws Exception { + default void send(Class packetProtocol) throws Exception { send(packetProtocol, true); } @@ -398,13 +212,7 @@ public class PacketWrapper { * @return The packets ChannelFuture * @throws Exception if it fails to write */ - public ChannelFuture sendFuture(Class packetProtocol) throws Exception { - if (!isCancelled()) { - ByteBuf output = constructPacket(packetProtocol, true, Direction.OUTGOING); - return user().sendRawPacketFuture(output); - } - return user().getChannel().newFailedFuture(new Exception("Cancelled packet")); - } + ChannelFuture sendFuture(Class packetProtocol) throws Exception; /** * Send this packet to the associated user. @@ -415,18 +223,7 @@ public class PacketWrapper { * @throws Exception if it fails to write */ @Deprecated - public void send() throws Exception { - if (!isCancelled()) { - // Send - ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); - try { - writeToBuffer(output); - user().sendRawPacket(output.retain()); - } finally { - output.release(); - } - } - } + void send() throws Exception; /** * Create a new packet for the target of this packet. @@ -434,9 +231,7 @@ public class PacketWrapper { * @param packetType packet type of the new packedt * @return The newly created packet wrapper */ - public PacketWrapper create(PacketType packetType) { - return new PacketWrapper(packetType.ordinal(), null, user()); - } + PacketWrapper create(PacketType packetType); /** * Create a new packet for the target of this packet. @@ -444,9 +239,7 @@ public class PacketWrapper { * @param packetID The ID of the new packet * @return The newly created packet wrapper */ - public PacketWrapper create(int packetID) { - return new PacketWrapper(packetID, null, user()); - } + PacketWrapper create(int packetID); /** * Create a new packet with values. @@ -456,11 +249,7 @@ public class PacketWrapper { * @return The newly created packet wrapper * @throws Exception If it failed to write the values from the ValueCreator. */ - public PacketWrapper create(int packetID, ValueCreator init) throws Exception { - PacketWrapper wrapper = create(packetID); - init.write(wrapper); - return wrapper; - } + PacketWrapper create(int packetID, ValueCreator init) throws Exception; /** * Applies a pipeline from an index to the wrapper. @@ -473,69 +262,36 @@ public class PacketWrapper { * @return The current packetwrapper * @throws Exception If it fails to transform a packet, exception will be thrown */ - public PacketWrapper apply(Direction direction, State state, int index, List pipeline, boolean reverse) throws Exception { - Protocol[] array = pipeline.toArray(PROTOCOL_ARRAY); - return apply(direction, state, reverse ? array.length - 1 : index, array, reverse); // Copy to prevent from removal - } + PacketWrapper apply(Direction direction, State state, int index, List pipeline, boolean reverse) throws Exception; /** * @see #apply(Direction, State, int, List, boolean) */ - public PacketWrapper apply(Direction direction, State state, int index, List pipeline) throws Exception { - return apply(direction, state, index, pipeline.toArray(PROTOCOL_ARRAY), false); - } - - private PacketWrapper apply(Direction direction, State state, int index, Protocol[] pipeline, boolean reverse) throws Exception { - // Reset the reader after every transformation for the packetWrapper, so it can be recycled across packets - if (reverse) { - for (int i = index; i >= 0; i--) { - pipeline[i].transform(direction, state, this); - resetReader(); - } - } else { - for (int i = index; i < pipeline.length; i++) { - pipeline[i].transform(direction, state, this); - resetReader(); - } - } - return this; - } + PacketWrapper apply(Direction direction, State state, int index, List pipeline) throws Exception; /** * Cancel this packet from sending */ - public void cancel() { - this.send = false; - } + void cancel(); /** * Check if this packet is cancelled. * * @return True if the packet won't be sent. */ - public boolean isCancelled() { - return !this.send; - } + boolean isCancelled(); /** * Get the user associated with this Packet * * @return The user */ - public UserConnection user() { - return this.userConnection; - } + UserConnection user(); /** * Reset the reader, so that it can be read again. */ - public void resetReader() { - // Move all packet values to the readable for next packet. - for (int i = packetValues.size() - 1; i >= 0; i--) { - this.readableObjects.addFirst(this.packetValues.get(i)); - } - this.packetValues.clear(); - } + void resetReader(); /** * Send the current packet to the server. @@ -544,18 +300,7 @@ public class PacketWrapper { * @throws Exception If it failed to write */ @Deprecated - public void sendToServer() throws Exception { - if (!isCancelled()) { - ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); - try { - writeToBuffer(output); - - user().sendRawPacketToServer(output.retain(), true); - } finally { - output.release(); - } - } - } + void sendToServer() throws Exception; /** * Send this packet to the server. @@ -565,41 +310,17 @@ public class PacketWrapper { * @param currentThread Run in the same thread * @throws Exception if it fails to write */ - public void sendToServer(Class packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception { - if (!isCancelled()) { - try { - ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline, Direction.INCOMING); - user().sendRawPacketToServer(output, currentThread); - } catch (Exception e) { - if (!PipelineUtil.containsCause(e, CancelException.class)) { - throw e; - } - } - } - } + void sendToServer(Class packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception; - public void sendToServer(Class packetProtocol, boolean skipCurrentPipeline) throws Exception { + default void sendToServer(Class packetProtocol, boolean skipCurrentPipeline) throws Exception { sendToServer(packetProtocol, skipCurrentPipeline, false); } - public void sendToServer(Class packetProtocol) throws Exception { + default void sendToServer(Class packetProtocol) throws Exception { sendToServer(packetProtocol, true); } - public int getId() { - return id; - } + int getId(); - public void setId(int id) { - this.id = id; - } - - @Override - public String toString() { - return "PacketWrapper{" + - "packetValues=" + packetValues + - ", readableObjects=" + readableObjects + - ", id=" + id + - '}'; - } + void setId(int id); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/protocol/remapper/PacketRemapper.java b/api/src/main/java/com/viaversion/viaversion/api/protocol/remapper/PacketRemapper.java index cc01bdadf..a073d2f9e 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/protocol/remapper/PacketRemapper.java +++ b/api/src/main/java/com/viaversion/viaversion/api/protocol/remapper/PacketRemapper.java @@ -23,10 +23,10 @@ package com.viaversion.viaversion.api.protocol.remapper; import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.util.Pair; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.exception.CancelException; import com.viaversion.viaversion.exception.InformativeException; +import com.viaversion.viaversion.util.Pair; import java.util.ArrayList; import java.util.List; diff --git a/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java b/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java index 123c41316..ca94f7c3b 100644 --- a/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java +++ b/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/ArmorListener.java @@ -58,7 +58,7 @@ public class ArmorListener extends ViaBukkitListener { armor += ArmorType.findById(stack.getTypeId()).getArmorPoints(); } - PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player)); + PacketWrapper wrapper = PacketWrapper.create(0x4B, null, getUserConnection(player)); try { wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID wrapper.write(Type.INT, 1); // only 1 property diff --git a/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/DeathListener.java b/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/DeathListener.java index 6bc8cda50..8920867fa 100644 --- a/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/DeathListener.java +++ b/bukkit-legacy/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_9to1_8/DeathListener.java @@ -58,7 +58,7 @@ public class DeathListener extends ViaBukkitListener { // If online UserConnection userConnection = getUserConnection(p); if (userConnection != null) { - PacketWrapper wrapper = new PacketWrapper(0x2C, null, userConnection); + PacketWrapper wrapper = PacketWrapper.create(0x2C, null, userConnection); try { wrapper.write(Type.VAR_INT, 2); // Event - Entity dead wrapper.write(Type.VAR_INT, p.getEntityId()); // Player ID diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitChannelInitializer.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitChannelInitializer.java index 23e62fa48..7eaceee85 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitChannelInitializer.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/handlers/BukkitChannelInitializer.java @@ -17,13 +17,14 @@ */ package com.viaversion.viaversion.bukkit.handlers; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import com.viaversion.viaversion.connection.UserConnectionImpl; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.MessageToByteEncoder; import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.ProtocolPipeline; import com.viaversion.viaversion.bukkit.classgenerator.ClassGenerator; import com.viaversion.viaversion.bukkit.classgenerator.HandlerConstructor; @@ -50,9 +51,9 @@ public class BukkitChannelInitializer extends ChannelInitializer @Override protected void initChannel(SocketChannel socketChannel) throws Exception { - UserConnection info = new UserConnection(socketChannel); + UserConnection info = new UserConnectionImpl(socketChannel); // init protocol - new ProtocolPipeline(info); + new ProtocolPipelineImpl(info); // Add originals this.method.invoke(this.original, socketChannel); diff --git a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_15to1_14_4/EntityToggleGlideListener.java b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_15to1_14_4/EntityToggleGlideListener.java index 982919d0b..368646e95 100644 --- a/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_15to1_14_4/EntityToggleGlideListener.java +++ b/bukkit/src/main/java/com/viaversion/viaversion/bukkit/listeners/protocol1_15to1_14_4/EntityToggleGlideListener.java @@ -55,7 +55,7 @@ public class EntityToggleGlideListener extends ViaBukkitListener { // Cancelling can only be done by updating the player's metadata if (event.isGliding() && event.isCancelled()) { - PacketWrapper packet = new PacketWrapper(0x44, null, getUserConnection(player)); + PacketWrapper packet = PacketWrapper.create(0x44, null, getUserConnection(player)); try { packet.write(Type.VAR_INT, player.getEntityId()); diff --git a/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeChannelInitializer.java b/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeChannelInitializer.java index 8eb7156d8..ac9718d64 100644 --- a/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeChannelInitializer.java +++ b/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeChannelInitializer.java @@ -17,10 +17,11 @@ */ package com.viaversion.viaversion.bungee.handlers; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import com.viaversion.viaversion.connection.UserConnectionImpl; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.ProtocolPipeline; import java.lang.reflect.Method; @@ -44,9 +45,9 @@ public class BungeeChannelInitializer extends ChannelInitializer { return; } - UserConnection info = new UserConnection(socketChannel); + UserConnection info = new UserConnectionImpl(socketChannel); // init protocol - new ProtocolPipeline(info); + new ProtocolPipelineImpl(info); // Add originals this.method.invoke(this.original, socketChannel); diff --git a/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java b/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java index 39eb31c4b..7bdf86291 100644 --- a/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java +++ b/bungee/src/main/java/com/viaversion/viaversion/bungee/handlers/BungeeServerHandler.java @@ -17,6 +17,23 @@ */ package com.viaversion.viaversion.bungee.handlers; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ProtocolInfo; +import com.viaversion.viaversion.api.connection.StoredObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.ExternalJoinGameListener; +import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; +import com.viaversion.viaversion.api.protocol.ProtocolPipeline; +import com.viaversion.viaversion.api.protocol.base.Protocol; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.bungee.service.ProtocolDetectorService; +import com.viaversion.viaversion.bungee.storage.BungeeStorage; +import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets.InventoryPackets; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.EntityIdProvider; +import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.EntityTracker1_9; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectedEvent; @@ -25,23 +42,6 @@ import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.score.Team; import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.protocol.packet.PluginMessage; -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.data.ExternalJoinGameListener; -import com.viaversion.viaversion.api.connection.StoredObject; -import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.Protocol; -import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; -import com.viaversion.viaversion.api.protocol.ProtocolPipeline; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; -import com.viaversion.viaversion.api.type.Type; -import com.viaversion.viaversion.bungee.service.ProtocolDetectorService; -import com.viaversion.viaversion.bungee.storage.BungeeStorage; -import com.viaversion.viaversion.api.connection.ProtocolInfo; -import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.packets.InventoryPackets; -import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8; -import com.viaversion.viaversion.protocols.protocol1_9to1_8.providers.EntityIdProvider; -import com.viaversion.viaversion.protocols.protocol1_9to1_8.storage.EntityTracker1_9; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; @@ -162,7 +162,7 @@ public class BungeeServerHandler implements Listener { // This ensures we can encode it properly as only the 1.9 protocol is currently implemented. if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) { for (UUID uuid : storage.getBossbar()) { - PacketWrapper wrapper = new PacketWrapper(0x0C, null, user); + PacketWrapper wrapper = PacketWrapper.create(0x0C, null, user); wrapper.write(Type.UUID, uuid); wrapper.write(Type.VAR_INT, 1); // remove wrapper.send(Protocol1_9To1_8.class, true, true); @@ -230,7 +230,7 @@ public class BungeeServerHandler implements Listener { plMsg.setTag(channel); } - user.put(info); + user.setProtocolInfo(info); user.put(storage); user.setActive(protocolPath != null); diff --git a/bungee/src/main/java/com/viaversion/viaversion/bungee/listeners/ElytraPatch.java b/bungee/src/main/java/com/viaversion/viaversion/bungee/listeners/ElytraPatch.java index a8e85e0cc..5888affbd 100644 --- a/bungee/src/main/java/com/viaversion/viaversion/bungee/listeners/ElytraPatch.java +++ b/bungee/src/main/java/com/viaversion/viaversion/bungee/listeners/ElytraPatch.java @@ -47,7 +47,7 @@ public class ElytraPatch implements Listener { if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) { int entityId = user.get(EntityTracker1_9.class).getProvidedEntityId(); - PacketWrapper wrapper = new PacketWrapper(0x39, null, user); + PacketWrapper wrapper = PacketWrapper.create(0x39, null, user); wrapper.write(Type.VAR_INT, entityId); wrapper.write(Types1_9.METADATA_LIST, Collections.singletonList(new Metadata(0, MetaType1_9.Byte, (byte) 0))); diff --git a/bungee/src/main/java/com/viaversion/viaversion/bungee/providers/BungeeMovementTransmitter.java b/bungee/src/main/java/com/viaversion/viaversion/bungee/providers/BungeeMovementTransmitter.java index ebd39cac2..f7a4a1310 100644 --- a/bungee/src/main/java/com/viaversion/viaversion/bungee/providers/BungeeMovementTransmitter.java +++ b/bungee/src/main/java/com/viaversion/viaversion/bungee/providers/BungeeMovementTransmitter.java @@ -38,7 +38,7 @@ public class BungeeMovementTransmitter extends MovementTransmitterProvider { public void sendPlayer(UserConnection userConnection) { if (userConnection.getProtocolInfo().getState() == State.PLAY) { - PacketWrapper wrapper = new PacketWrapper(0x03, null, userConnection); + PacketWrapper wrapper = PacketWrapper.create(0x03, null, userConnection); wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround()); try { wrapper.sendToServer(Protocol1_9To1_8.class); diff --git a/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java b/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java index 0c3adec94..fa7fa4b53 100644 --- a/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/ViaManagerImpl.java @@ -17,26 +17,27 @@ */ package com.viaversion.viaversion; -import com.viaversion.viaversion.api.ViaManager; -import it.unimi.dsi.fastutil.ints.IntSortedSet; import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.ViaManager; +import com.viaversion.viaversion.api.connection.ConnectionManager; import com.viaversion.viaversion.api.platform.TaskId; -import com.viaversion.viaversion.api.connection.ViaConnectionManager; +import com.viaversion.viaversion.api.platform.UnsupportedSoftware; import com.viaversion.viaversion.api.platform.ViaInjector; import com.viaversion.viaversion.api.platform.ViaPlatform; import com.viaversion.viaversion.api.platform.ViaPlatformLoader; import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.protocol.ProtocolManager; -import com.viaversion.viaversion.protocol.ProtocolManagerImpl; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion; +import com.viaversion.viaversion.commands.ViaCommandHandler; +import com.viaversion.viaversion.connection.ConnectionManagerImpl; +import com.viaversion.viaversion.protocol.ProtocolManagerImpl; import com.viaversion.viaversion.protocol.ServerProtocolVersionRange; import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton; -import com.viaversion.viaversion.commands.ViaCommandHandler; import com.viaversion.viaversion.protocols.protocol1_13to1_12_2.TabCompleteThread; import com.viaversion.viaversion.protocols.protocol1_9to1_8.ViaIdleThread; import com.viaversion.viaversion.update.UpdateUtil; -import com.viaversion.viaversion.api.platform.UnsupportedSoftware; +import it.unimi.dsi.fastutil.ints.IntSortedSet; import java.util.ArrayList; import java.util.Arrays; @@ -46,7 +47,7 @@ import java.util.Set; public class ViaManagerImpl implements ViaManager { private final ProtocolManagerImpl protocolManager = new ProtocolManagerImpl(); - private final ViaConnectionManager connectionManager = new ViaConnectionManager(); + private final ConnectionManager connectionManager = new ConnectionManagerImpl(); private final ViaProviders providers = new ViaProviders(); private final ViaPlatform platform; private final ViaInjector injector; @@ -237,7 +238,7 @@ public class ViaManagerImpl implements ViaManager { } @Override - public ViaConnectionManager getConnectionManager() { + public ConnectionManager getConnectionManager() { return connectionManager; } diff --git a/common/src/main/java/com/viaversion/viaversion/boss/CommonBoss.java b/common/src/main/java/com/viaversion/viaversion/boss/CommonBoss.java index 142fd82ac..06e5806a1 100644 --- a/common/src/main/java/com/viaversion/viaversion/boss/CommonBoss.java +++ b/common/src/main/java/com/viaversion/viaversion/boss/CommonBoss.java @@ -226,7 +226,7 @@ public abstract class CommonBoss extends BossBar { private PacketWrapper getPacket(UpdateAction action, UserConnection connection) { try { - PacketWrapper wrapper = new PacketWrapper(0x0C, null, connection); // TODO don't use fixed packet ids for future support + PacketWrapper wrapper = PacketWrapper.create(0x0C, null, connection); // TODO don't use fixed packet ids for future support wrapper.write(Type.UUID, uuid); wrapper.write(Type.VAR_INT, action.getId()); switch (action) { diff --git a/api/src/main/java/com/viaversion/viaversion/api/connection/ViaConnectionManager.java b/common/src/main/java/com/viaversion/viaversion/connection/ConnectionManagerImpl.java similarity index 59% rename from api/src/main/java/com/viaversion/viaversion/api/connection/ViaConnectionManager.java rename to common/src/main/java/com/viaversion/viaversion/connection/ConnectionManagerImpl.java index 74feb3ad5..6e4182c7f 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/connection/ViaConnectionManager.java +++ b/common/src/main/java/com/viaversion/viaversion/connection/ConnectionManagerImpl.java @@ -20,9 +20,11 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.viaversion.viaversion.api.connection; +package com.viaversion.viaversion.connection; import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ConnectionManager; +import com.viaversion.viaversion.api.connection.UserConnection; import io.netty.channel.ChannelFutureListener; import org.checkerframework.checker.nullness.qual.Nullable; @@ -33,13 +35,11 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; -/** - * Handles injected UserConnections - */ -public class ViaConnectionManager { +public class ConnectionManagerImpl implements ConnectionManager { protected final Map clients = new ConcurrentHashMap<>(); protected final Set connections = Collections.newSetFromMap(new ConcurrentHashMap<>()); + @Override public void onLoginSuccess(UserConnection connection) { Objects.requireNonNull(connection, "connection is null!"); connections.add(connection); @@ -56,6 +56,7 @@ public class ViaConnectionManager { } } + @Override public void onDisconnect(UserConnection connection) { Objects.requireNonNull(connection, "connection is null!"); connections.remove(connection); @@ -66,74 +67,39 @@ public class ViaConnectionManager { } } - /** - * Frontend connections will have the UUID stored. Override this if your platform isn't always frontend. - * UUIDs can't be duplicate between frontend connections. - */ - public boolean isFrontEnd(UserConnection conn) { - return !conn.isClientSide(); + @Override + public boolean isFrontEnd(UserConnection connection) { + return !connection.isClientSide(); } - /** - * Returns a map containing the UUIDs and frontend UserConnections from players connected to this proxy server - * Returns empty list when there isn't a server - * When ViaVersion is reloaded, this method may not return some players. - * May not contain ProtocolSupport players. - */ + @Override public Map getConnectedClients() { return Collections.unmodifiableMap(clients); } - /** - * Returns the frontend UserConnection from the player connected to this proxy server - * Returns null when there isn't a server or connection was not found - * When ViaVersion is reloaded, this method may not return some players. - * May not return ProtocolSupport players. - *

- * Note that connections are removed as soon as their channel is closed, - * so avoid using this method during player quits for example. - */ + @Override public @Nullable UserConnection getConnectedClient(UUID clientIdentifier) { return clients.get(clientIdentifier); } - /** - * Returns the UUID from the frontend connection to this proxy server - * Returns null when there isn't a server or this connection isn't frontend or it doesn't have an id - * When ViaVersion is reloaded, this method may not return some players. - * May not return ProtocolSupport players. - *

- * Note that connections are removed as soon as their channel is closed, - * so avoid using this method during player quits for example. - */ - public @Nullable UUID getConnectedClientId(UserConnection conn) { - if (conn.getProtocolInfo() == null) return null; - UUID uuid = conn.getProtocolInfo().getUuid(); + @Override + public @Nullable UUID getConnectedClientId(UserConnection connection) { + if (connection.getProtocolInfo() == null) return null; + UUID uuid = connection.getProtocolInfo().getUuid(); UserConnection client = clients.get(uuid); - if (conn.equals(client)) { + if (connection.equals(client)) { // This is frontend return uuid; } return null; } - /** - * Returns all UserConnections which are registered - * May contain duplicated UUIDs on multiple ProtocolInfo. - * May contain frontend, backend and/or client-sided connections. - * When ViaVersion is reloaded, this method may not return some players. - * May not contain ProtocolSupport players. - */ + @Override public Set getConnections() { return Collections.unmodifiableSet(connections); } - /** - * Returns if Via injected into this player connection. - * - * @param playerId player uuid - * @return true if the player is handled by Via - */ + @Override public boolean isClientConnected(UUID playerId) { return clients.containsKey(playerId); } diff --git a/common/src/main/java/com/viaversion/viaversion/connection/ProtocolInfoImpl.java b/common/src/main/java/com/viaversion/viaversion/connection/ProtocolInfoImpl.java new file mode 100644 index 000000000..f2781ef00 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/connection/ProtocolInfoImpl.java @@ -0,0 +1,120 @@ +/* + * 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 com.viaversion.viaversion.connection; + +import com.viaversion.viaversion.api.connection.ProtocolInfo; +import com.viaversion.viaversion.api.connection.StoredObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.ProtocolPipeline; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; + +import java.util.UUID; + +public class ProtocolInfoImpl extends StoredObject implements ProtocolInfo { + private State state = State.HANDSHAKE; + private int protocolVersion = -1; + private int serverProtocolVersion = -1; + private String username; + private UUID uuid; + private ProtocolPipeline pipeline; + + public ProtocolInfoImpl(UserConnection user) { + super(user); + } + + @Override + public State getState() { + return state; + } + + @Override + public void setState(State state) { + this.state = state; + } + + @Override + public int getProtocolVersion() { + return protocolVersion; + } + + @Override + public void setProtocolVersion(int protocolVersion) { + // Map snapshot versions to the higher/orderer release version + ProtocolVersion protocol = ProtocolVersion.getProtocol(protocolVersion); + this.protocolVersion = protocol.getVersion(); + } + + @Override + public int getServerProtocolVersion() { + return serverProtocolVersion; + } + + @Override + public void setServerProtocolVersion(int serverProtocolVersion) { + ProtocolVersion protocol = ProtocolVersion.getProtocol(serverProtocolVersion); + this.serverProtocolVersion = protocol.getVersion(); + } + + @Override + public @MonotonicNonNull String getUsername() { + return username; + } + + @Override + public void setUsername(String username) { + this.username = username; + } + + @Override + public UUID getUuid() { + return uuid; + } + + @Override + public void setUuid(UUID uuid) { + this.uuid = uuid; + } + + @Override + public ProtocolPipeline getPipeline() { + return pipeline; + } + + @Override + public void setPipeline(ProtocolPipeline pipeline) { + this.pipeline = pipeline; + } + + @Override + public String toString() { + return "ProtocolInfo{" + + "state=" + state + + ", protocolVersion=" + protocolVersion + + ", serverProtocolVersion=" + serverProtocolVersion + + ", username='" + username + '\'' + + ", uuid=" + uuid + + '}'; + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java b/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java new file mode 100644 index 000000000..77f480f1f --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/connection/UserConnectionImpl.java @@ -0,0 +1,385 @@ +/* + * 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 com.viaversion.viaversion.connection; + +import com.google.common.base.Preconditions; +import com.google.common.cache.CacheBuilder; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ProtocolInfo; +import com.viaversion.viaversion.api.connection.StoredObject; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.packet.Direction; +import com.viaversion.viaversion.api.protocol.packet.PacketTracker; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.exception.CancelException; +import com.viaversion.viaversion.util.ChatColorUtil; +import com.viaversion.viaversion.util.PipelineUtil; +import io.netty.buffer.ByteBuf; +import io.netty.channel.Channel; +import io.netty.channel.ChannelFuture; +import io.netty.channel.ChannelHandlerContext; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; + +public class UserConnectionImpl implements UserConnection { + private static final AtomicLong IDS = new AtomicLong(); + private final long id = IDS.incrementAndGet(); + private final Map, StoredObject> storedObjects = new ConcurrentHashMap<>(); + private final PacketTracker packetTracker = new PacketTracker(this); + private final Set passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder() + .expireAfterWrite(10, TimeUnit.SECONDS) + .build().asMap()); + private final Channel channel; + private final boolean clientSide; + private ProtocolInfo protocolInfo; + private boolean active = true; + private boolean pendingDisconnect; + + /** + * Creates an UserConnection. When it's a client-side connection, some method behaviors are modified. + * + * @param channel netty channel. + * @param clientSide true if it's a client-side connection + */ + public UserConnectionImpl(@Nullable Channel channel, boolean clientSide) { + this.channel = channel; + this.clientSide = clientSide; + } + + /** + * @see #UserConnectionImpl(Channel, boolean) + */ + public UserConnectionImpl(@Nullable Channel channel) { + this(channel, false); + } + + @Override + public @Nullable T get(Class objectClass) { + return (T) storedObjects.get(objectClass); + } + + @Override + public boolean has(Class objectClass) { + return storedObjects.containsKey(objectClass); + } + + @Override + public void put(StoredObject object) { + storedObjects.put(object.getClass(), object); + } + + @Override + public void clearStoredObjects() { + storedObjects.clear(); + } + + @Override + public void sendRawPacket(final ByteBuf packet, boolean currentThread) { + Runnable act; + if (clientSide) { + // We'll just assume that Via decoder isn't wrapping the original decoder + act = () -> getChannel().pipeline() + .context(Via.getManager().getInjector().getDecoderName()).fireChannelRead(packet); + } else { + act = () -> channel.pipeline().context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet); + } + if (currentThread) { + act.run(); + } else { + try { + channel.eventLoop().submit(act); + } catch (Throwable e) { + packet.release(); // Couldn't schedule + e.printStackTrace(); + } + } + } + + @Override + public ChannelFuture sendRawPacketFuture(final ByteBuf packet) { + if (clientSide) { + return sendRawPacketFutureClientSide(packet); + } else { + return sendRawPacketFutureServerSide(packet); + } + } + + private ChannelFuture sendRawPacketFutureServerSide(final ByteBuf packet) { + return channel.pipeline().context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet); + } + + private ChannelFuture sendRawPacketFutureClientSide(final ByteBuf packet) { + // Assume that decoder isn't wrapping + getChannel().pipeline().context(Via.getManager().getInjector().getDecoderName()).fireChannelRead(packet); + return getChannel().newSucceededFuture(); + } + + @Override + public void sendRawPacket(ByteBuf packet) { + sendRawPacket(packet, false); + } + + @Override + public PacketTracker getPacketTracker() { + return packetTracker; + } + + @Override + public void disconnect(String reason) { + if (!channel.isOpen() || pendingDisconnect) return; + + pendingDisconnect = true; + Via.getPlatform().runSync(() -> { + if (!Via.getPlatform().disconnect(this, ChatColorUtil.translateAlternateColorCodes(reason))) { + channel.close(); // =) + } + }); + } + + @Override + public void sendRawPacketToServer(final ByteBuf packet, boolean currentThread) { + if (clientSide) { + sendRawPacketToServerClientSide(packet, currentThread); + } else { + sendRawPacketToServerServerSide(packet, currentThread); + } + } + + private void sendRawPacketToServerServerSide(final ByteBuf packet, boolean currentThread) { + final ByteBuf buf = packet.alloc().buffer(); + try { + // We'll use passing through because there are some encoder wrappers + ChannelHandlerContext context = PipelineUtil + .getPreviousContext(Via.getManager().getInjector().getDecoderName(), channel.pipeline()); + try { + Type.VAR_INT.writePrimitive(buf, PacketWrapper.PASSTHROUGH_ID); + Type.UUID.write(buf, generatePassthroughToken()); + } catch (Exception shouldNotHappen) { + throw new RuntimeException(shouldNotHappen); + } + buf.writeBytes(packet); + Runnable act = () -> { + if (context != null) { + context.fireChannelRead(buf); + } else { + channel.pipeline().fireChannelRead(buf); + } + }; + if (currentThread) { + act.run(); + } else { + try { + channel.eventLoop().submit(act); + } catch (Throwable t) { + // Couldn't schedule + buf.release(); + throw t; + } + } + } finally { + packet.release(); + } + } + + private void sendRawPacketToServerClientSide(final ByteBuf packet, boolean currentThread) { + Runnable act = () -> getChannel().pipeline() + .context(Via.getManager().getInjector().getEncoderName()).writeAndFlush(packet); + if (currentThread) { + act.run(); + } else { + try { + getChannel().eventLoop().submit(act); + } catch (Throwable e) { + e.printStackTrace(); + packet.release(); // Couldn't schedule + } + } + } + + @Override + public void sendRawPacketToServer(ByteBuf packet) { + sendRawPacketToServer(packet, false); + } + + @Override + public boolean checkIncomingPacket() { + if (clientSide) { + return checkClientbound(); + } else { + return checkServerbound(); + } + } + + private boolean checkClientbound() { + packetTracker.incrementSent(); + return true; + } + + private boolean checkServerbound() { + // Ignore if pending disconnect + if (pendingDisconnect) return false; + // Increment received + Check PPS + return !packetTracker.incrementReceived() || !packetTracker.exceedsMaxPPS(); + } + + @Override + public boolean checkOutgoingPacket() { + if (clientSide) { + return checkServerbound(); + } else { + return checkClientbound(); + } + } + + @Override + public boolean shouldTransformPacket() { + return active; + } + + @Override + public void transformOutgoing(ByteBuf buf, Function cancelSupplier) throws Exception { + if (!buf.isReadable()) return; + transform(buf, clientSide ? Direction.INCOMING : Direction.OUTGOING, cancelSupplier); + } + + @Override + public void transformIncoming(ByteBuf buf, Function cancelSupplier) throws Exception { + if (!buf.isReadable()) return; + transform(buf, clientSide ? Direction.OUTGOING : Direction.INCOMING, cancelSupplier); + } + + private void transform(ByteBuf buf, Direction direction, Function cancelSupplier) throws Exception { + int id = Type.VAR_INT.readPrimitive(buf); + if (id == PacketWrapper.PASSTHROUGH_ID) { + if (!passthroughTokens.remove(Type.UUID.read(buf))) { + throw new IllegalArgumentException("Invalid token"); + } + return; + } + + PacketWrapper wrapper = PacketWrapper.create(id, buf, this); + try { + protocolInfo.getPipeline().transform(direction, protocolInfo.getState(), wrapper); + } catch (CancelException ex) { + throw cancelSupplier.apply(ex); + } + + ByteBuf transformed = buf.alloc().buffer(); + try { + wrapper.writeToBuffer(transformed); + buf.clear().writeBytes(transformed); + } finally { + transformed.release(); + } + } + + @Override + public long getId() { + return id; + } + + @Override + public @Nullable Channel getChannel() { + return channel; + } + + @Override + public @Nullable ProtocolInfo getProtocolInfo() { + return protocolInfo; + } + + @Override + public void setProtocolInfo(@Nullable ProtocolInfo protocolInfo) { + Preconditions.checkArgument(protocolInfo instanceof StoredObject, "ProtocolInfo has to extend StoredObject!"); + this.protocolInfo = protocolInfo; + if (protocolInfo != null) { + storedObjects.put(ProtocolInfo.class, (StoredObject) protocolInfo); + } else { + storedObjects.remove(ProtocolInfo.class); + } + } + + @Override + public Map, StoredObject> getStoredObjects() { + return storedObjects; + } + + @Override + public boolean isActive() { + return active; + } + + @Override + public void setActive(boolean active) { + this.active = active; + } + + @Override + public boolean isPendingDisconnect() { + return pendingDisconnect; + } + + @Override + public void setPendingDisconnect(boolean pendingDisconnect) { + this.pendingDisconnect = pendingDisconnect; + } + + @Override + public boolean isClientSide() { + return clientSide; + } + + @Override + public boolean shouldApplyBlockProtocol() { + return !clientSide; // Don't apply protocol blocking on client-side + } + + @Override + public UUID generatePassthroughToken() { + UUID token = UUID.randomUUID(); + passthroughTokens.add(token); + return token; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + UserConnectionImpl that = (UserConnectionImpl) o; + return id == that.id; + } + + @Override + public int hashCode() { + return Long.hashCode(id); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java index 127a25b8a..3667df8af 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolManagerImpl.java @@ -21,18 +21,17 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Range; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.viaversion.viaversion.api.protocol.Protocol; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.data.MappingDataLoader; import com.viaversion.viaversion.api.protocol.ProtocolManager; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPathKey; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.base.Protocol; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import org.checkerframework.checker.nullness.qual.Nullable; -import com.viaversion.viaversion.util.Pair; -import com.viaversion.viaversion.api.Via; -import com.viaversion.viaversion.api.data.MappingDataLoader; +import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl; import com.viaversion.viaversion.protocols.base.BaseProtocol; import com.viaversion.viaversion.protocols.base.BaseProtocol1_16; import com.viaversion.viaversion.protocols.base.BaseProtocol1_7; @@ -64,6 +63,11 @@ import com.viaversion.viaversion.protocols.protocol1_9_1to1_9.Protocol1_9_1To1_9 import com.viaversion.viaversion.protocols.protocol1_9_3to1_9_1_2.Protocol1_9_3To1_9_1_2; import com.viaversion.viaversion.protocols.protocol1_9to1_8.Protocol1_9To1_8; import com.viaversion.viaversion.protocols.protocol1_9to1_9_1.Protocol1_9To1_9_1; +import com.viaversion.viaversion.util.Pair; +import io.netty.buffer.ByteBuf; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; import java.util.Arrays; @@ -288,8 +292,8 @@ public class ProtocolManagerImpl implements ProtocolManager { } @Override - public @Nullable Protocol getProtocol(Class protocolClass) { - return protocols.get(protocolClass); + public @Nullable T getProtocol(Class protocolClass) { + return (T) protocols.get(protocolClass); } @Override @@ -414,6 +418,11 @@ public class ProtocolManagerImpl implements ProtocolManager { } } + @Override + public PacketWrapper createPacketWrapper(int packetId, ByteBuf buf, UserConnection connection) { + return new PacketWrapperImpl(packetId, buf, connection); + } + /** * Called when the server is enabled, to register any non-registered listeners. */ diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPathEntryImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPathEntryImpl.java index 3cac8ac06..b512906c7 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPathEntryImpl.java +++ b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPathEntryImpl.java @@ -17,8 +17,8 @@ */ package com.viaversion.viaversion.protocol; -import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; +import com.viaversion.viaversion.api.protocol.base.Protocol; public class ProtocolPathEntryImpl implements ProtocolPathEntry { private final int outputProtocolVersion; diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java new file mode 100644 index 000000000..4baa93765 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocol/ProtocolPipelineImpl.java @@ -0,0 +1,193 @@ +/* + * 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 com.viaversion.viaversion.protocol; + +import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ProtocolInfo; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.platform.ViaPlatform; +import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol; +import com.viaversion.viaversion.api.protocol.ProtocolPipeline; +import com.viaversion.viaversion.api.protocol.base.Protocol; +import com.viaversion.viaversion.api.protocol.packet.Direction; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.connection.ProtocolInfoImpl; +import org.checkerframework.checker.nullness.qual.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.logging.Level; + +public class ProtocolPipelineImpl extends AbstractSimpleProtocol implements ProtocolPipeline { + /** + * Protocol list ordered from client to server transforation with the base protocols at the end. + */ + private List protocolList; + private UserConnection userConnection; + + public ProtocolPipelineImpl(UserConnection userConnection) { + init(userConnection); + } + + @Override + protected void registerPackets() { + protocolList = new CopyOnWriteArrayList<>(); + // This is a pipeline so we register basic pipes + protocolList.add(Via.getManager().getProtocolManager().getBaseProtocol()); + } + + @Override + public void init(UserConnection userConnection) { + this.userConnection = userConnection; + + ProtocolInfo protocolInfo = new ProtocolInfoImpl(userConnection); + protocolInfo.setPipeline(this); + + userConnection.setProtocolInfo(protocolInfo); + + /* Init through all our pipes */ + for (Protocol protocol : protocolList) { + protocol.init(userConnection); + } + } + + @Override + public void add(Protocol protocol) { + Preconditions.checkNotNull(protocolList, "Tried to add protocol too early"); + + protocolList.add(protocol); + protocol.init(userConnection); + + if (!protocol.isBaseProtocol()) { + moveBaseProtocolsToTail(); + } + } + + @Override + public void add(List protocols) { + Preconditions.checkNotNull(protocolList, "Tried to add protocol too early"); + + protocolList.addAll(protocols); + for (Protocol protocol : protocols) { + protocol.init(userConnection); + } + + moveBaseProtocolsToTail(); + } + + private void moveBaseProtocolsToTail() { + // Move base Protocols to the end, so the login packets can be modified by other protocols + List baseProtocols = null; + for (Protocol protocol : protocolList) { + if (protocol.isBaseProtocol()) { + if (baseProtocols == null) { + baseProtocols = new ArrayList<>(); + } + + baseProtocols.add(protocol); + } + } + + if (baseProtocols != null) { + protocolList.removeAll(baseProtocols); + protocolList.addAll(baseProtocols); + } + } + + @Override + public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception { + int originalID = packetWrapper.getId(); + + // Apply protocols + packetWrapper.apply(direction, state, 0, protocolList, direction == Direction.OUTGOING); + super.transform(direction, state, packetWrapper); + + if (Via.getManager().isDebug()) { + logPacket(direction, state, packetWrapper, originalID); + } + } + + private void logPacket(Direction direction, State state, PacketWrapper packetWrapper, int originalID) { + // Debug packet + int clientProtocol = userConnection.getProtocolInfo().getProtocolVersion(); + ViaPlatform platform = Via.getPlatform(); + + String actualUsername = packetWrapper.user().getProtocolInfo().getUsername(); + String username = actualUsername != null ? actualUsername + " " : ""; + + platform.getLogger().log(Level.INFO, "{0}{1} {2}: {3} (0x{4}) -> {5} (0x{6}) [{7}] {8}", + new Object[]{ + username, + direction, + state, + originalID, + Integer.toHexString(originalID), + packetWrapper.getId(), + Integer.toHexString(packetWrapper.getId()), + Integer.toString(clientProtocol), + packetWrapper + }); + } + + @Override + public boolean contains(Class pipeClass) { + for (Protocol protocol : protocolList) { + if (protocol.getClass().equals(pipeClass)) return true; + } + return false; + } + + @Override + public @Nullable

P getProtocol(Class

pipeClass) { + for (Protocol protocol : protocolList) { + if (protocol.getClass() == pipeClass) return (P) protocol; + } + return null; + } + + @Override + public boolean filter(Object o, List list) throws Exception { + for (Protocol protocol : protocolList) { + if (protocol.isFiltered(o.getClass())) { + protocol.filterPacket(userConnection, o, list); + return true; + } + } + + return false; + } + + @Override + public List pipes() { + return protocolList; + } + + @Override + public void cleanPipes() { + pipes().clear(); + registerPackets(); + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java b/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java new file mode 100644 index 000000000..6502bd2d5 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/protocol/packet/PacketWrapperImpl.java @@ -0,0 +1,443 @@ +/* + * 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 com.viaversion.viaversion.protocol.packet; + +import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.UserConnection; +import com.viaversion.viaversion.api.protocol.base.Protocol; +import com.viaversion.viaversion.api.protocol.packet.Direction; +import com.viaversion.viaversion.api.protocol.packet.PacketType; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; +import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.remapper.ValueCreator; +import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.type.TypeConverter; +import com.viaversion.viaversion.exception.CancelException; +import com.viaversion.viaversion.exception.InformativeException; +import com.viaversion.viaversion.util.Pair; +import com.viaversion.viaversion.util.PipelineUtil; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelFuture; + +import java.io.IOException; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; +import java.util.NoSuchElementException; + +public class PacketWrapperImpl implements PacketWrapper { + private static final Protocol[] PROTOCOL_ARRAY = new Protocol[0]; + + private final ByteBuf inputBuffer; + private final UserConnection userConnection; + private boolean send = true; + private int id = -1; + private final Deque> readableObjects = new ArrayDeque<>(); + private final List> packetValues = new ArrayList<>(); + + public PacketWrapperImpl(int packetID, ByteBuf inputBuffer, UserConnection userConnection) { + this.id = packetID; + this.inputBuffer = inputBuffer; + this.userConnection = userConnection; + } + + @Override + public T get(Type type, int index) throws Exception { + int currentIndex = 0; + for (Pair packetValue : packetValues) { + if (packetValue.getKey() == type) { // Ref check + if (currentIndex == index) { + return (T) packetValue.getValue(); + } + 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()).set("Data", packetValues); + } + + @Override + public boolean is(Type type, int index) { + int currentIndex = 0; + for (Pair packetValue : packetValues) { + if (packetValue.getKey() == type) { // Ref check + if (currentIndex == index) { + return true; + } + currentIndex++; + } + } + return false; + } + + @Override + public boolean isReadable(Type type, int index) { + int currentIndex = 0; + for (Pair packetValue : readableObjects) { + if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check + if (currentIndex == index) { + return true; + } + currentIndex++; + } + } + return false; + } + + + @Override + public void set(Type type, int index, T value) throws Exception { + int currentIndex = 0; + for (Pair packetValue : packetValues) { + if (packetValue.getKey() == type) { // Ref check + if (currentIndex == index) { + packetValue.setValue(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()); + } + + @Override + public T read(Type type) throws Exception { + if (type == Type.NOTHING) return null; + if (readableObjects.isEmpty()) { + Preconditions.checkNotNull(inputBuffer, "This packet does not have an input buffer."); + // We could in the future log input read values, but honestly for things like bulk maps, mem waste D: + try { + return type.read(inputBuffer); + } catch (Exception e) { + throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues); + } + } else { + Pair 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); + } + } + } + } + + @Override + public void write(Type 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, value)); + } + + @Override + public T passthrough(Type type) throws Exception { + T value = read(type); + write(type, value); + return value; + } + + @Override + public void passthroughAll() throws Exception { + // Copy previous objects + packetValues.addAll(readableObjects); + readableObjects.clear(); + // If the buffer has readable bytes, copy them. + if (inputBuffer.isReadable()) { + passthrough(Type.REMAINING_BYTES); + } + } + + @Override + public void writeToBuffer(ByteBuf buffer) throws Exception { + if (id != -1) { + Type.VAR_INT.writePrimitive(buffer, id); + } + if (!readableObjects.isEmpty()) { + packetValues.addAll(readableObjects); + readableObjects.clear(); + } + + int index = 0; + for (Pair 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); + } catch (Exception e) { + throw new InformativeException(e).set("Index", index).set("Type", packetValue.getKey().getTypeName()).set("Packet ID", getId()).set("Data", packetValues); + } + index++; + } + writeRemaining(buffer); + } + + @Override + public void clearInputBuffer() { + if (inputBuffer != null) { + inputBuffer.clear(); + } + readableObjects.clear(); // :( + } + + @Override + public void clearPacket() { + clearInputBuffer(); + packetValues.clear(); + } + + private void writeRemaining(ByteBuf output) { + if (inputBuffer != null) { + output.writeBytes(inputBuffer); + } + } + + @Override + public void send(Class packetProtocol, boolean skipCurrentPipeline) throws Exception { + send(packetProtocol, skipCurrentPipeline, false); + } + + @Override + public void send(Class packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception { + if (!isCancelled()) { + try { + ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline, Direction.OUTGOING); + user().sendRawPacket(output, currentThread); + } catch (Exception e) { + if (!PipelineUtil.containsCause(e, CancelException.class)) { + throw e; + } + } + } + } + + /** + * Let the packet go through the protocol pipes and write it to ByteBuf + * + * @param packetProtocol The protocol version of the packet. + * @param skipCurrentPipeline Skip the current pipeline + * @return Packet buffer + * @throws Exception if it fails to write + */ + private ByteBuf constructPacket(Class packetProtocol, boolean skipCurrentPipeline, Direction direction) throws Exception { + // Apply current pipeline - for outgoing protocol, the collection will be reversed in the apply method + Protocol[] protocols = user().getProtocolInfo().getPipeline().pipes().toArray(PROTOCOL_ARRAY); + boolean reverse = direction == Direction.OUTGOING; + int index = -1; + for (int i = 0; i < protocols.length; i++) { + if (protocols[i].getClass() == packetProtocol) { + index = i; + break; + } + } + + if (index == -1) { + // The given protocol is not in the pipeline + throw new NoSuchElementException(packetProtocol.getCanonicalName()); + } + + if (skipCurrentPipeline) { + index = reverse ? index - 1 : index + 1; + } + + // Reset reader before we start + resetReader(); + + // Apply other protocols + apply(direction, user().getProtocolInfo().getState(), index, protocols, reverse); + ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + try { + writeToBuffer(output); + return output.retain(); + } finally { + output.release(); + } + } + + @Override + public ChannelFuture sendFuture(Class packetProtocol) throws Exception { + if (!isCancelled()) { + ByteBuf output = constructPacket(packetProtocol, true, Direction.OUTGOING); + return user().sendRawPacketFuture(output); + } + return user().getChannel().newFailedFuture(new Exception("Cancelled packet")); + } + + @Override + @Deprecated + public void send() throws Exception { + if (!isCancelled()) { + // Send + ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + try { + writeToBuffer(output); + user().sendRawPacket(output.retain()); + } finally { + output.release(); + } + } + } + + @Override + public PacketWrapperImpl create(PacketType packetType) { + return new PacketWrapperImpl(packetType.ordinal(), null, user()); + } + + @Override + public PacketWrapperImpl create(int packetID) { + return new PacketWrapperImpl(packetID, null, user()); + } + + @Override + public PacketWrapperImpl create(int packetID, ValueCreator init) throws Exception { + PacketWrapperImpl wrapper = create(packetID); + init.write(wrapper); + return wrapper; + } + + @Override + public PacketWrapperImpl apply(Direction direction, State state, int index, List pipeline, boolean reverse) throws Exception { + Protocol[] array = pipeline.toArray(PROTOCOL_ARRAY); + return apply(direction, state, reverse ? array.length - 1 : index, array, reverse); // Copy to prevent from removal + } + + @Override + public PacketWrapperImpl apply(Direction direction, State state, int index, List pipeline) throws Exception { + return apply(direction, state, index, pipeline.toArray(PROTOCOL_ARRAY), false); + } + + private PacketWrapperImpl apply(Direction direction, State state, int index, Protocol[] pipeline, boolean reverse) throws Exception { + // Reset the reader after every transformation for the packetWrapper, so it can be recycled across packets + if (reverse) { + for (int i = index; i >= 0; i--) { + pipeline[i].transform(direction, state, this); + resetReader(); + } + } else { + for (int i = index; i < pipeline.length; i++) { + pipeline[i].transform(direction, state, this); + resetReader(); + } + } + return this; + } + + @Override + public void cancel() { + this.send = false; + } + + @Override + public boolean isCancelled() { + return !this.send; + } + + @Override + public UserConnection user() { + return this.userConnection; + } + + @Override + public void resetReader() { + // Move all packet values to the readable for next packet. + for (int i = packetValues.size() - 1; i >= 0; i--) { + this.readableObjects.addFirst(this.packetValues.get(i)); + } + this.packetValues.clear(); + } + + @Override + @Deprecated + public void sendToServer() throws Exception { + if (!isCancelled()) { + ByteBuf output = inputBuffer == null ? user().getChannel().alloc().buffer() : inputBuffer.alloc().buffer(); + try { + writeToBuffer(output); + + user().sendRawPacketToServer(output.retain(), true); + } finally { + output.release(); + } + } + } + + @Override + public void sendToServer(Class packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception { + if (!isCancelled()) { + try { + ByteBuf output = constructPacket(packetProtocol, skipCurrentPipeline, Direction.INCOMING); + user().sendRawPacketToServer(output, currentThread); + } catch (Exception e) { + if (!PipelineUtil.containsCause(e, CancelException.class)) { + throw e; + } + } + } + } + + @Override + public int getId() { + return id; + } + + @Override + public void setId(int id) { + this.id = id; + } + + @Override + public String toString() { + return "PacketWrapper{" + + "packetValues=" + packetValues + + ", readableObjects=" + readableObjects + + ", id=" + id + + '}'; + } +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java b/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java index 4a6cb79bb..2b10808e7 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol.java @@ -17,26 +17,26 @@ */ package com.viaversion.viaversion.protocols.base; -import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.Via; +import com.viaversion.viaversion.api.connection.ProtocolInfo; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.platform.providers.ViaProviders; -import com.viaversion.viaversion.api.protocol.Protocol; -import com.viaversion.viaversion.api.connection.ProtocolInfo; +import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPipeline; -import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; -import com.viaversion.viaversion.api.protocol.SimpleProtocol; -import com.viaversion.viaversion.api.protocol.version.VersionProvider; -import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; -import com.viaversion.viaversion.api.type.Type; +import com.viaversion.viaversion.api.protocol.base.Protocol; import com.viaversion.viaversion.api.protocol.packet.Direction; +import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; import com.viaversion.viaversion.api.protocol.packet.State; +import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; +import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; +import com.viaversion.viaversion.api.protocol.version.VersionProvider; +import com.viaversion.viaversion.api.type.Type; import java.util.ArrayList; import java.util.List; -public class BaseProtocol extends SimpleProtocol { +public class BaseProtocol extends AbstractSimpleProtocol { @Override protected void registerPackets() { diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol1_7.java b/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol1_7.java index a97ee7d91..6da96a62f 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol1_7.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/base/BaseProtocol1_7.java @@ -30,7 +30,7 @@ import com.viaversion.viaversion.protocol.ProtocolManagerImpl; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton; -import com.viaversion.viaversion.api.protocol.SimpleProtocol; +import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol; import com.viaversion.viaversion.api.protocol.remapper.PacketHandler; import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; import com.viaversion.viaversion.api.type.Type; @@ -43,7 +43,7 @@ import java.util.List; import java.util.UUID; import java.util.logging.Level; -public class BaseProtocol1_7 extends SimpleProtocol { +public class BaseProtocol1_7 extends AbstractSimpleProtocol { @Override protected void registerPackets() { @@ -185,7 +185,7 @@ public class BaseProtocol1_7 extends SimpleProtocol { if (!wrapper.user().getChannel().isOpen()) return; if (!wrapper.user().shouldApplyBlockProtocol()) return; - PacketWrapper disconnectPacket = new PacketWrapper(0x00, null, wrapper.user()); // Disconnect Packet + PacketWrapper disconnectPacket = PacketWrapper.create(0x00, null, wrapper.user()); // Disconnect Packet Protocol1_9To1_8.FIX_JSON.write(disconnectPacket, ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg())); wrapper.cancel(); // cancel current diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/metadata/MetadataRewriter1_11To1_10.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/metadata/MetadataRewriter1_11To1_10.java index a1714f239..90f107136 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/metadata/MetadataRewriter1_11To1_10.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_11to1_10/metadata/MetadataRewriter1_11To1_10.java @@ -129,7 +129,7 @@ public class MetadataRewriter1_11To1_10 extends MetadataRewriter { tracker.addHologram(entityId); try { // Send movement - PacketWrapper wrapper = new PacketWrapper(0x25, null, connection); + PacketWrapper wrapper = PacketWrapper.create(0x25, null, connection); wrapper.write(Type.VAR_INT, entityId); wrapper.write(Type.SHORT, (short) 0); wrapper.write(Type.SHORT, (short) (128D * (-Via.getConfig().getHologramYOffset() * 32D))); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java index 87c198bfc..0d51c90c4 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/blockconnections/ConnectionData.java @@ -62,7 +62,7 @@ public class ConnectionData { if (handler == null) continue; int newBlockState = handler.connect(user, pos, blockState); - PacketWrapper blockUpdatePacket = new PacketWrapper(0x0B, null, user); + PacketWrapper blockUpdatePacket = PacketWrapper.create(0x0B, null, user); blockUpdatePacket.write(Type.POSITION, pos); blockUpdatePacket.write(Type.VAR_INT, newBlockState); try { @@ -135,7 +135,7 @@ public class ConnectionData { } if (!updates.isEmpty()) { - PacketWrapper wrapper = new PacketWrapper(0x0F, null, user); + PacketWrapper wrapper = PacketWrapper.create(0x0F, null, user); wrapper.write(Type.INT, chunkX + chunkDeltaX); wrapper.write(Type.INT, chunkZ + chunkDeltaZ); wrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, updates.toArray(EMPTY_RECORDS)); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/providers/BlockEntityProvider.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/providers/BlockEntityProvider.java index ec4813a5b..b640a9e6e 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/providers/BlockEntityProvider.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/providers/BlockEntityProvider.java @@ -81,7 +81,7 @@ public class BlockEntityProvider implements Provider { } private void sendBlockChange(UserConnection user, Position position, int blockId) throws Exception { - PacketWrapper wrapper = new PacketWrapper(0x0B, null, user); + PacketWrapper wrapper = PacketWrapper.create(0x0B, null, user); wrapper.write(Type.POSITION, position); wrapper.write(Type.VAR_INT, blockId); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/TabCompleteTracker.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/TabCompleteTracker.java index ddf8ab631..d49840b14 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/TabCompleteTracker.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_13to1_12_2/storage/TabCompleteTracker.java @@ -35,7 +35,7 @@ public class TabCompleteTracker extends StoredObject { public void sendPacketToServer() { if (lastTabComplete == null || timeToSend > System.currentTimeMillis()) return; - PacketWrapper wrapper = new PacketWrapper(0x01, null, getUser()); + PacketWrapper wrapper = PacketWrapper.create(0x01, null, getUser()); wrapper.write(Type.STRING, lastTabComplete); wrapper.write(Type.BOOLEAN, false); wrapper.write(Type.OPTIONAL_POSITION, null); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/metadata/MetadataRewriter1_14To1_13_2.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/metadata/MetadataRewriter1_14To1_13_2.java index e9da60e95..f489562ab 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/metadata/MetadataRewriter1_14To1_13_2.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/metadata/MetadataRewriter1_14To1_13_2.java @@ -130,7 +130,7 @@ public class MetadataRewriter1_14To1_13_2 extends MetadataRewriter { armorItem = new Item(protocol.getMappingData().getNewItemId(729), (byte) 1, (short) 0, null); } - PacketWrapper equipmentPacket = new PacketWrapper(0x46, null, connection); + PacketWrapper equipmentPacket = PacketWrapper.create(0x46, null, connection); equipmentPacket.write(Type.VAR_INT, entityId); equipmentPacket.write(Type.VAR_INT, 4); equipmentPacket.write(Type.FLAT_VAR_INT_ITEM, armorItem); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java index 7da121c79..2af88263d 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_14to1_13_2/storage/EntityTracker1_14.java @@ -94,7 +94,7 @@ public class EntityTracker1_14 extends EntityTracker { public void onExternalJoinGame(int playerEntityId) { super.onExternalJoinGame(playerEntityId); - PacketWrapper setViewDistance = new PacketWrapper(0x41, null, getUser()); + PacketWrapper setViewDistance = PacketWrapper.create(0x41, null, getUser()); setViewDistance.write(Type.VAR_INT, WorldPackets.SERVERSIDE_VIEW_DISTANCE); try { setViewDistance.send(Protocol1_14To1_13_2.class, true, true); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9_1_2to1_9_3_4/chunks/BlockEntity.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9_1_2to1_9_3_4/chunks/BlockEntity.java index f4fa57e03..0cbda0dd1 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9_1_2to1_9_3_4/chunks/BlockEntity.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9_1_2to1_9_3_4/chunks/BlockEntity.java @@ -75,7 +75,7 @@ public class BlockEntity { } private static void updateBlockEntity(Position pos, short id, CompoundTag tag, UserConnection connection) throws Exception { - PacketWrapper wrapper = new PacketWrapper(0x09, null, connection); + PacketWrapper wrapper = PacketWrapper.create(0x09, null, connection); wrapper.write(Type.POSITION, pos); wrapper.write(Type.UNSIGNED_BYTE, id); wrapper.write(Type.NBT, tag); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/Protocol1_9To1_8.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/Protocol1_9To1_8.java index 75ece53fa..0224986e9 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/Protocol1_9To1_8.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/Protocol1_9To1_8.java @@ -154,7 +154,7 @@ public class Protocol1_9To1_8 extends Protocol tag = provider.get(wrapper.user(), pos); // Send the Update Block Entity packet if present if (tag.isPresent()) { - PacketWrapper updateBlockEntity = new PacketWrapper(0x09, null, wrapper.user()); + PacketWrapper updateBlockEntity = PacketWrapper.create(0x09, null, wrapper.user()); updateBlockEntity.write(Type.POSITION, pos); updateBlockEntity.write(Type.UNSIGNED_BYTE, (short) 2); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java index 7b4f3f87f..838d08f4b 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/BulkChunkTranslatorProvider.java @@ -55,7 +55,7 @@ public class BulkChunkTranslatorProvider implements Provider { meta.setData(wrapper.read(customByteType)); // Construct chunk packet - PacketWrapper chunkPacket = new PacketWrapper(0x21, null, wrapper.user()); + PacketWrapper chunkPacket = PacketWrapper.create(0x21, null, wrapper.user()); chunkPacket.write(Type.INT, meta.getX()); chunkPacket.write(Type.INT, meta.getZ()); chunkPacket.write(Type.BOOLEAN, true); // Always ground-up diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/CommandBlockProvider.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/CommandBlockProvider.java index 563fcbd65..00e2e466e 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/CommandBlockProvider.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/providers/CommandBlockProvider.java @@ -57,7 +57,7 @@ public class CommandBlockProvider implements Provider { public void sendPermission(UserConnection user) throws Exception { if (!isEnabled()) return; - PacketWrapper wrapper = new PacketWrapper(0x1B, null, user); // Entity status + PacketWrapper wrapper = PacketWrapper.create(0x1B, null, user); // Entity status wrapper.write(Type.INT, user.get(EntityTracker1_9.class).getProvidedEntityId()); // Entity ID wrapper.write(Type.BYTE, (byte) 26); // Hardcoded op permission level diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java index fb4e4d683..63a433386 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_9to1_8/storage/EntityTracker1_9.java @@ -88,7 +88,7 @@ public class EntityTracker1_9 extends EntityTracker { } public void setSecondHand(int entityID, Item item) { - PacketWrapper wrapper = new PacketWrapper(0x3C, null, getUser()); + PacketWrapper wrapper = PacketWrapper.create(0x3C, null, getUser()); wrapper.write(Type.VAR_INT, entityID); wrapper.write(Type.VAR_INT, 1); // slot wrapper.write(Type.ITEM, this.itemInSecondHand = item); @@ -232,7 +232,7 @@ public class EntityTracker1_9 extends EntityTracker { knownHolograms.add(entityId); try { // Send movement - PacketWrapper wrapper = new PacketWrapper(0x25, null, getUser()); + PacketWrapper wrapper = PacketWrapper.create(0x25, null, getUser()); wrapper.write(Type.VAR_INT, entityId); wrapper.write(Type.SHORT, (short) 0); wrapper.write(Type.SHORT, (short) (128D * (Via.getConfig().getHologramYOffset() * 32D))); @@ -294,7 +294,7 @@ public class EntityTracker1_9 extends EntityTracker { } public void sendTeamPacket(boolean add, boolean now) { - PacketWrapper wrapper = new PacketWrapper(0x41, null, getUser()); + PacketWrapper wrapper = PacketWrapper.create(0x41, null, getUser()); wrapper.write(Type.STRING, "viaversion"); // Use viaversion as name if (add) { // add @@ -334,7 +334,7 @@ public class EntityTracker1_9 extends EntityTracker { public void sendMetadataBuffer(int entityId) { List metadataList = metadataBuffer.get(entityId); if (metadataList != null) { - PacketWrapper wrapper = new PacketWrapper(0x39, null, getUser()); + PacketWrapper wrapper = PacketWrapper.create(0x39, null, getUser()); wrapper.write(Type.VAR_INT, entityId); wrapper.write(Types1_9.METADATA_LIST, metadataList); getUser().getProtocolInfo().getPipeline().getProtocol(Protocol1_9To1_8.class).get(MetadataRewriter1_9To1_8.class) diff --git a/sponge-legacy/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge4/Sponge4ArmorListener.java b/sponge-legacy/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge4/Sponge4ArmorListener.java index abf312989..a89745ab9 100644 --- a/sponge-legacy/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge4/Sponge4ArmorListener.java +++ b/sponge-legacy/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge4/Sponge4ArmorListener.java @@ -60,7 +60,7 @@ public class Sponge4ArmorListener extends ViaListener { armor += calculate(player.getLeggings()); armor += calculate(player.getBoots()); - PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player.getUniqueId())); + PacketWrapper wrapper = PacketWrapper.create(0x4B, null, getUserConnection(player.getUniqueId())); try { wrapper.write(Type.VAR_INT, getEntityId(player)); // Player ID wrapper.write(Type.INT, 1); // only 1 property diff --git a/sponge/src/main/java/com/viaversion/viaversion/sponge/handlers/SpongeChannelInitializer.java b/sponge/src/main/java/com/viaversion/viaversion/sponge/handlers/SpongeChannelInitializer.java index ce16636e9..fdbdf5c96 100644 --- a/sponge/src/main/java/com/viaversion/viaversion/sponge/handlers/SpongeChannelInitializer.java +++ b/sponge/src/main/java/com/viaversion/viaversion/sponge/handlers/SpongeChannelInitializer.java @@ -17,6 +17,8 @@ */ package com.viaversion.viaversion.sponge.handlers; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import com.viaversion.viaversion.connection.UserConnectionImpl; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import io.netty.channel.socket.SocketChannel; @@ -24,7 +26,6 @@ import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.MessageToByteEncoder; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.ProtocolPipeline; import java.lang.reflect.Method; @@ -49,9 +50,9 @@ public class SpongeChannelInitializer extends ChannelInitializer { // Ensure ViaVersion is loaded if (Via.getAPI().getServerVersion().isKnown() && channel instanceof SocketChannel) { // channel can be LocalChannel on internal server - UserConnection info = new UserConnection((SocketChannel) channel); + UserConnection info = new UserConnectionImpl((SocketChannel) channel); // init protocol - new ProtocolPipeline(info); + new ProtocolPipelineImpl(info); // Add originals this.method.invoke(this.original, channel); // Add our transformers diff --git a/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/DeathListener.java b/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/DeathListener.java index 8fa1e9d14..4dd6f4617 100644 --- a/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/DeathListener.java +++ b/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/DeathListener.java @@ -64,7 +64,7 @@ public class DeathListener extends ViaSpongeListener { Via.getPlatform().runSync(new Runnable() { @Override public void run() { - PacketWrapper wrapper = new PacketWrapper(0x2C, null, getUserConnection(p.getUniqueId())); + PacketWrapper wrapper = PacketWrapper.create(0x2C, null, getUserConnection(p.getUniqueId())); try { int entityId = getEntityId(p); wrapper.write(Type.VAR_INT, 2); // Event - Entity dead diff --git a/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge5/Sponge5ArmorListener.java b/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge5/Sponge5ArmorListener.java index 68713e382..fc5da12ea 100644 --- a/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge5/Sponge5ArmorListener.java +++ b/sponge/src/main/java/com/viaversion/viaversion/sponge/listeners/protocol1_9to1_8/sponge5/Sponge5ArmorListener.java @@ -58,7 +58,7 @@ public class Sponge5ArmorListener extends ViaSpongeListener { armor += calculate(player.getLeggings()); armor += calculate(player.getBoots()); - PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player.getUniqueId())); + PacketWrapper wrapper = PacketWrapper.create(0x4B, null, getUserConnection(player.getUniqueId())); try { wrapper.write(Type.VAR_INT, getEntityId(player)); // Player ID wrapper.write(Type.INT, 1); // only 1 property diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java index 82774a062..b36dfbf8a 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/handlers/VelocityChannelInitializer.java @@ -17,10 +17,11 @@ */ package com.viaversion.viaversion.velocity.handlers; +import com.viaversion.viaversion.protocol.ProtocolPipelineImpl; +import com.viaversion.viaversion.connection.UserConnectionImpl; import io.netty.channel.Channel; import io.netty.channel.ChannelInitializer; import com.viaversion.viaversion.api.connection.UserConnection; -import com.viaversion.viaversion.api.protocol.ProtocolPipeline; import java.lang.reflect.Method; @@ -47,8 +48,8 @@ public class VelocityChannelInitializer extends ChannelInitializer { protected void initChannel(Channel channel) throws Exception { initChannel.invoke(original, channel); - UserConnection user = new UserConnection(channel, clientSide); - new ProtocolPipeline(user); + UserConnection user = new UserConnectionImpl(channel, clientSide); + new ProtocolPipelineImpl(user); // We need to add a separated handler because Velocity uses pipeline().get(MINECRAFT_DECODER) channel.pipeline().addBefore("minecraft-encoder", "via-encoder", new VelocityEncodeHandler(user)); diff --git a/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityMovementTransmitter.java b/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityMovementTransmitter.java index 3eca46565..35827d82e 100644 --- a/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityMovementTransmitter.java +++ b/velocity/src/main/java/com/viaversion/viaversion/velocity/providers/VelocityMovementTransmitter.java @@ -38,7 +38,7 @@ public class VelocityMovementTransmitter extends MovementTransmitterProvider { public void sendPlayer(UserConnection userConnection) { if (userConnection.getProtocolInfo().getState() == State.PLAY) { - PacketWrapper wrapper = new PacketWrapper(0x03, null, userConnection); + PacketWrapper wrapper = PacketWrapper.create(0x03, null, userConnection); wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround()); try { wrapper.sendToServer(Protocol1_9To1_8.class);