Create some fancy interfaces

This commit is contained in:
KennyTV 2021-04-26 22:54:43 +02:00
parent 49d386063d
commit 30d122e7fa
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
53 changed files with 1839 additions and 1164 deletions

View File

@ -22,7 +22,7 @@
*/ */
package com.viaversion.viaversion.api; 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 io.netty.buffer.ByteBuf;
import com.viaversion.viaversion.api.boss.BossBar; import com.viaversion.viaversion.api.boss.BossBar;
import com.viaversion.viaversion.api.boss.BossColor; import com.viaversion.viaversion.api.boss.BossColor;
@ -40,7 +40,7 @@ import java.util.UUID;
* @param <T> The player type for the specific platform, for bukkit it's {@code ViaAPI<Player>} * @param <T> The player type for the specific platform, for bukkit it's {@code ViaAPI<Player>}
* @see ViaManager * @see ViaManager
* @see ProtocolManager * @see ProtocolManager
* @see ViaConnectionManager * @see ConnectionManager
* @see ViaPlatform * @see ViaPlatform
*/ */
public interface ViaAPI<T> { public interface ViaAPI<T> {

View File

@ -28,7 +28,7 @@ import com.viaversion.viaversion.api.platform.ViaPlatform;
import com.viaversion.viaversion.api.platform.ViaPlatformLoader; import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.ProtocolManager; 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; import java.util.Set;
@ -53,7 +53,7 @@ public interface ViaManager {
* *
* @return userconnection manager * @return userconnection manager
*/ */
ViaConnectionManager getConnectionManager(); ConnectionManager getConnectionManager();
/** /**
* Returns the manager for Via providers. * Returns the manager for Via providers.

View File

@ -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.
* <p>
* 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.
* <p>
* 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<UserConnection> 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<UUID, UserConnection> getConnectedClients();
void onLoginSuccess(UserConnection connection);
void onDisconnect(UserConnection connection);
}

View File

@ -23,36 +23,21 @@
package com.viaversion.viaversion.api.connection; package com.viaversion.viaversion.api.connection;
import com.viaversion.viaversion.api.protocol.ProtocolPipeline; 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 com.viaversion.viaversion.api.protocol.packet.State;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import java.util.UUID; import java.util.UUID;
public class ProtocolInfo extends StoredObject { public interface ProtocolInfo {
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);
}
/** /**
* Returns the protocol state the user is currently in. * Returns the protocol state the user is currently in.
* *
* @return protocol state * @return protocol state
*/ */
public State getState() { State getState();
return state;
}
public void setState(State state) { void setState(State state);
this.state = state;
}
/** /**
* Returns the user's protocol version, or -1 if not set. * 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 * @return protocol version, or -1 if not set
*/ */
public int getProtocolVersion() { int getProtocolVersion();
return protocolVersion;
}
public void setProtocolVersion(int protocolVersion) { void setProtocolVersion(int protocolVersion);
// Map snapshot versions to the higher/orderer release version
ProtocolVersion protocol = ProtocolVersion.getProtocol(protocolVersion);
this.protocolVersion = protocol.getVersion();
}
/** /**
* Returns the server protocol version the user is connected to, or -1 if not set. * 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 * @return server protocol version, or -1 if not set
*/ */
public int getServerProtocolVersion() { int getServerProtocolVersion();
return serverProtocolVersion;
}
public void setServerProtocolVersion(int serverProtocolVersion) { void setServerProtocolVersion(int serverProtocolVersion);
ProtocolVersion protocol = ProtocolVersion.getProtocol(serverProtocolVersion);
this.serverProtocolVersion = protocol.getVersion();
}
/** /**
* Returns the username associated with this connection. * 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 * @return username, set when entering the {@link State#PLAY} state
*/ */
public @MonotonicNonNull String getUsername() { @MonotonicNonNull String getUsername();
return username;
}
public void setUsername(String username) { void setUsername(String username);
this.username = username;
}
/** /**
* Returns the uuid associated with this connection. * 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 * @return uuid, set when entering the {@link State#PLAY} state
*/ */
public UUID getUuid() { UUID getUuid();
return uuid;
}
public void setUuid(UUID uuid) { void setUuid(UUID uuid);
this.uuid = uuid;
}
/** /**
* Returns the user's pipeline. * Returns the user's pipeline.
* *
* @return protocol pipeline * @return protocol pipeline
*/ */
public ProtocolPipeline getPipeline() { ProtocolPipeline getPipeline();
return pipeline;
}
public void setPipeline(ProtocolPipeline pipeline) { void setPipeline(ProtocolPipeline pipeline);
this.pipeline = pipeline;
}
@Override /**
public String toString() { * Returns the user connection this info represents.
return "ProtocolInfo{" + *
"state=" + state + * @return user connection
", protocolVersion=" + protocolVersion + */
", serverProtocolVersion=" + serverProtocolVersion + UserConnection getUser();
", username='" + username + '\'' +
", uuid=" + uuid +
'}';
}
} }

View File

@ -22,10 +22,10 @@
*/ */
package com.viaversion.viaversion.api.connection; package com.viaversion.viaversion.api.connection;
public class StoredObject { public abstract class StoredObject {
private final UserConnection user; private final UserConnection user;
public StoredObject(UserConnection user) { protected StoredObject(UserConnection user) {
this.user = user; this.user = user;
} }

View File

@ -22,63 +22,21 @@
*/ */
package com.viaversion.viaversion.api.connection; 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.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.buffer.ByteBuf;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import org.checkerframework.checker.nullness.qual.Nullable; 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.Map;
import java.util.Set;
import java.util.UUID; 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; import java.util.function.Function;
public class UserConnection { public interface UserConnection {
private static final AtomicLong IDS = new AtomicLong();
private final long id = IDS.incrementAndGet();
private final Map<Class<?>, StoredObject> storedObjects = new ConcurrentHashMap<>();
private final PacketTracker packetTracker = new PacketTracker(this);
private final Set<UUID> passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
.<UUID, Boolean>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);
}
/** /**
* Get an object from the storage. * Get an object from the storage.
@ -87,9 +45,7 @@ public class UserConnection {
* @param <T> The type of the class you want to get. * @param <T> The type of the class you want to get.
* @return The requested object * @return The requested object
*/ */
public @Nullable <T extends StoredObject> T get(Class<T> objectClass) { @Nullable <T extends StoredObject> T get(Class<T> objectClass);
return (T) storedObjects.get(objectClass);
}
/** /**
* Check if the storage has an object. * Check if the storage has an object.
@ -97,26 +53,20 @@ public class UserConnection {
* @param objectClass The object class to check * @param objectClass The object class to check
* @return True if the object is in the storage * @return True if the object is in the storage
*/ */
public boolean has(Class<? extends StoredObject> objectClass) { boolean has(Class<? extends StoredObject> objectClass);
return storedObjects.containsKey(objectClass);
}
/** /**
* Put an object into the stored objects based on class. * Put an object into the stored objects based on class.
* *
* @param object The object to store. * @param object The object to store.
*/ */
public void put(StoredObject object) { void put(StoredObject object);
storedObjects.put(object.getClass(), object);
}
/** /**
* Clear all the stored objects. * Clear all the stored objects.
* Used for bungee when switching servers. * Used for bungee when switching servers.
*/ */
public void clearStoredObjects() { void clearStoredObjects();
storedObjects.clear();
}
/** /**
* Send a raw packet to the player. * Send a raw packet to the player.
@ -124,26 +74,7 @@ public class UserConnection {
* @param packet The raw packet to send * @param packet The raw packet to send
* @param currentThread Should it run in the same thread * @param currentThread Should it run in the same thread
*/ */
public void sendRawPacket(final ByteBuf packet, boolean currentThread) { void sendRawPacket(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();
}
}
}
/** /**
* Send a raw packet to the player with returning the future. * 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 * @param packet The raw packet to send
* @return ChannelFuture of the packet being sent * @return ChannelFuture of the packet being sent
*/ */
public ChannelFuture sendRawPacketFuture(final ByteBuf packet) { ChannelFuture sendRawPacketFuture(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();
}
/** /**
* Send a raw packet to the player (netty thread). * Send a raw packet to the player (netty thread).
* *
* @param packet The packet to send * @param packet The packet to send
*/ */
public void sendRawPacket(ByteBuf packet) { void sendRawPacket(ByteBuf packet);
sendRawPacket(packet, false);
}
/** /**
* Returns the user's packet tracker used for the inbuilt packet-limiter. * Returns the user's packet tracker used for the inbuilt packet-limiter.
* *
* @return packet tracker * @return packet tracker
*/ */
public PacketTracker getPacketTracker() { PacketTracker getPacketTracker();
return packetTracker;
}
/** /**
* Disconnect a connection. * Disconnect a connection.
* *
* @param reason The reason to use, not used if player is not active. * @param reason The reason to use, not used if player is not active.
*/ */
public void disconnect(String reason) { void disconnect(String reason);
if (!channel.isOpen() || pendingDisconnect) return;
pendingDisconnect = true;
Via.getPlatform().runSync(() -> {
if (!Via.getPlatform().disconnect(this, ChatColorUtil.translateAlternateColorCodes(reason))) {
channel.close(); // =)
}
});
}
/** /**
* Sends a raw packet to the server. * Sends a raw packet to the server.
@ -209,120 +111,35 @@ public class UserConnection {
* @param packet Raw packet to be sent * @param packet Raw packet to be sent
* @param currentThread If {@code true} executes immediately, {@code false} submits a task to EventLoop * @param currentThread If {@code true} executes immediately, {@code false} submits a task to EventLoop
*/ */
public void sendRawPacketToServer(final ByteBuf packet, boolean currentThread) { void sendRawPacketToServer(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
}
}
}
/** /**
* Sends a raw packet to the server. It will submit a task to EventLoop. * Sends a raw packet to the server. It will submit a task to EventLoop.
* *
* @param packet Raw packet to be sent * @param packet Raw packet to be sent
*/ */
public void sendRawPacketToServer(ByteBuf packet) { void sendRawPacketToServer(ByteBuf packet);
sendRawPacketToServer(packet, false);
}
/** /**
* Monitors incoming packets * Monitors incoming packets
* *
* @return false if this packet should be cancelled * @return false if this packet should be cancelled
*/ */
public boolean checkIncomingPacket() { 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();
}
/** /**
* Monitors outgoing packets * Monitors outgoing packets
* *
* @return false if this packet should be cancelled * @return false if this packet should be cancelled
*/ */
public boolean checkOutgoingPacket() { boolean checkOutgoingPacket();
if (clientSide) {
return checkServerbound();
} else {
return checkClientbound();
}
}
/** /**
* Checks if packets needs transforming. * Checks if packets needs transforming.
* *
* @return if packets should be passed through * @return if packets should be passed through
*/ */
public boolean shouldTransformPacket() { boolean shouldTransformPacket();
return active;
}
/** /**
* Transforms the outgoing packet contained in ByteBuf. When clientSide is true, this packet is considered * 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 InformativeException if packet transforming failed
* @throws Exception if any other processing outside of transforming fails * @throws Exception if any other processing outside of transforming fails
*/ */
public void transformOutgoing(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception { void transformOutgoing(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception;
if (!buf.isReadable()) return;
transform(buf, clientSide ? Direction.INCOMING : Direction.OUTGOING, cancelSupplier);
}
/** /**
* Transforms the incoming packet contained in ByteBuf. When clientSide is true, this packet is considered * 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 InformativeException if packet transforming failed
* @throws Exception if any other processing outside of transforming fails * @throws Exception if any other processing outside of transforming fails
*/ */
public void transformIncoming(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception { void transformIncoming(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception;
if (!buf.isReadable()) return;
transform(buf, clientSide ? Direction.OUTGOING : Direction.INCOMING, cancelSupplier);
}
private void transform(ByteBuf buf, Direction direction, Function<Throwable, Exception> 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();
}
}
/** /**
* Returns the internal id incremented for each new connection. * Returns the internal id incremented for each new connection.
* *
* @return internal id * @return internal id
*/ */
public long getId() { long getId();
return id;
}
/** /**
* Returns the netty channel if present. * Returns the netty channel if present.
* *
* @return netty channel if present * @return netty channel if present
*/ */
public @Nullable Channel getChannel() { @Nullable Channel getChannel();
return channel;
}
/** /**
* Returns info containing the current protocol state and userdata. * Returns info containing the current protocol state and userdata.
* *
* @return info containing the current protocol state and userdata * @return info containing the current protocol state and userdata
*/ */
public @Nullable ProtocolInfo getProtocolInfo() { @Nullable ProtocolInfo getProtocolInfo();
return protocolInfo;
}
public void setProtocolInfo(@Nullable ProtocolInfo protocolInfo) { void setProtocolInfo(@Nullable ProtocolInfo protocolInfo);
this.protocolInfo = protocolInfo;
if (protocolInfo != null) {
storedObjects.put(ProtocolInfo.class, protocolInfo);
} else {
storedObjects.remove(ProtocolInfo.class);
}
}
/** /**
* Returns a map of stored objects. * Returns a map of stored objects.
@ -425,35 +198,25 @@ public class UserConnection {
* @see #get(Class) * @see #get(Class)
* @see #put(StoredObject) * @see #put(StoredObject)
*/ */
public Map<Class<?>, StoredObject> getStoredObjects() { Map<Class<?>, StoredObject> getStoredObjects();
return storedObjects;
}
/** /**
* Returns whether the connection has protocols other than the base protocol applied. * Returns whether the connection has protocols other than the base protocol applied.
* *
* @return whether the connection is active * @return whether the connection is active
*/ */
public boolean isActive() { boolean isActive();
return active;
}
public void setActive(boolean active) { void setActive(boolean active);
this.active = active;
}
/** /**
* Returns whether the connection is pending a disconnect, initiated through {@link #disconnect(String)}. * Returns whether the connection is pending a disconnect, initiated through {@link #disconnect(String)}.
* *
* @return whether the connection is pending a disconnect * @return whether the connection is pending a disconnect
*/ */
public boolean isPendingDisconnect() { boolean isPendingDisconnect();
return pendingDisconnect;
}
public void setPendingDisconnect(boolean pendingDisconnect) { void setPendingDisconnect(boolean pendingDisconnect);
this.pendingDisconnect = pendingDisconnect;
}
/** /**
* Returns whether this is a client-side connection. * Returns whether this is a client-side connection.
@ -461,18 +224,14 @@ public class UserConnection {
* *
* @return whether this is a client-side connection * @return whether this is a client-side connection
*/ */
public boolean isClientSide() { boolean isClientSide();
return clientSide;
}
/** /**
* Returns whether {@link ViaVersionConfig#getBlockedProtocols()} should be checked for this connection. * Returns whether {@link ViaVersionConfig#getBlockedProtocols()} should be checked for this connection.
* *
* @return whether blocked protocols should be applied * @return whether blocked protocols should be applied
*/ */
public boolean shouldApplyBlockProtocol() { boolean shouldApplyBlockProtocol();
return !clientSide; // Don't apply protocol blocking on client-side
}
/** /**
* Returns a newly generated uuid that will let a packet be passed through without * 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 * @return generated passthrough token
*/ */
public UUID generatePassthroughToken() { 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);
}
} }

View File

@ -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<SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes,
SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes> implements SimpleProtocol {
}

View File

@ -23,20 +23,19 @@
package com.viaversion.viaversion.api.protocol; package com.viaversion.viaversion.api.protocol;
import com.google.common.base.Preconditions; 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.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.Direction; import com.viaversion.viaversion.api.protocol.packet.Direction;
import com.viaversion.viaversion.api.protocol.packet.PacketType; 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.ServerboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.State; 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.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.exception.CancelException; import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException; import com.viaversion.viaversion.exception.InformativeException;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
@ -44,17 +43,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
/** public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends ClientboundPacketType, S1 extends ServerboundPacketType, S2 extends ServerboundPacketType>
* Abstract protocol class handling packet transformation between two protocol versions. implements com.viaversion.viaversion.api.protocol.base.Protocol<C1, C2, S1, S2> {
* Clientbound and serverbount packet types can be set to enforce correct usage of them.
*
* @param <C1> old clientbound packet types
* @param <C2> new clientbound packet types
* @param <S1> old serverbound packet types
* @param <S2> 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<C1 extends ClientboundPacketType, C2 extends ClientboundPacketType, S1 extends ServerboundPacketType, S2 extends ServerboundPacketType> {
private final Map<Packet, ProtocolPacket> incoming = new HashMap<>(); private final Map<Packet, ProtocolPacket> incoming = new HashMap<>();
private final Map<Packet, ProtocolPacket> outgoing = new HashMap<>(); private final Map<Packet, ProtocolPacket> outgoing = new HashMap<>();
private final Map<Class, Object> storedObjects = new HashMap<>(); // currently only used for MetadataRewriters private final Map<Class, Object> storedObjects = new HashMap<>(); // currently only used for MetadataRewriters
@ -137,26 +127,8 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
} }
} }
/** @Override
* Should this protocol filter an object packet from this class. public void filterPacket(UserConnection info, Object packet, List output) throws Exception {
* Default: false
*
* @param packetClass The class of the current input
* @return True if it should handle the filtering
*/
public 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.
*/
protected void filterPacket(UserConnection info, Object packet, List output) throws Exception {
output.add(packet); output.add(packet);
} }
@ -166,9 +138,7 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
protected void registerPackets() { protected void registerPackets() {
} }
/** @Override
* Loads the mappingdata.
*/
public final void loadMappingData() { public final void loadMappingData() {
getMappingData().load(); getMappingData().load();
onMappingDataLoaded(); onMappingDataLoaded();
@ -182,50 +152,25 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
protected void onMappingDataLoaded() { protected void onMappingDataLoaded() {
} }
/** @Override
* Handle protocol registration phase, use this to register providers / tasks.
* <p>
* To be overridden if needed.
*
* @param providers The current providers
*/
public void register(ViaProviders providers) { public void register(ViaProviders providers) {
} }
/** @Override
* Initialise a user for this protocol setting up objects.
* /!\ WARNING - May be called more than once in a single {@link UserConnection}
* <p>
* To be overridden if needed.
*
* @param userConnection The user to initialise
*/
public void init(UserConnection userConnection) { public void init(UserConnection userConnection) {
} }
/** @Override
* 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
*/
public void registerIncoming(State state, int oldPacketID, int newPacketID) { public void registerIncoming(State state, int oldPacketID, int newPacketID) {
registerIncoming(state, oldPacketID, newPacketID, null); registerIncoming(state, oldPacketID, newPacketID, null);
} }
/** @Override
* 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
*/
public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) { public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) {
registerIncoming(state, oldPacketID, newPacketID, packetRemapper, false); registerIncoming(state, oldPacketID, newPacketID, packetRemapper, false);
} }
@Override
public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override) { public void registerIncoming(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override) {
ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper); ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper);
Packet packet = new Packet(state, newPacketID); Packet packet = new Packet(state, newPacketID);
@ -236,6 +181,7 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
incoming.put(packet, protocolPacket); incoming.put(packet, protocolPacket);
} }
@Override
public void cancelIncoming(State state, int oldPacketID, int newPacketID) { public void cancelIncoming(State state, int oldPacketID, int newPacketID) {
registerIncoming(state, oldPacketID, newPacketID, new PacketRemapper() { registerIncoming(state, oldPacketID, newPacketID, new PacketRemapper() {
@Override @Override
@ -245,33 +191,22 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
}); });
} }
@Override
public void cancelIncoming(State state, int newPacketID) { public void cancelIncoming(State state, int newPacketID) {
cancelIncoming(state, -1, newPacketID); cancelIncoming(state, -1, newPacketID);
} }
/** @Override
* 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
*/
public void registerOutgoing(State state, int oldPacketID, int newPacketID) { public void registerOutgoing(State state, int oldPacketID, int newPacketID) {
registerOutgoing(state, oldPacketID, newPacketID, null); registerOutgoing(state, oldPacketID, newPacketID, null);
} }
/** @Override
* 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
*/
public void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) { public void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper) {
registerOutgoing(state, oldPacketID, newPacketID, packetRemapper, false); registerOutgoing(state, oldPacketID, newPacketID, packetRemapper, false);
} }
@Override
public void cancelOutgoing(State state, int oldPacketID, int newPacketID) { public void cancelOutgoing(State state, int oldPacketID, int newPacketID) {
registerOutgoing(state, oldPacketID, newPacketID, new PacketRemapper() { registerOutgoing(state, oldPacketID, newPacketID, new PacketRemapper() {
@Override @Override
@ -281,10 +216,12 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
}); });
} }
@Override
public void cancelOutgoing(State state, int oldPacketID) { public void cancelOutgoing(State state, int oldPacketID) {
cancelOutgoing(state, oldPacketID, -1); cancelOutgoing(state, oldPacketID, -1);
} }
@Override
public void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override) { public void registerOutgoing(State state, int oldPacketID, int newPacketID, PacketRemapper packetRemapper, boolean override) {
ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper); ProtocolPacket protocolPacket = new ProtocolPacket(state, oldPacketID, newPacketID, packetRemapper);
Packet packet = new Packet(state, oldPacketID); Packet packet = new Packet(state, oldPacketID);
@ -296,12 +233,7 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
} }
/** @Override
* Registers an outgoing protocol and automatically maps it to the new id.
*
* @param packetType clientbound packet type the server sends
* @param packetRemapper remapper
*/
public void registerOutgoing(C1 packetType, @Nullable PacketRemapper packetRemapper) { public void registerOutgoing(C1 packetType, @Nullable PacketRemapper packetRemapper) {
checkPacketType(packetType, packetType.getClass() == oldClientboundPacketEnum); checkPacketType(packetType, packetType.getClass() == oldClientboundPacketEnum);
@ -314,13 +246,7 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
registerOutgoing(State.PLAY, oldId, newId, packetRemapper); registerOutgoing(State.PLAY, oldId, newId, packetRemapper);
} }
/** @Override
* 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
*/
public void registerOutgoing(C1 packetType, @Nullable C2 mappedPacketType, @Nullable PacketRemapper packetRemapper) { public void registerOutgoing(C1 packetType, @Nullable C2 mappedPacketType, @Nullable PacketRemapper packetRemapper) {
checkPacketType(packetType, packetType.getClass() == oldClientboundPacketEnum); checkPacketType(packetType, packetType.getClass() == oldClientboundPacketEnum);
checkPacketType(mappedPacketType, mappedPacketType == null || mappedPacketType.getClass() == newClientboundPacketEnum); checkPacketType(mappedPacketType, mappedPacketType == null || mappedPacketType.getClass() == newClientboundPacketEnum);
@ -328,27 +254,17 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
registerOutgoing(State.PLAY, packetType.ordinal(), mappedPacketType != null ? mappedPacketType.ordinal() : -1, packetRemapper); registerOutgoing(State.PLAY, packetType.ordinal(), mappedPacketType != null ? mappedPacketType.ordinal() : -1, packetRemapper);
} }
/** @Override
* 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
*/
public void registerOutgoing(C1 packetType, @Nullable C2 mappedPacketType) { public void registerOutgoing(C1 packetType, @Nullable C2 mappedPacketType) {
registerOutgoing(packetType, mappedPacketType, null); registerOutgoing(packetType, mappedPacketType, null);
} }
@Override
public void cancelOutgoing(C1 packetType) { public void cancelOutgoing(C1 packetType) {
cancelOutgoing(State.PLAY, packetType.ordinal(), packetType.ordinal()); cancelOutgoing(State.PLAY, packetType.ordinal(), packetType.ordinal());
} }
/** @Override
* Registers an incoming protocol and automatically maps it to the server's id.
*
* @param packetType serverbound packet type the client sends
* @param packetRemapper remapper
*/
public void registerIncoming(S2 packetType, @Nullable PacketRemapper packetRemapper) { public void registerIncoming(S2 packetType, @Nullable PacketRemapper packetRemapper) {
checkPacketType(packetType, packetType.getClass() == newServerboundPacketEnum); checkPacketType(packetType, packetType.getClass() == newServerboundPacketEnum);
@ -361,13 +277,7 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
registerIncoming(State.PLAY, oldId, newId, packetRemapper); registerIncoming(State.PLAY, oldId, newId, packetRemapper);
} }
/** @Override
* 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
*/
public void registerIncoming(S2 packetType, @Nullable S1 mappedPacketType, @Nullable PacketRemapper packetRemapper) { public void registerIncoming(S2 packetType, @Nullable S1 mappedPacketType, @Nullable PacketRemapper packetRemapper) {
checkPacketType(packetType, packetType.getClass() == newServerboundPacketEnum); checkPacketType(packetType, packetType.getClass() == newServerboundPacketEnum);
checkPacketType(mappedPacketType, mappedPacketType == null || mappedPacketType.getClass() == oldServerboundPacketEnum); checkPacketType(mappedPacketType, mappedPacketType == null || mappedPacketType.getClass() == oldServerboundPacketEnum);
@ -375,44 +285,26 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
registerIncoming(State.PLAY, mappedPacketType != null ? mappedPacketType.ordinal() : -1, packetType.ordinal(), packetRemapper); registerIncoming(State.PLAY, mappedPacketType != null ? mappedPacketType.ordinal() : -1, packetType.ordinal(), packetRemapper);
} }
@Override
public void cancelIncoming(S2 packetType) { public void cancelIncoming(S2 packetType) {
Preconditions.checkArgument(packetType.getClass() == newServerboundPacketEnum); Preconditions.checkArgument(packetType.getClass() == newServerboundPacketEnum);
cancelIncoming(State.PLAY, -1, packetType.ordinal()); cancelIncoming(State.PLAY, -1, packetType.ordinal());
} }
/** @Override
* 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
*/
public boolean hasRegisteredOutgoing(State state, int oldPacketID) { public boolean hasRegisteredOutgoing(State state, int oldPacketID) {
Packet packet = new Packet(state, oldPacketID); Packet packet = new Packet(state, oldPacketID);
return outgoing.containsKey(packet); return outgoing.containsKey(packet);
} }
/** @Override
* 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
*/
public boolean hasRegisteredIncoming(State state, int newPacketId) { public boolean hasRegisteredIncoming(State state, int newPacketId) {
Packet packet = new Packet(state, newPacketId); Packet packet = new Packet(state, newPacketId);
return incoming.containsKey(packet); return incoming.containsKey(packet);
} }
/** @Override
* 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
*/
public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception { public void transform(Direction direction, State state, PacketWrapper packetWrapper) throws Exception {
Packet statePacket = new Packet(state, packetWrapper.getId()); Packet statePacket = new Packet(state, packetWrapper.getId());
Map<Packet, ProtocolPacket> packetMap = (direction == Direction.OUTGOING ? outgoing : incoming); Map<Packet, ProtocolPacket> packetMap = (direction == Direction.OUTGOING ? outgoing : incoming);
@ -475,39 +367,21 @@ public abstract class Protocol<C1 extends ClientboundPacketType, C2 extends Clie
} }
} }
@Override
public @Nullable <T> T get(Class<T> objectClass) { public @Nullable <T> T get(Class<T> objectClass) {
return (T) storedObjects.get(objectClass); return (T) storedObjects.get(objectClass);
} }
@Override
public void put(Object object) { public void put(Object object) {
storedObjects.put(object.getClass(), object); storedObjects.put(object.getClass(), object);
} }
/** @Override
* Returns true if this Protocol's {@link #loadMappingData()} method should be called.
* <p>
* 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
*/
public boolean hasMappingDataToLoad() { public boolean hasMappingDataToLoad() {
return getMappingData() != null; 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 @Override
public String toString() { public String toString() {
return "Protocol:" + getClass().getSimpleName(); return "Protocol:" + getClass().getSimpleName();

View File

@ -23,8 +23,13 @@
package com.viaversion.viaversion.api.protocol; package com.viaversion.viaversion.api.protocol;
import com.google.common.collect.Range; 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.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import io.netty.buffer.ByteBuf;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.List; import java.util.List;
@ -44,9 +49,10 @@ public interface ProtocolManager {
* Returns a protocol instance by its class. * Returns a protocol instance by its class.
* *
* @param protocolClass class of the protocol * @param protocolClass class of the protocol
* @param <T> protocol
* @return protocol if present * @return protocol if present
*/ */
@Nullable Protocol getProtocol(Class<? extends Protocol> protocolClass); @Nullable <T extends Protocol> T getProtocol(Class<T> protocolClass);
/** /**
* Returns the base protocol handling incoming handshake packets. * 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 * @return data loading future bound to the protocol, or null if all loading is complete
*/ */
@Nullable CompletableFuture<Void> getMappingLoaderFuture(Class<? extends Protocol> protocolClass); @Nullable CompletableFuture<Void> getMappingLoaderFuture(Class<? extends Protocol> 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);
} }

View File

@ -22,6 +22,8 @@
*/ */
package com.viaversion.viaversion.api.protocol; package com.viaversion.viaversion.api.protocol;
import com.viaversion.viaversion.api.protocol.base.Protocol;
public interface ProtocolPathEntry { public interface ProtocolPathEntry {
/** /**

View File

@ -22,52 +22,14 @@
*/ */
package com.viaversion.viaversion.api.protocol; 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.connection.UserConnection;
import com.viaversion.viaversion.api.platform.ViaPlatform; import com.viaversion.viaversion.api.protocol.base.Protocol;
import com.viaversion.viaversion.api.protocol.packet.Direction; import com.viaversion.viaversion.api.protocol.base.SimpleProtocol;
import com.viaversion.viaversion.api.protocol.packet.State; import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
public class ProtocolPipeline extends SimpleProtocol { public interface ProtocolPipeline extends SimpleProtocol {
/**
* Protocol list ordered from client to server transforation with the base protocols at the end.
*/
private List<Protocol> 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);
}
}
/** /**
* Adds a protocol to the current pipeline. * Adds a protocol to the current pipeline.
@ -75,16 +37,7 @@ public class ProtocolPipeline extends SimpleProtocol {
* *
* @param protocol protocol to add to the end * @param protocol protocol to add to the end
*/ */
public void add(Protocol protocol) { void add(Protocol protocol);
Preconditions.checkNotNull(protocolList, "Tried to add protocol too early");
protocolList.add(protocol);
protocol.init(userConnection);
if (!protocol.isBaseProtocol()) {
moveBaseProtocolsToTail();
}
}
/** /**
* Adds a list of protocols to the current pipeline. * 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 * @param protocols protocols to add to the end
*/ */
public void add(List<Protocol> protocols) { void add(List<Protocol> 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<Protocol> 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
});
}
/** /**
* Check if the pipeline contains a protocol * Check if the pipeline contains a protocol
@ -163,19 +53,18 @@ public class ProtocolPipeline extends SimpleProtocol {
* @param pipeClass The class to check * @param pipeClass The class to check
* @return True if the protocol class is in the pipeline * @return True if the protocol class is in the pipeline
*/ */
public boolean contains(Class<? extends Protocol> pipeClass) { boolean contains(Class<? extends Protocol> pipeClass);
for (Protocol protocol : protocolList) {
if (protocol.getClass().equals(pipeClass)) return true;
}
return false;
}
public <P extends Protocol> P getProtocol(Class<P> pipeClass) { /**
for (Protocol protocol : protocolList) { * Returns the protocol from the given class if present in the pipeline.
if (protocol.getClass() == pipeClass) return (P) protocol; *
} * @param pipeClass protocol class
return null; * @param <P> protocol
} * @return protocol from class
* @see #contains(Class)
* @see ProtocolManager#getProtocol(Class) for a faster alternative
*/
@Nullable <P extends Protocol> P getProtocol(Class<P> pipeClass);
/** /**
* Use the pipeline to filter a NMS packet * 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. * @return If it should not write the input object to te list.
* @throws Exception If it failed to convert / packet cancelld. * @throws Exception If it failed to convert / packet cancelld.
*/ */
public boolean filter(Object o, List list) throws Exception { 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; List<Protocol> pipes();
}
public List<Protocol> pipes() {
return protocolList;
}
/** /**
* Cleans the pipe and adds the base protocol. * Cleans the pipe and adds the base protocol.
* /!\ WARNING - It doesn't add version-specific base Protocol. * /!\ WARNING - It doesn't add version-specific base Protocol.
*/ */
public void cleanPipes() { void cleanPipes();
pipes().clear();
registerPackets();
}
} }

View File

@ -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 <C1> old clientbound packet types
* @param <C2> new clientbound packet types
* @param <S1> old serverbound packet types
* @param <S2> 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<C1 extends ClientboundPacketType, C2 extends ClientboundPacketType, S1 extends ServerboundPacketType, S2 extends ServerboundPacketType> {
/**
* 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.
* <p>
* 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}
* <p>
* 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> T get(Class<T> objectClass);
void put(Object object);
/**
* Returns true if this Protocol's {@link #loadMappingData()} method should be called.
* <p>
* 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;
}
}

View File

@ -20,7 +20,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * 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.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.ServerboundPacketType; 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 * Dummy protocol class when there is no need of any of the
* existing packet type enums or automated channel mappings. * existing packet type enums or automated channel mappings.
* *
* @see Protocol * @see com.viaversion.viaversion.api.protocol.base.Protocol
*/ */
public abstract class SimpleProtocol extends Protocol<SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes> { public interface SimpleProtocol extends Protocol<SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes, SimpleProtocol.DummyPacketTypes> {
protected SimpleProtocol() { enum DummyPacketTypes implements ClientboundPacketType, ServerboundPacketType {
}
public enum DummyPacketTypes implements ClientboundPacketType, ServerboundPacketType {
} }
} }

View File

@ -22,42 +22,55 @@
*/ */
package com.viaversion.viaversion.api.protocol.packet; package com.viaversion.viaversion.api.protocol.packet;
import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.Via; 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.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.protocol.remapper.ValueCreator;
import com.viaversion.viaversion.api.type.Type; 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.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.List;
import java.util.NoSuchElementException;
public class PacketWrapper { public interface PacketWrapper {
public static final int PASSTHROUGH_ID = 1000;
private static final Protocol[] PROTOCOL_ARRAY = new Protocol[0];
private final ByteBuf inputBuffer; int PASSTHROUGH_ID = 1000;
private final UserConnection userConnection;
private boolean send = true;
private int id = -1;
private final Deque<Pair<Type, Object>> readableObjects = new ArrayDeque<>();
private final List<Pair<Type, Object>> packetValues = new ArrayList<>();
public PacketWrapper(int packetID, ByteBuf inputBuffer, UserConnection userConnection) { /**
this.id = packetID; * Creates a new packet wrapper instance.
this.inputBuffer = inputBuffer; *
this.userConnection = userConnection; * @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 * @return The requested type or throws ArrayIndexOutOfBounds
* @throws InformativeException If it fails to find it, an exception will be thrown. * @throws InformativeException If it fails to find it, an exception will be thrown.
*/ */
public <T> T get(Type<T> type, int index) throws Exception { <T> T get(Type<T> type, int index) throws Exception;
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return (T) packetValue.getValue();
}
currentIndex++;
}
}
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);
}
/** /**
* Check if a type is at an index * 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) * @param index The index of the part (relative to the type)
* @return True if the type is at the index * @return True if the type is at the index
*/ */
public boolean is(Type type, int index) { boolean is(Type type, int index);
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
}
}
return false;
}
/** /**
* Check if a type is at an 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) * @param index The index of the part (relative to the type)
* @return True if the type is at the index * @return True if the type is at the index
*/ */
public boolean isReadable(Type type, int index) { boolean isReadable(Type type, int index);
int currentIndex = 0;
for (Pair<Type, Object> packetValue : readableObjects) {
if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
}
}
return false;
}
/** /**
* Set a currently existing part in the output * 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. * @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. * @throws InformativeException If it fails to set it, an exception will be thrown.
*/ */
public <T> void set(Type<T> type, int index, T value) throws Exception { <T> void set(Type<T> type, int index, T value) throws Exception;
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
packetValue.setValue(value);
return;
}
currentIndex++;
}
}
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());
}
/** /**
* Read a type from the input. * Read a type from the input.
@ -157,33 +121,7 @@ public class PacketWrapper {
* @return The requested type * @return The requested type
* @throws InformativeException If it fails to read * @throws InformativeException If it fails to read
*/ */
public <T> T read(Type<T> type) throws Exception { <T> T read(Type<T> 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<Type, Object> read = readableObjects.poll();
Type rtype = read.getKey();
if (rtype.equals(type)
|| (type.getBaseClass().equals(rtype.getBaseClass())
&& type.getOutputClass().equals(rtype.getOutputClass()))) {
return (T) read.getValue();
} else {
if (rtype == Type.NOTHING) {
return read(type); // retry
} else {
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
}
}
}
/** /**
* Write a type to the output. * Write a type to the output.
@ -192,19 +130,7 @@ public class PacketWrapper {
* @param <T> The return type of the type you wish to write. * @param <T> The return type of the type you wish to write.
* @param value The value of the type to write. * @param value The value of the type to write.
*/ */
public <T> void write(Type<T> type, T value) { <T> void write(Type<T> type, T value);
if (value != null) {
if (!type.getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (type instanceof TypeConverter) {
value = (T) ((TypeConverter) type).from(value);
} else {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
}
}
}
packetValues.add(new Pair<>(type, value));
}
/** /**
* Take a value from the input and write to the output. * 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. * @return The type which was read/written.
* @throws Exception If it failed to read or write * @throws Exception If it failed to read or write
*/ */
public <T> T passthrough(Type<T> type) throws Exception { <T> T passthrough(Type<T> type) throws Exception;
T value = read(type);
write(type, value);
return value;
}
/** /**
* Take all the inputs and write them to the output. * Take all the inputs and write them to the output.
* *
* @throws Exception If it failed to read or write * @throws Exception If it failed to read or write
*/ */
public void passthroughAll() throws Exception { 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);
}
}
/** /**
* Write the current output to a buffer. * Write the current output to a buffer.
@ -241,61 +155,17 @@ public class PacketWrapper {
* @param buffer The buffer to write to. * @param buffer The buffer to write to.
* @throws InformativeException Throws an exception if it fails to write a value. * @throws InformativeException Throws an exception if it fails to write a value.
*/ */
public void writeToBuffer(ByteBuf buffer) throws Exception { 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<Type, Object> packetValue : packetValues) {
try {
Object value = packetValue.getValue();
if (value != null) {
if (!packetValue.getKey().getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (packetValue.getKey() instanceof TypeConverter) {
value = ((TypeConverter) packetValue.getKey()).from(value);
} else {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
}
}
}
packetValue.getKey().write(buffer, value);
} 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);
}
/** /**
* Clear the input buffer / readable objects * Clear the input buffer / readable objects
*/ */
public void clearInputBuffer() { void clearInputBuffer();
if (inputBuffer != null) {
inputBuffer.clear();
}
readableObjects.clear(); // :(
}
/** /**
* Clear the packet, used if you have to change the packet completely * Clear the packet, used if you have to change the packet completely
*/ */
public void clearPacket() { void clearPacket();
clearInputBuffer();
packetValues.clear();
}
private void writeRemaining(ByteBuf output) {
if (inputBuffer != null) {
output.writeBytes(inputBuffer);
}
}
/** /**
* Send this packet to the associated user. * Send this packet to the associated user.
@ -306,9 +176,7 @@ public class PacketWrapper {
* @param skipCurrentPipeline Skip the current pipeline * @param skipCurrentPipeline Skip the current pipeline
* @throws Exception if it fails to write * @throws Exception if it fails to write
*/ */
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception { void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception;
send(packetProtocol, skipCurrentPipeline, false);
}
/** /**
* Send this packet to the associated user. * Send this packet to the associated user.
@ -320,61 +188,7 @@ public class PacketWrapper {
* @param currentThread Run in the same thread * @param currentThread Run in the same thread
* @throws Exception if it fails to write * @throws Exception if it fails to write
*/ */
public void send(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception { void send(Class<? extends Protocol> 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<? extends Protocol> 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();
}
}
/** /**
* Send this packet to the associated user. * Send this packet to the associated user.
@ -384,7 +198,7 @@ public class PacketWrapper {
* @param packetProtocol The protocol version of the packet. * @param packetProtocol The protocol version of the packet.
* @throws Exception if it fails to write * @throws Exception if it fails to write
*/ */
public void send(Class<? extends Protocol> packetProtocol) throws Exception { default void send(Class<? extends Protocol> packetProtocol) throws Exception {
send(packetProtocol, true); send(packetProtocol, true);
} }
@ -398,13 +212,7 @@ public class PacketWrapper {
* @return The packets ChannelFuture * @return The packets ChannelFuture
* @throws Exception if it fails to write * @throws Exception if it fails to write
*/ */
public ChannelFuture sendFuture(Class<? extends Protocol> packetProtocol) throws Exception { ChannelFuture sendFuture(Class<? extends Protocol> packetProtocol) throws Exception;
if (!isCancelled()) {
ByteBuf output = constructPacket(packetProtocol, true, Direction.OUTGOING);
return user().sendRawPacketFuture(output);
}
return user().getChannel().newFailedFuture(new Exception("Cancelled packet"));
}
/** /**
* Send this packet to the associated user. * Send this packet to the associated user.
@ -415,18 +223,7 @@ public class PacketWrapper {
* @throws Exception if it fails to write * @throws Exception if it fails to write
*/ */
@Deprecated @Deprecated
public void send() throws Exception { 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();
}
}
}
/** /**
* Create a new packet for the target of this packet. * 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 * @param packetType packet type of the new packedt
* @return The newly created packet wrapper * @return The newly created packet wrapper
*/ */
public PacketWrapper create(PacketType packetType) { PacketWrapper create(PacketType packetType);
return new PacketWrapper(packetType.ordinal(), null, user());
}
/** /**
* Create a new packet for the target of this packet. * 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 * @param packetID The ID of the new packet
* @return The newly created packet wrapper * @return The newly created packet wrapper
*/ */
public PacketWrapper create(int packetID) { PacketWrapper create(int packetID);
return new PacketWrapper(packetID, null, user());
}
/** /**
* Create a new packet with values. * Create a new packet with values.
@ -456,11 +249,7 @@ public class PacketWrapper {
* @return The newly created packet wrapper * @return The newly created packet wrapper
* @throws Exception If it failed to write the values from the ValueCreator. * @throws Exception If it failed to write the values from the ValueCreator.
*/ */
public PacketWrapper create(int packetID, ValueCreator init) throws Exception { PacketWrapper create(int packetID, ValueCreator init) throws Exception;
PacketWrapper wrapper = create(packetID);
init.write(wrapper);
return wrapper;
}
/** /**
* Applies a pipeline from an index to the wrapper. * Applies a pipeline from an index to the wrapper.
@ -473,69 +262,36 @@ public class PacketWrapper {
* @return The current packetwrapper * @return The current packetwrapper
* @throws Exception If it fails to transform a packet, exception will be thrown * @throws Exception If it fails to transform a packet, exception will be thrown
*/ */
public PacketWrapper apply(Direction direction, State state, int index, List<Protocol> pipeline, boolean reverse) throws Exception { PacketWrapper apply(Direction direction, State state, int index, List<Protocol> 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
}
/** /**
* @see #apply(Direction, State, int, List, boolean) * @see #apply(Direction, State, int, List, boolean)
*/ */
public PacketWrapper apply(Direction direction, State state, int index, List<Protocol> pipeline) throws Exception { PacketWrapper apply(Direction direction, State state, int index, List<Protocol> 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;
}
/** /**
* Cancel this packet from sending * Cancel this packet from sending
*/ */
public void cancel() { void cancel();
this.send = false;
}
/** /**
* Check if this packet is cancelled. * Check if this packet is cancelled.
* *
* @return True if the packet won't be sent. * @return True if the packet won't be sent.
*/ */
public boolean isCancelled() { boolean isCancelled();
return !this.send;
}
/** /**
* Get the user associated with this Packet * Get the user associated with this Packet
* *
* @return The user * @return The user
*/ */
public UserConnection user() { UserConnection user();
return this.userConnection;
}
/** /**
* Reset the reader, so that it can be read again. * Reset the reader, so that it can be read again.
*/ */
public void resetReader() { 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();
}
/** /**
* Send the current packet to the server. * Send the current packet to the server.
@ -544,18 +300,7 @@ public class PacketWrapper {
* @throws Exception If it failed to write * @throws Exception If it failed to write
*/ */
@Deprecated @Deprecated
public void sendToServer() throws Exception { 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();
}
}
}
/** /**
* Send this packet to the server. * Send this packet to the server.
@ -565,41 +310,17 @@ public class PacketWrapper {
* @param currentThread Run in the same thread * @param currentThread Run in the same thread
* @throws Exception if it fails to write * @throws Exception if it fails to write
*/ */
public void sendToServer(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline, boolean currentThread) throws Exception { void sendToServer(Class<? extends Protocol> 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;
}
}
}
}
public void sendToServer(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception { default void sendToServer(Class<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
sendToServer(packetProtocol, skipCurrentPipeline, false); sendToServer(packetProtocol, skipCurrentPipeline, false);
} }
public void sendToServer(Class<? extends Protocol> packetProtocol) throws Exception { default void sendToServer(Class<? extends Protocol> packetProtocol) throws Exception {
sendToServer(packetProtocol, true); sendToServer(packetProtocol, true);
} }
public int getId() { int getId();
return id;
}
public void setId(int id) { void setId(int id);
this.id = id;
}
@Override
public String toString() {
return "PacketWrapper{" +
"packetValues=" + packetValues +
", readableObjects=" + readableObjects +
", id=" + id +
'}';
}
} }

View File

@ -23,10 +23,10 @@
package com.viaversion.viaversion.api.protocol.remapper; package com.viaversion.viaversion.api.protocol.remapper;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper; 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.api.type.Type;
import com.viaversion.viaversion.exception.CancelException; import com.viaversion.viaversion.exception.CancelException;
import com.viaversion.viaversion.exception.InformativeException; import com.viaversion.viaversion.exception.InformativeException;
import com.viaversion.viaversion.util.Pair;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;

View File

@ -58,7 +58,7 @@ public class ArmorListener extends ViaBukkitListener {
armor += ArmorType.findById(stack.getTypeId()).getArmorPoints(); armor += ArmorType.findById(stack.getTypeId()).getArmorPoints();
} }
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player)); PacketWrapper wrapper = PacketWrapper.create(0x4B, null, getUserConnection(player));
try { try {
wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID wrapper.write(Type.VAR_INT, player.getEntityId()); // Player ID
wrapper.write(Type.INT, 1); // only 1 property wrapper.write(Type.INT, 1); // only 1 property

View File

@ -58,7 +58,7 @@ public class DeathListener extends ViaBukkitListener {
// If online // If online
UserConnection userConnection = getUserConnection(p); UserConnection userConnection = getUserConnection(p);
if (userConnection != null) { if (userConnection != null) {
PacketWrapper wrapper = new PacketWrapper(0x2C, null, userConnection); PacketWrapper wrapper = PacketWrapper.create(0x2C, null, userConnection);
try { try {
wrapper.write(Type.VAR_INT, 2); // Event - Entity dead wrapper.write(Type.VAR_INT, 2); // Event - Entity dead
wrapper.write(Type.VAR_INT, p.getEntityId()); // Player ID wrapper.write(Type.VAR_INT, p.getEntityId()); // Player ID

View File

@ -17,13 +17,14 @@
*/ */
package com.viaversion.viaversion.bukkit.handlers; 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.Channel;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder; import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import com.viaversion.viaversion.api.connection.UserConnection; 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.ClassGenerator;
import com.viaversion.viaversion.bukkit.classgenerator.HandlerConstructor; import com.viaversion.viaversion.bukkit.classgenerator.HandlerConstructor;
@ -50,9 +51,9 @@ public class BukkitChannelInitializer extends ChannelInitializer<SocketChannel>
@Override @Override
protected void initChannel(SocketChannel socketChannel) throws Exception { protected void initChannel(SocketChannel socketChannel) throws Exception {
UserConnection info = new UserConnection(socketChannel); UserConnection info = new UserConnectionImpl(socketChannel);
// init protocol // init protocol
new ProtocolPipeline(info); new ProtocolPipelineImpl(info);
// Add originals // Add originals
this.method.invoke(this.original, socketChannel); this.method.invoke(this.original, socketChannel);

View File

@ -55,7 +55,7 @@ public class EntityToggleGlideListener extends ViaBukkitListener {
// Cancelling can only be done by updating the player's metadata // Cancelling can only be done by updating the player's metadata
if (event.isGliding() && event.isCancelled()) { if (event.isGliding() && event.isCancelled()) {
PacketWrapper packet = new PacketWrapper(0x44, null, getUserConnection(player)); PacketWrapper packet = PacketWrapper.create(0x44, null, getUserConnection(player));
try { try {
packet.write(Type.VAR_INT, player.getEntityId()); packet.write(Type.VAR_INT, player.getEntityId());

View File

@ -17,10 +17,11 @@
*/ */
package com.viaversion.viaversion.bungee.handlers; 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.Channel;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.ProtocolPipeline;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -44,9 +45,9 @@ public class BungeeChannelInitializer extends ChannelInitializer<Channel> {
return; return;
} }
UserConnection info = new UserConnection(socketChannel); UserConnection info = new UserConnectionImpl(socketChannel);
// init protocol // init protocol
new ProtocolPipeline(info); new ProtocolPipelineImpl(info);
// Add originals // Add originals
this.method.invoke(this.original, socketChannel); this.method.invoke(this.original, socketChannel);

View File

@ -17,6 +17,23 @@
*/ */
package com.viaversion.viaversion.bungee.handlers; 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.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerConnectedEvent; 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.api.score.Team;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.protocol.packet.PluginMessage; 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.Field;
import java.lang.reflect.InvocationTargetException; 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. // 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)) { if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) {
for (UUID uuid : storage.getBossbar()) { 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.UUID, uuid);
wrapper.write(Type.VAR_INT, 1); // remove wrapper.write(Type.VAR_INT, 1); // remove
wrapper.send(Protocol1_9To1_8.class, true, true); wrapper.send(Protocol1_9To1_8.class, true, true);
@ -230,7 +230,7 @@ public class BungeeServerHandler implements Listener {
plMsg.setTag(channel); plMsg.setTag(channel);
} }
user.put(info); user.setProtocolInfo(info);
user.put(storage); user.put(storage);
user.setActive(protocolPath != null); user.setActive(protocolPath != null);

View File

@ -47,7 +47,7 @@ public class ElytraPatch implements Listener {
if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) { if (user.getProtocolInfo().getPipeline().contains(Protocol1_9To1_8.class)) {
int entityId = user.get(EntityTracker1_9.class).getProvidedEntityId(); 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(Type.VAR_INT, entityId);
wrapper.write(Types1_9.METADATA_LIST, Collections.singletonList(new Metadata(0, MetaType1_9.Byte, (byte) 0))); wrapper.write(Types1_9.METADATA_LIST, Collections.singletonList(new Metadata(0, MetaType1_9.Byte, (byte) 0)));

View File

@ -38,7 +38,7 @@ public class BungeeMovementTransmitter extends MovementTransmitterProvider {
public void sendPlayer(UserConnection userConnection) { public void sendPlayer(UserConnection userConnection) {
if (userConnection.getProtocolInfo().getState() == State.PLAY) { 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()); wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround());
try { try {
wrapper.sendToServer(Protocol1_9To1_8.class); wrapper.sendToServer(Protocol1_9To1_8.class);

View File

@ -17,26 +17,27 @@
*/ */
package com.viaversion.viaversion; 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.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.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.ViaInjector;
import com.viaversion.viaversion.api.platform.ViaPlatform; import com.viaversion.viaversion.api.platform.ViaPlatform;
import com.viaversion.viaversion.api.platform.ViaPlatformLoader; import com.viaversion.viaversion.api.platform.ViaPlatformLoader;
import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.ProtocolManager; 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.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion; 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.ServerProtocolVersionRange;
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton; 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_13to1_12_2.TabCompleteThread;
import com.viaversion.viaversion.protocols.protocol1_9to1_8.ViaIdleThread; import com.viaversion.viaversion.protocols.protocol1_9to1_8.ViaIdleThread;
import com.viaversion.viaversion.update.UpdateUtil; 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.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -46,7 +47,7 @@ import java.util.Set;
public class ViaManagerImpl implements ViaManager { public class ViaManagerImpl implements ViaManager {
private final ProtocolManagerImpl protocolManager = new ProtocolManagerImpl(); 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 ViaProviders providers = new ViaProviders();
private final ViaPlatform<?> platform; private final ViaPlatform<?> platform;
private final ViaInjector injector; private final ViaInjector injector;
@ -237,7 +238,7 @@ public class ViaManagerImpl implements ViaManager {
} }
@Override @Override
public ViaConnectionManager getConnectionManager() { public ConnectionManager getConnectionManager() {
return connectionManager; return connectionManager;
} }

View File

@ -226,7 +226,7 @@ public abstract class CommonBoss<T> extends BossBar<T> {
private PacketWrapper getPacket(UpdateAction action, UserConnection connection) { private PacketWrapper getPacket(UpdateAction action, UserConnection connection) {
try { 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.UUID, uuid);
wrapper.write(Type.VAR_INT, action.getId()); wrapper.write(Type.VAR_INT, action.getId());
switch (action) { switch (action) {

View File

@ -20,9 +20,11 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. * SOFTWARE.
*/ */
package com.viaversion.viaversion.api.connection; package com.viaversion.viaversion.connection;
import com.viaversion.viaversion.api.Via; 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 io.netty.channel.ChannelFutureListener;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -33,13 +35,11 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
/** public class ConnectionManagerImpl implements ConnectionManager {
* Handles injected UserConnections
*/
public class ViaConnectionManager {
protected final Map<UUID, UserConnection> clients = new ConcurrentHashMap<>(); protected final Map<UUID, UserConnection> clients = new ConcurrentHashMap<>();
protected final Set<UserConnection> connections = Collections.newSetFromMap(new ConcurrentHashMap<>()); protected final Set<UserConnection> connections = Collections.newSetFromMap(new ConcurrentHashMap<>());
@Override
public void onLoginSuccess(UserConnection connection) { public void onLoginSuccess(UserConnection connection) {
Objects.requireNonNull(connection, "connection is null!"); Objects.requireNonNull(connection, "connection is null!");
connections.add(connection); connections.add(connection);
@ -56,6 +56,7 @@ public class ViaConnectionManager {
} }
} }
@Override
public void onDisconnect(UserConnection connection) { public void onDisconnect(UserConnection connection) {
Objects.requireNonNull(connection, "connection is null!"); Objects.requireNonNull(connection, "connection is null!");
connections.remove(connection); connections.remove(connection);
@ -66,74 +67,39 @@ public class ViaConnectionManager {
} }
} }
/** @Override
* Frontend connections will have the UUID stored. Override this if your platform isn't always frontend. public boolean isFrontEnd(UserConnection connection) {
* UUIDs can't be duplicate between frontend connections. return !connection.isClientSide();
*/
public boolean isFrontEnd(UserConnection conn) {
return !conn.isClientSide();
} }
/** @Override
* 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.
*/
public Map<UUID, UserConnection> getConnectedClients() { public Map<UUID, UserConnection> getConnectedClients() {
return Collections.unmodifiableMap(clients); return Collections.unmodifiableMap(clients);
} }
/** @Override
* 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.
* <p>
* Note that connections are removed as soon as their channel is closed,
* so avoid using this method during player quits for example.
*/
public @Nullable UserConnection getConnectedClient(UUID clientIdentifier) { public @Nullable UserConnection getConnectedClient(UUID clientIdentifier) {
return clients.get(clientIdentifier); return clients.get(clientIdentifier);
} }
/** @Override
* Returns the UUID from the frontend connection to this proxy server public @Nullable UUID getConnectedClientId(UserConnection connection) {
* Returns null when there isn't a server or this connection isn't frontend or it doesn't have an id if (connection.getProtocolInfo() == null) return null;
* When ViaVersion is reloaded, this method may not return some players. UUID uuid = connection.getProtocolInfo().getUuid();
* May not return ProtocolSupport players.
* <p>
* 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();
UserConnection client = clients.get(uuid); UserConnection client = clients.get(uuid);
if (conn.equals(client)) { if (connection.equals(client)) {
// This is frontend // This is frontend
return uuid; return uuid;
} }
return null; return null;
} }
/** @Override
* 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.
*/
public Set<UserConnection> getConnections() { public Set<UserConnection> getConnections() {
return Collections.unmodifiableSet(connections); return Collections.unmodifiableSet(connections);
} }
/** @Override
* Returns if Via injected into this player connection.
*
* @param playerId player uuid
* @return true if the player is handled by Via
*/
public boolean isClientConnected(UUID playerId) { public boolean isClientConnected(UUID playerId) {
return clients.containsKey(playerId); return clients.containsKey(playerId);
} }

View File

@ -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 +
'}';
}
}

View File

@ -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<Class<?>, StoredObject> storedObjects = new ConcurrentHashMap<>();
private final PacketTracker packetTracker = new PacketTracker(this);
private final Set<UUID> passthroughTokens = Collections.newSetFromMap(CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.SECONDS)
.<UUID, Boolean>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 extends StoredObject> T get(Class<T> objectClass) {
return (T) storedObjects.get(objectClass);
}
@Override
public boolean has(Class<? extends StoredObject> 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<Throwable, Exception> cancelSupplier) throws Exception {
if (!buf.isReadable()) return;
transform(buf, clientSide ? Direction.INCOMING : Direction.OUTGOING, cancelSupplier);
}
@Override
public void transformIncoming(ByteBuf buf, Function<Throwable, Exception> cancelSupplier) throws Exception {
if (!buf.isReadable()) return;
transform(buf, clientSide ? Direction.OUTGOING : Direction.INCOMING, cancelSupplier);
}
private void transform(ByteBuf buf, Direction direction, Function<Throwable, Exception> 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<Class<?>, 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);
}
}

View File

@ -21,18 +21,17 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.google.common.collect.Range; import com.google.common.collect.Range;
import com.google.common.util.concurrent.ThreadFactoryBuilder; 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.ProtocolManager;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.ProtocolPathKey; 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.ProtocolVersion;
import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ServerProtocolVersion;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import com.viaversion.viaversion.protocol.packet.PacketWrapperImpl;
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.protocols.base.BaseProtocol; import com.viaversion.viaversion.protocols.base.BaseProtocol;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_16; import com.viaversion.viaversion.protocols.base.BaseProtocol1_16;
import com.viaversion.viaversion.protocols.base.BaseProtocol1_7; 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_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_8.Protocol1_9To1_8;
import com.viaversion.viaversion.protocols.protocol1_9to1_9_1.Protocol1_9To1_9_1; 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.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -288,8 +292,8 @@ public class ProtocolManagerImpl implements ProtocolManager {
} }
@Override @Override
public @Nullable Protocol getProtocol(Class<? extends Protocol> protocolClass) { public @Nullable <T extends Protocol> T getProtocol(Class<T> protocolClass) {
return protocols.get(protocolClass); return (T) protocols.get(protocolClass);
} }
@Override @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. * Called when the server is enabled, to register any non-registered listeners.
*/ */

View File

@ -17,8 +17,8 @@
*/ */
package com.viaversion.viaversion.protocol; 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.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.base.Protocol;
public class ProtocolPathEntryImpl implements ProtocolPathEntry { public class ProtocolPathEntryImpl implements ProtocolPathEntry {
private final int outputProtocolVersion; private final int outputProtocolVersion;

View File

@ -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<Protocol> 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<Protocol> 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<Protocol> 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<? extends Protocol> pipeClass) {
for (Protocol protocol : protocolList) {
if (protocol.getClass().equals(pipeClass)) return true;
}
return false;
}
@Override
public @Nullable <P extends Protocol> P getProtocol(Class<P> 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<Protocol> pipes() {
return protocolList;
}
@Override
public void cleanPipes() {
pipes().clear();
registerPackets();
}
}

View File

@ -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<Pair<Type, Object>> readableObjects = new ArrayDeque<>();
private final List<Pair<Type, Object>> packetValues = new ArrayList<>();
public PacketWrapperImpl(int packetID, ByteBuf inputBuffer, UserConnection userConnection) {
this.id = packetID;
this.inputBuffer = inputBuffer;
this.userConnection = userConnection;
}
@Override
public <T> T get(Type<T> type, int index) throws Exception {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
return (T) packetValue.getValue();
}
currentIndex++;
}
}
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<Type, Object> 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<Type, Object> packetValue : readableObjects) {
if (packetValue.getKey().getBaseClass() == type.getBaseClass()) { // Ref check
if (currentIndex == index) {
return true;
}
currentIndex++;
}
}
return false;
}
@Override
public <T> void set(Type<T> type, int index, T value) throws Exception {
int currentIndex = 0;
for (Pair<Type, Object> packetValue : packetValues) {
if (packetValue.getKey() == type) { // Ref check
if (currentIndex == index) {
packetValue.setValue(value);
return;
}
currentIndex++;
}
}
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> T read(Type<T> 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<Type, Object> read = readableObjects.poll();
Type rtype = read.getKey();
if (rtype.equals(type)
|| (type.getBaseClass().equals(rtype.getBaseClass())
&& type.getOutputClass().equals(rtype.getOutputClass()))) {
return (T) read.getValue();
} else {
if (rtype == Type.NOTHING) {
return read(type); // retry
} else {
Exception e = new IOException("Unable to read type " + type.getTypeName() + ", found " + read.getKey().getTypeName());
throw new InformativeException(e).set("Type", type.getTypeName()).set("Packet ID", getId()).set("Data", packetValues);
}
}
}
}
@Override
public <T> void write(Type<T> type, T value) {
if (value != null) {
if (!type.getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (type instanceof TypeConverter) {
value = (T) ((TypeConverter) type).from(value);
} else {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + type.getOutputClass());
}
}
}
packetValues.add(new Pair<>(type, value));
}
@Override
public <T> T passthrough(Type<T> 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<Type, Object> packetValue : packetValues) {
try {
Object value = packetValue.getValue();
if (value != null) {
if (!packetValue.getKey().getOutputClass().isAssignableFrom(value.getClass())) {
// attempt conversion
if (packetValue.getKey() instanceof TypeConverter) {
value = ((TypeConverter) packetValue.getKey()).from(value);
} else {
Via.getPlatform().getLogger().warning("Possible type mismatch: " + value.getClass().getName() + " -> " + packetValue.getKey().getOutputClass());
}
}
}
packetValue.getKey().write(buffer, value);
} 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<? extends Protocol> packetProtocol, boolean skipCurrentPipeline) throws Exception {
send(packetProtocol, skipCurrentPipeline, false);
}
@Override
public void send(Class<? extends Protocol> 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<? extends Protocol> 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<? extends Protocol> 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<Protocol> 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<Protocol> 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<? extends Protocol> 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 +
'}';
}
}

View File

@ -17,26 +17,26 @@
*/ */
package com.viaversion.viaversion.protocols.base; 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.Via;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.platform.providers.ViaProviders; import com.viaversion.viaversion.api.platform.providers.ViaProviders;
import com.viaversion.viaversion.api.protocol.Protocol; import com.viaversion.viaversion.api.protocol.AbstractSimpleProtocol;
import com.viaversion.viaversion.api.connection.ProtocolInfo;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.ProtocolPipeline; import com.viaversion.viaversion.api.protocol.ProtocolPipeline;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.protocol.base.Protocol;
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.packet.Direction; 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.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.ArrayList;
import java.util.List; import java.util.List;
public class BaseProtocol extends SimpleProtocol { public class BaseProtocol extends AbstractSimpleProtocol {
@Override @Override
protected void registerPackets() { protected void registerPackets() {

View File

@ -30,7 +30,7 @@ import com.viaversion.viaversion.protocol.ProtocolManagerImpl;
import com.viaversion.viaversion.api.protocol.ProtocolPathEntry; import com.viaversion.viaversion.api.protocol.ProtocolPathEntry;
import com.viaversion.viaversion.api.protocol.version.ProtocolVersion; import com.viaversion.viaversion.api.protocol.version.ProtocolVersion;
import com.viaversion.viaversion.protocol.ServerProtocolVersionSingleton; 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.PacketHandler;
import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper; import com.viaversion.viaversion.api.protocol.remapper.PacketRemapper;
import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.Type;
@ -43,7 +43,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
public class BaseProtocol1_7 extends SimpleProtocol { public class BaseProtocol1_7 extends AbstractSimpleProtocol {
@Override @Override
protected void registerPackets() { protected void registerPackets() {
@ -185,7 +185,7 @@ public class BaseProtocol1_7 extends SimpleProtocol {
if (!wrapper.user().getChannel().isOpen()) return; if (!wrapper.user().getChannel().isOpen()) return;
if (!wrapper.user().shouldApplyBlockProtocol()) 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())); Protocol1_9To1_8.FIX_JSON.write(disconnectPacket, ChatColorUtil.translateAlternateColorCodes(Via.getConfig().getBlockedDisconnectMsg()));
wrapper.cancel(); // cancel current wrapper.cancel(); // cancel current

View File

@ -129,7 +129,7 @@ public class MetadataRewriter1_11To1_10 extends MetadataRewriter {
tracker.addHologram(entityId); tracker.addHologram(entityId);
try { try {
// Send movement // 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.VAR_INT, entityId);
wrapper.write(Type.SHORT, (short) 0); wrapper.write(Type.SHORT, (short) 0);
wrapper.write(Type.SHORT, (short) (128D * (-Via.getConfig().getHologramYOffset() * 32D))); wrapper.write(Type.SHORT, (short) (128D * (-Via.getConfig().getHologramYOffset() * 32D)));

View File

@ -62,7 +62,7 @@ public class ConnectionData {
if (handler == null) continue; if (handler == null) continue;
int newBlockState = handler.connect(user, pos, blockState); 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.POSITION, pos);
blockUpdatePacket.write(Type.VAR_INT, newBlockState); blockUpdatePacket.write(Type.VAR_INT, newBlockState);
try { try {
@ -135,7 +135,7 @@ public class ConnectionData {
} }
if (!updates.isEmpty()) { 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, chunkX + chunkDeltaX);
wrapper.write(Type.INT, chunkZ + chunkDeltaZ); wrapper.write(Type.INT, chunkZ + chunkDeltaZ);
wrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, updates.toArray(EMPTY_RECORDS)); wrapper.write(Type.BLOCK_CHANGE_RECORD_ARRAY, updates.toArray(EMPTY_RECORDS));

View File

@ -81,7 +81,7 @@ public class BlockEntityProvider implements Provider {
} }
private void sendBlockChange(UserConnection user, Position position, int blockId) throws Exception { 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.POSITION, position);
wrapper.write(Type.VAR_INT, blockId); wrapper.write(Type.VAR_INT, blockId);

View File

@ -35,7 +35,7 @@ public class TabCompleteTracker extends StoredObject {
public void sendPacketToServer() { public void sendPacketToServer() {
if (lastTabComplete == null || timeToSend > System.currentTimeMillis()) return; 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.STRING, lastTabComplete);
wrapper.write(Type.BOOLEAN, false); wrapper.write(Type.BOOLEAN, false);
wrapper.write(Type.OPTIONAL_POSITION, null); wrapper.write(Type.OPTIONAL_POSITION, null);

View File

@ -130,7 +130,7 @@ public class MetadataRewriter1_14To1_13_2 extends MetadataRewriter {
armorItem = new Item(protocol.getMappingData().getNewItemId(729), (byte) 1, (short) 0, null); 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, entityId);
equipmentPacket.write(Type.VAR_INT, 4); equipmentPacket.write(Type.VAR_INT, 4);
equipmentPacket.write(Type.FLAT_VAR_INT_ITEM, armorItem); equipmentPacket.write(Type.FLAT_VAR_INT_ITEM, armorItem);

View File

@ -94,7 +94,7 @@ public class EntityTracker1_14 extends EntityTracker {
public void onExternalJoinGame(int playerEntityId) { public void onExternalJoinGame(int playerEntityId) {
super.onExternalJoinGame(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); setViewDistance.write(Type.VAR_INT, WorldPackets.SERVERSIDE_VIEW_DISTANCE);
try { try {
setViewDistance.send(Protocol1_14To1_13_2.class, true, true); setViewDistance.send(Protocol1_14To1_13_2.class, true, true);

View File

@ -75,7 +75,7 @@ public class BlockEntity {
} }
private static void updateBlockEntity(Position pos, short id, CompoundTag tag, UserConnection connection) throws Exception { 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.POSITION, pos);
wrapper.write(Type.UNSIGNED_BYTE, id); wrapper.write(Type.UNSIGNED_BYTE, id);
wrapper.write(Type.NBT, tag); wrapper.write(Type.NBT, tag);

View File

@ -154,7 +154,7 @@ public class Protocol1_9To1_8 extends Protocol<ClientboundPackets1_8, Clientboun
} }
@Override @Override
protected void filterPacket(UserConnection info, Object packet, List output) throws Exception { public void filterPacket(UserConnection info, Object packet, List output) throws Exception {
output.addAll(info.get(ClientChunks.class).transformMapChunkBulk(packet)); output.addAll(info.get(ClientChunks.class).transformMapChunkBulk(packet));
} }

View File

@ -306,7 +306,7 @@ public class SpawnPackets {
public void handle(PacketWrapper wrapper) throws Exception { public void handle(PacketWrapper wrapper) throws Exception {
short item = wrapper.read(Type.SHORT); short item = wrapper.read(Type.SHORT);
if (item != 0) { if (item != 0) {
PacketWrapper packet = new PacketWrapper(0x3C, null, wrapper.user()); PacketWrapper packet = PacketWrapper.create(0x3C, null, wrapper.user());
packet.write(Type.VAR_INT, wrapper.get(Type.VAR_INT, 0)); packet.write(Type.VAR_INT, wrapper.get(Type.VAR_INT, 0));
packet.write(Type.VAR_INT, 0); packet.write(Type.VAR_INT, 0);
packet.write(Type.ITEM, new Item(item, (byte) 1, (short) 0, null)); packet.write(Type.ITEM, new Item(item, (byte) 1, (short) 0, null));

View File

@ -176,7 +176,7 @@ public class WorldPackets {
try { try {
output.setId(-1); // -1 for no writing of id output.setId(-1); // -1 for no writing of id
output.writeToBuffer(buffer); output.writeToBuffer(buffer);
PacketWrapper chunkPacket = new PacketWrapper(0x21, buffer, wrapper.user()); PacketWrapper chunkPacket = PacketWrapper.create(0x21, buffer, wrapper.user());
chunkPacket.send(Protocol1_9To1_8.class, false, true); chunkPacket.send(Protocol1_9To1_8.class, false, true);
} finally { } finally {
buffer.release(); buffer.release();
@ -414,7 +414,7 @@ public class WorldPackets {
Optional<CompoundTag> tag = provider.get(wrapper.user(), pos); Optional<CompoundTag> tag = provider.get(wrapper.user(), pos);
// Send the Update Block Entity packet if present // Send the Update Block Entity packet if present
if (tag.isPresent()) { 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.POSITION, pos);
updateBlockEntity.write(Type.UNSIGNED_BYTE, (short) 2); updateBlockEntity.write(Type.UNSIGNED_BYTE, (short) 2);

View File

@ -55,7 +55,7 @@ public class BulkChunkTranslatorProvider implements Provider {
meta.setData(wrapper.read(customByteType)); meta.setData(wrapper.read(customByteType));
// Construct chunk packet // 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.getX());
chunkPacket.write(Type.INT, meta.getZ()); chunkPacket.write(Type.INT, meta.getZ());
chunkPacket.write(Type.BOOLEAN, true); // Always ground-up chunkPacket.write(Type.BOOLEAN, true); // Always ground-up

View File

@ -57,7 +57,7 @@ public class CommandBlockProvider implements Provider {
public void sendPermission(UserConnection user) throws Exception { public void sendPermission(UserConnection user) throws Exception {
if (!isEnabled()) if (!isEnabled())
return; 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.INT, user.get(EntityTracker1_9.class).getProvidedEntityId()); // Entity ID
wrapper.write(Type.BYTE, (byte) 26); // Hardcoded op permission level wrapper.write(Type.BYTE, (byte) 26); // Hardcoded op permission level

View File

@ -88,7 +88,7 @@ public class EntityTracker1_9 extends EntityTracker {
} }
public void setSecondHand(int entityID, Item item) { 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, entityID);
wrapper.write(Type.VAR_INT, 1); // slot wrapper.write(Type.VAR_INT, 1); // slot
wrapper.write(Type.ITEM, this.itemInSecondHand = item); wrapper.write(Type.ITEM, this.itemInSecondHand = item);
@ -232,7 +232,7 @@ public class EntityTracker1_9 extends EntityTracker {
knownHolograms.add(entityId); knownHolograms.add(entityId);
try { try {
// Send movement // 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.VAR_INT, entityId);
wrapper.write(Type.SHORT, (short) 0); wrapper.write(Type.SHORT, (short) 0);
wrapper.write(Type.SHORT, (short) (128D * (Via.getConfig().getHologramYOffset() * 32D))); 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) { 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 wrapper.write(Type.STRING, "viaversion"); // Use viaversion as name
if (add) { if (add) {
// add // add
@ -334,7 +334,7 @@ public class EntityTracker1_9 extends EntityTracker {
public void sendMetadataBuffer(int entityId) { public void sendMetadataBuffer(int entityId) {
List<Metadata> metadataList = metadataBuffer.get(entityId); List<Metadata> metadataList = metadataBuffer.get(entityId);
if (metadataList != null) { 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(Type.VAR_INT, entityId);
wrapper.write(Types1_9.METADATA_LIST, metadataList); wrapper.write(Types1_9.METADATA_LIST, metadataList);
getUser().getProtocolInfo().getPipeline().getProtocol(Protocol1_9To1_8.class).get(MetadataRewriter1_9To1_8.class) getUser().getProtocolInfo().getPipeline().getProtocol(Protocol1_9To1_8.class).get(MetadataRewriter1_9To1_8.class)

View File

@ -60,7 +60,7 @@ public class Sponge4ArmorListener extends ViaListener {
armor += calculate(player.getLeggings()); armor += calculate(player.getLeggings());
armor += calculate(player.getBoots()); armor += calculate(player.getBoots());
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player.getUniqueId())); PacketWrapper wrapper = PacketWrapper.create(0x4B, null, getUserConnection(player.getUniqueId()));
try { try {
wrapper.write(Type.VAR_INT, getEntityId(player)); // Player ID wrapper.write(Type.VAR_INT, getEntityId(player)); // Player ID
wrapper.write(Type.INT, 1); // only 1 property wrapper.write(Type.INT, 1); // only 1 property

View File

@ -17,6 +17,8 @@
*/ */
package com.viaversion.viaversion.sponge.handlers; 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.Channel;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
@ -24,7 +26,6 @@ import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder; import io.netty.handler.codec.MessageToByteEncoder;
import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.ProtocolPipeline;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -49,9 +50,9 @@ public class SpongeChannelInitializer extends ChannelInitializer<Channel> {
// Ensure ViaVersion is loaded // Ensure ViaVersion is loaded
if (Via.getAPI().getServerVersion().isKnown() if (Via.getAPI().getServerVersion().isKnown()
&& channel instanceof SocketChannel) { // channel can be LocalChannel on internal server && channel instanceof SocketChannel) { // channel can be LocalChannel on internal server
UserConnection info = new UserConnection((SocketChannel) channel); UserConnection info = new UserConnectionImpl((SocketChannel) channel);
// init protocol // init protocol
new ProtocolPipeline(info); new ProtocolPipelineImpl(info);
// Add originals // Add originals
this.method.invoke(this.original, channel); this.method.invoke(this.original, channel);
// Add our transformers // Add our transformers

View File

@ -64,7 +64,7 @@ public class DeathListener extends ViaSpongeListener {
Via.getPlatform().runSync(new Runnable() { Via.getPlatform().runSync(new Runnable() {
@Override @Override
public void run() { public void run() {
PacketWrapper wrapper = new PacketWrapper(0x2C, null, getUserConnection(p.getUniqueId())); PacketWrapper wrapper = PacketWrapper.create(0x2C, null, getUserConnection(p.getUniqueId()));
try { try {
int entityId = getEntityId(p); int entityId = getEntityId(p);
wrapper.write(Type.VAR_INT, 2); // Event - Entity dead wrapper.write(Type.VAR_INT, 2); // Event - Entity dead

View File

@ -58,7 +58,7 @@ public class Sponge5ArmorListener extends ViaSpongeListener {
armor += calculate(player.getLeggings()); armor += calculate(player.getLeggings());
armor += calculate(player.getBoots()); armor += calculate(player.getBoots());
PacketWrapper wrapper = new PacketWrapper(0x4B, null, getUserConnection(player.getUniqueId())); PacketWrapper wrapper = PacketWrapper.create(0x4B, null, getUserConnection(player.getUniqueId()));
try { try {
wrapper.write(Type.VAR_INT, getEntityId(player)); // Player ID wrapper.write(Type.VAR_INT, getEntityId(player)); // Player ID
wrapper.write(Type.INT, 1); // only 1 property wrapper.write(Type.INT, 1); // only 1 property

View File

@ -17,10 +17,11 @@
*/ */
package com.viaversion.viaversion.velocity.handlers; 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.Channel;
import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelInitializer;
import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.protocol.ProtocolPipeline;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -47,8 +48,8 @@ public class VelocityChannelInitializer extends ChannelInitializer<Channel> {
protected void initChannel(Channel channel) throws Exception { protected void initChannel(Channel channel) throws Exception {
initChannel.invoke(original, channel); initChannel.invoke(original, channel);
UserConnection user = new UserConnection(channel, clientSide); UserConnection user = new UserConnectionImpl(channel, clientSide);
new ProtocolPipeline(user); new ProtocolPipelineImpl(user);
// We need to add a separated handler because Velocity uses pipeline().get(MINECRAFT_DECODER) // We need to add a separated handler because Velocity uses pipeline().get(MINECRAFT_DECODER)
channel.pipeline().addBefore("minecraft-encoder", "via-encoder", new VelocityEncodeHandler(user)); channel.pipeline().addBefore("minecraft-encoder", "via-encoder", new VelocityEncodeHandler(user));

View File

@ -38,7 +38,7 @@ public class VelocityMovementTransmitter extends MovementTransmitterProvider {
public void sendPlayer(UserConnection userConnection) { public void sendPlayer(UserConnection userConnection) {
if (userConnection.getProtocolInfo().getState() == State.PLAY) { 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()); wrapper.write(Type.BOOLEAN, userConnection.get(MovementTracker.class).isGround());
try { try {
wrapper.sendToServer(Protocol1_9To1_8.class); wrapper.sendToServer(Protocol1_9To1_8.class);