Mirror von
https://github.com/ViaVersion/ViaVersion.git
synchronisiert 2024-11-19 14:30:16 +01:00
Create some fancy interfaces
Dieser Commit ist enthalten in:
Ursprung
49d386063d
Commit
30d122e7fa
@ -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> {
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
}
|
@ -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();
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -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 {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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 +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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());
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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)));
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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 +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)));
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
|
@ -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);
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren