Move packet tracking methods out of UserConnectionn

This commit is contained in:
KennyTV 2021-04-20 13:19:34 +02:00
parent 2c884dc241
commit 144c24c276
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
11 changed files with 271 additions and 178 deletions

View File

@ -64,8 +64,6 @@ Please note the [differences in licensing](#license).
Building:
--------
You need JDK 9 or higher to build ViaVersion. The plugin works on Java 8, but needs to be compiled with a higher version for compatibility reasons.
After cloning this repository, build the project with Gradle by running `/gradlew build` and take the created jar out of
the `build/libs` directory.

View File

@ -0,0 +1,176 @@
/*
* 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 us.myles.ViaVersion.api.data;
import org.checkerframework.checker.nullness.qual.Nullable;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.ViaVersionConfig;
public class PacketTracker {
private final UserConnection connection;
private Object lastPacket;
private long sentPackets;
private long receivedPackets;
// Used for tracking pps
private long startTime;
private long intervalPackets;
private long packetsPerSecond = -1L;
// Used for handling warnings (over time)
private int secondsObserved;
private int warnings;
public PacketTracker(UserConnection connection) {
this.connection = connection;
}
/**
* Used for incrementing the number of packets sent to the client.
*/
public void incrementSent() {
this.sentPackets++;
}
/**
* Used for incrementing the number of packets received from the client.
*
* @return true if the interval has reset and can now be checked for the packets sent
*/
public boolean incrementReceived() {
// handle stats
long diff = System.currentTimeMillis() - startTime;
if (diff >= 1000) {
packetsPerSecond = intervalPackets;
startTime = System.currentTimeMillis();
intervalPackets = 1;
return true;
} else {
intervalPackets++;
}
// increase total
this.receivedPackets++;
return false;
}
/**
* Checks for packet flood with the packets sent in the last second.
* ALWAYS check for {@link #incrementReceived()} before using this method.
*
* @return true if the packet should be cancelled
* @see #incrementReceived()
*/
public boolean exceedsMaxPPS() {
if (connection.isClientSide()) return false; // Don't apply PPS limiting for client-side
ViaVersionConfig conf = Via.getConfig();
// Max PPS Checker
if (conf.getMaxPPS() > 0) {
if (packetsPerSecond >= conf.getMaxPPS()) {
connection.disconnect(conf.getMaxPPSKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
}
// Tracking PPS Checker
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
if (secondsObserved > conf.getTrackingPeriod()) {
// Reset
warnings = 0;
secondsObserved = 1;
} else {
secondsObserved++;
if (packetsPerSecond >= conf.getWarningPPS()) {
warnings++;
}
if (warnings >= conf.getMaxWarnings()) {
connection.disconnect(conf.getMaxWarningsKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
}
}
return false;
}
public @Nullable Object getLastPacket() {
return lastPacket;
}
public void setLastPacket(Object lastPacket) {
this.lastPacket = lastPacket;
}
public long getSentPackets() {
return sentPackets;
}
public void setSentPackets(long sentPackets) {
this.sentPackets = sentPackets;
}
public long getReceivedPackets() {
return receivedPackets;
}
public void setReceivedPackets(long receivedPackets) {
this.receivedPackets = receivedPackets;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getIntervalPackets() {
return intervalPackets;
}
public void setIntervalPackets(long intervalPackets) {
this.intervalPackets = intervalPackets;
}
public long getPacketsPerSecond() {
return packetsPerSecond;
}
public void setPacketsPerSecond(long packetsPerSecond) {
this.packetsPerSecond = packetsPerSecond;
}
public int getSecondsObserved() {
return secondsObserved;
}
public void setSecondsObserved(int secondsObserved) {
this.secondsObserved = secondsObserved;
}
public int getWarnings() {
return warnings;
}
public void setWarnings(int warnings) {
this.warnings = warnings;
}
}

View File

@ -51,25 +51,16 @@ import java.util.function.Function;
public class UserConnection {
private static final AtomicLong IDS = new AtomicLong();
private final long id = IDS.incrementAndGet();
private final Channel channel;
private final boolean clientSide;
Map<Class<?>, StoredObject> storedObjects = new ConcurrentHashMap<>();
private ProtocolInfo protocolInfo;
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;
private Object lastPacket;
private long sentPackets;
private long receivedPackets;
// Used for tracking pps
private long startTime;
private long intervalPackets;
private long packetsPerSecond = -1L;
// Used for handling warnings (over time)
private int secondsObserved;
private int warnings;
/**
* Creates an UserConnection. When it's a client-side connection, some method behaviors are modified.
@ -188,70 +179,12 @@ public class UserConnection {
}
/**
* Used for incrementing the number of packets sent to the client.
*/
public void incrementSent() {
this.sentPackets++;
}
/**
* Used for incrementing the number of packets received from the client.
* Returns the user's packet tracker used for the inbuilt packet-limiter.
*
* @return true if the interval has reset and can now be checked for the packets sent
* @return packet tracker
*/
public boolean incrementReceived() {
// handle stats
long diff = System.currentTimeMillis() - startTime;
if (diff >= 1000) {
packetsPerSecond = intervalPackets;
startTime = System.currentTimeMillis();
intervalPackets = 1;
return true;
} else {
intervalPackets++;
}
// increase total
this.receivedPackets++;
return false;
}
/**
* Checks for packet flood with the packets sent in the last second.
* ALWAYS check for {@link #incrementReceived()} before using this method.
*
* @return true if the packet should be cancelled
* @see #incrementReceived()
*/
public boolean exceedsMaxPPS() {
if (clientSide) return false; // Don't apply PPS limiting for client-side
ViaVersionConfig conf = Via.getConfig();
// Max PPS Checker
if (conf.getMaxPPS() > 0) {
if (packetsPerSecond >= conf.getMaxPPS()) {
disconnect(conf.getMaxPPSKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
}
// Tracking PPS Checker
if (conf.getMaxWarnings() > 0 && conf.getTrackingPeriod() > 0) {
if (secondsObserved > conf.getTrackingPeriod()) {
// Reset
warnings = 0;
secondsObserved = 1;
} else {
secondsObserved++;
if (packetsPerSecond >= conf.getWarningPPS()) {
warnings++;
}
if (warnings >= conf.getMaxWarnings()) {
disconnect(conf.getMaxWarningsKickMessage().replace("%pps", Long.toString(packetsPerSecond)));
return true; // don't send current packet
}
}
}
return false;
public PacketTracker getPacketTracker() {
return packetTracker;
}
/**
@ -351,22 +284,22 @@ public class UserConnection {
*/
public boolean checkIncomingPacket() {
if (clientSide) {
return checkClientBound();
return checkClientbound();
} else {
return checkServerBound();
return checkServerbound();
}
}
private boolean checkClientBound() {
incrementSent();
private boolean checkClientbound() {
packetTracker.incrementSent();
return true;
}
private boolean checkServerBound() {
private boolean checkServerbound() {
// Ignore if pending disconnect
if (pendingDisconnect) return false;
// Increment received + Check PPS
return !incrementReceived() || !exceedsMaxPPS();
return !packetTracker.incrementReceived() || !packetTracker.exceedsMaxPPS();
}
/**
@ -376,9 +309,9 @@ public class UserConnection {
*/
public boolean checkOutgoingPacket() {
if (clientSide) {
return checkServerBound();
return checkServerbound();
} else {
return checkClientBound();
return checkClientbound();
}
}
@ -448,14 +381,29 @@ public class UserConnection {
}
}
/**
* Returns the internal id incremented for each new connection.
*
* @return internal id
*/
public long getId() {
return id;
}
/**
* Returns the netty channel if present.
*
* @return netty channel if present
*/
public @Nullable Channel getChannel() {
return channel;
}
/**
* Returns info containing the current protocol state and userdata.
*
* @return info containing the current protocol state and userdata
*/
public @Nullable ProtocolInfo getProtocolInfo() {
return protocolInfo;
}
@ -469,10 +417,23 @@ public class UserConnection {
}
}
/**
* Returns a map of stored objects.
*
* @return map of stored objects
* @see #has(Class)
* @see #get(Class)
* @see #put(StoredObject)
*/
public Map<Class<?>, StoredObject> getStoredObjects() {
return storedObjects;
}
/**
* Returns whether the connection has protocols other than the base protocol applied.
*
* @return whether the connection is active
*/
public boolean isActive() {
return active;
}
@ -481,6 +442,11 @@ public class UserConnection {
this.active = active;
}
/**
* Returns whether the connection is pending a disconnect, initiated through {@link #disconnect(String)}.
*
* @return whether the connection is pending a disconnect
*/
public boolean isPendingDisconnect() {
return pendingDisconnect;
}
@ -489,68 +455,34 @@ public class UserConnection {
this.pendingDisconnect = pendingDisconnect;
}
public @Nullable Object getLastPacket() {
return lastPacket;
/**
* Returns whether this is a client-side connection (a mod integrated into the client itself).
*
* @return whether this is a client-side connection
*/
public boolean isClientSide() {
return clientSide;
}
public void setLastPacket(@Nullable Object lastPacket) {
this.lastPacket = lastPacket;
/**
* Returns whether {@link ViaVersionConfig#getBlockedProtocols()} should be checked for this connection.
*
* @return whether blocked protocols should be applied
*/
public boolean shouldApplyBlockProtocol() {
return !clientSide; // Don't apply protocol blocking on client-side
}
public long getSentPackets() {
return sentPackets;
}
public void setSentPackets(long sentPackets) {
this.sentPackets = sentPackets;
}
public long getReceivedPackets() {
return receivedPackets;
}
public void setReceivedPackets(long receivedPackets) {
this.receivedPackets = receivedPackets;
}
public long getStartTime() {
return startTime;
}
public void setStartTime(long startTime) {
this.startTime = startTime;
}
public long getIntervalPackets() {
return intervalPackets;
}
public void setIntervalPackets(long intervalPackets) {
this.intervalPackets = intervalPackets;
}
public long getPacketsPerSecond() {
return packetsPerSecond;
}
public void setPacketsPerSecond(long packetsPerSecond) {
this.packetsPerSecond = packetsPerSecond;
}
public int getSecondsObserved() {
return secondsObserved;
}
public void setSecondsObserved(int secondsObserved) {
this.secondsObserved = secondsObserved;
}
public int getWarnings() {
return warnings;
}
public void setWarnings(int warnings) {
this.warnings = warnings;
/**
* Returns a newly generated uuid that will let a packet be passed through without
* transformig its contents if used together with {@link PacketWrapper#PASSTHROUGH_ID}.
*
* @return generated passthrough token
*/
public UUID generatePassthroughToken() {
UUID token = UUID.randomUUID();
passthroughTokens.add(token);
return token;
}
@Override
@ -565,18 +497,4 @@ public class UserConnection {
public int hashCode() {
return Long.hashCode(id);
}
public boolean isClientSide() {
return clientSide;
}
public boolean shouldApplyBlockProtocol() {
return !clientSide; // Don't apply protocol blocking on client-side
}
public UUID generatePassthroughToken() {
UUID token = UUID.randomUUID();
passthroughTokens.add(token);
return token;
}
}

View File

@ -30,7 +30,6 @@ import us.myles.ViaVersion.api.ViaVersionConfig;
import us.myles.ViaVersion.api.command.ViaCommandSender;
import us.myles.ViaVersion.api.configuration.ConfigurationProvider;
import us.myles.ViaVersion.api.data.UserConnection;
import us.myles.ViaVersion.protocols.base.ProtocolInfo;
import us.myles.ViaVersion.util.UnsupportedSoftware;
import java.io.File;
@ -159,7 +158,7 @@ public interface ViaPlatform<T> {
*/
default boolean disconnect(UserConnection connection, String message) {
if (connection.isClientSide()) return false;
UUID uuid = connection.get(ProtocolInfo.class).getUuid();
UUID uuid = connection.getProtocolInfo().getUuid();
if (uuid == null) return false;
return kickPlayer(uuid, message);
}

View File

@ -37,7 +37,7 @@ public class BukkitPacketHandler extends MessageToMessageEncoder {
// This will prevent issues with several plugins and other protocol handlers due to the chunks being sent twice.
// It also sends the chunks in the right order possible resolving some issues with added chunks/block/entity data.
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
info.getPacketTracker().setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at packet level :) */
if (info.isActive()) {
if (info.getProtocolInfo().getPipeline().filter(o, list)) {

View File

@ -55,13 +55,13 @@ public class PPSSubCmd extends ViaSubCommand {
for (ViaCommandSender p : Via.getPlatform().getOnlinePlayers()) {
int playerVersion = Via.getAPI().getPlayerVersion(p.getUUID());
if (!playerVersions.containsKey(playerVersion))
playerVersions.put(playerVersion, new HashSet<String>());
playerVersions.put(playerVersion, new HashSet<>());
UserConnection uc = Via.getManager().getConnectionManager().getConnectedClient(p.getUUID());
if (uc != null && uc.getPacketsPerSecond() > -1) {
playerVersions.get(playerVersion).add(p.getName() + " (" + uc.getPacketsPerSecond() + " PPS)");
totalPackets += uc.getPacketsPerSecond();
if (uc.getPacketsPerSecond() > max) {
max = uc.getPacketsPerSecond();
if (uc != null && uc.getPacketTracker().getPacketsPerSecond() > -1) {
playerVersions.get(playerVersion).add(p.getName() + " (" + uc.getPacketTracker().getPacketsPerSecond() + " PPS)");
totalPackets += uc.getPacketTracker().getPacketsPerSecond();
if (uc.getPacketTracker().getPacketsPerSecond() > max) {
max = uc.getPacketTracker().getPacketsPerSecond();
}
clients++;
}

View File

@ -17,7 +17,6 @@
*/
package us.myles.ViaVersion.protocols.protocol1_17to1_16_4;
import org.checkerframework.checker.nullness.qual.Nullable;
import us.myles.ViaVersion.api.Via;
import us.myles.ViaVersion.api.data.MappingData;
import us.myles.ViaVersion.api.data.UserConnection;
@ -230,7 +229,7 @@ public class Protocol1_17To1_16_4 extends Protocol<ClientboundPackets1_16_2, Cli
}
@Override
public @Nullable MappingData getMappingData() {
public MappingData getMappingData() {
return MAPPINGS;
}
}

View File

@ -34,7 +34,7 @@ import java.util.UUID;
public class UpdateUtil {
public static final String PREFIX = "§a§l[ViaVersion] §a";
private static final String PREFIX = "§a§l[ViaVersion] §a";
private static final String URL = "https://api.spiget.org/v2/resources/";
private static final int PLUGIN = 19254;
private static final String LATEST_VERSION = "/versions/latest";
@ -76,10 +76,11 @@ public class UpdateUtil {
return "You are using a custom version, consider updating.";
}
Version newest = new Version(newestString);
if (current.compareTo(newest) < 0)
return "There is a newer plugin version available: " + newest.toString() + ", you're on: " + current.toString();
else if (console && current.compareTo(newest) != 0) {
if (current.getTag().toLowerCase(Locale.ROOT).startsWith("dev") || current.getTag().toLowerCase(Locale.ROOT).startsWith("snapshot")) {
if (current.compareTo(newest) < 0) {
return "There is a newer plugin version available: " + newest + ", you're on: " + current;
} else if (console && current.compareTo(newest) != 0) {
String tag = current.getTag().toLowerCase(Locale.ROOT);
if (tag.startsWith("dev") || tag.startsWith("snapshot")) {
return "You are running a development version of the plugin, please report any bugs to GitHub.";
} else {
return "You are running a newer version of the plugin than is released!";

View File

@ -45,6 +45,7 @@ import us.myles.ViaVersion.sponge.platform.SpongeViaConfig;
import us.myles.ViaVersion.sponge.platform.SpongeViaInjector;
import us.myles.ViaVersion.sponge.platform.SpongeViaLoader;
import us.myles.ViaVersion.sponge.util.LoggerWrapper;
import us.myles.ViaVersion.util.ChatColorUtil;
import us.myles.ViaVersion.util.GsonUtil;
import us.myles.ViaVersion.util.VersionInfo;
import us.myles.viaversion.libs.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
@ -70,7 +71,7 @@ public class SpongePlugin implements ViaPlatform<Player> {
@DefaultConfig(sharedRoot = false)
private File spongeConfig;
public static final LegacyComponentSerializer COMPONENT_SERIALIZER = LegacyComponentSerializer.builder().character('§').extractUrls().build();
public static final LegacyComponentSerializer COMPONENT_SERIALIZER = LegacyComponentSerializer.builder().character(ChatColorUtil.COLOR_CHAR).extractUrls().build();
private final SpongeViaAPI api = new SpongeViaAPI();
private SpongeViaConfig conf;
private Logger logger;
@ -192,7 +193,7 @@ public class SpongePlugin implements ViaPlatform<Player> {
@Override
public boolean kickPlayer(UUID uuid, String message) {
return game.getServer().getPlayer(uuid).map(player -> {
player.kick(TextSerializers.formattingCode('§').deserialize(message));
player.kick(TextSerializers.formattingCode(ChatColorUtil.COLOR_CHAR).deserialize(message));
return true;
}).orElse(false);
}

View File

@ -37,7 +37,7 @@ public class SpongePacketHandler extends MessageToMessageEncoder {
// This will prevent issues with several plugins and other protocol handlers due to the chunks being sent twice.
// It also sends the chunks in the right order possible resolving some issues with added chunks/block/entity data.
if (!(o instanceof ByteBuf)) {
info.setLastPacket(o);
info.getPacketTracker().setLastPacket(o);
/* This transformer is more for fixing issues which we find hard at packet level :) */
if (info.isActive()) {
if (info.getProtocolInfo().getPipeline().filter(o, list)) {

View File

@ -36,6 +36,7 @@ import us.myles.ViaVersion.api.data.MappingDataLoader;
import us.myles.ViaVersion.api.platform.TaskId;
import us.myles.ViaVersion.api.platform.ViaPlatform;
import us.myles.ViaVersion.dump.PluginInfo;
import us.myles.ViaVersion.util.ChatColorUtil;
import us.myles.ViaVersion.util.GsonUtil;
import us.myles.ViaVersion.util.VersionInfo;
import us.myles.ViaVersion.velocity.command.VelocityCommandHandler;
@ -64,7 +65,7 @@ import java.util.concurrent.TimeUnit;
url = "https://viaversion.com"
)
public class VelocityPlugin implements ViaPlatform<Player> {
public static final LegacyComponentSerializer COMPONENT_SERIALIZER = LegacyComponentSerializer.builder().character('§').extractUrls().build();
public static final LegacyComponentSerializer COMPONENT_SERIALIZER = LegacyComponentSerializer.builder().character(ChatColorUtil.COLOR_CHAR).extractUrls().build();
public static ProxyServer PROXY;
@Inject