diff --git a/Emulator/.idea/misc.xml b/Emulator/.idea/misc.xml index 749dacb..44185bb 100644 --- a/Emulator/.idea/misc.xml +++ b/Emulator/.idea/misc.xml @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/LatencyTracker.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/LatencyTracker.java new file mode 100644 index 0000000..43e1c55 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/LatencyTracker.java @@ -0,0 +1,47 @@ +package com.eu.habbo.habbohotel; + +import com.eu.habbo.habbohotel.gameclients.GameClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +public class LatencyTracker { + + private static final Logger LOGGER = LoggerFactory.getLogger(GameClient.class); + + private boolean initialPing; + + private long last; + private long average; + + public LatencyTracker() { + this.initialPing = true; + this.average = 0; + } + + public void update(long latencyInNano) { + this.last = latencyInNano; + + if (this.initialPing) { + this.initialPing = false; + this.average = latencyInNano; + return; + } + + this.average = (long) (this.average * .7f + latencyInNano * .3f); + } + + public boolean hasInitialized() { + return !this.initialPing; + } + + public long getLastMs() { + return TimeUnit.NANOSECONDS.toMillis(this.last); + } + + public long getAverageMs() { + return TimeUnit.NANOSECONDS.toMillis(this.average); + } + +} \ No newline at end of file diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java index b2f98f3..42e32d5 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/CommandHandler.java @@ -230,6 +230,7 @@ public class CommandHandler { addCommand(new MutePetsCommand()); addCommand(new PetInfoCommand()); addCommand(new PickallCommand()); + addCommand(new PingCommand()); addCommand(new PixelCommand()); addCommand(new PluginsCommand()); addCommand(new PointsCommand()); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/PingCommand.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/PingCommand.java new file mode 100644 index 0000000..5e1c0bd --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/commands/PingCommand.java @@ -0,0 +1,29 @@ +package com.eu.habbo.habbohotel.commands; + +import com.eu.habbo.habbohotel.LatencyTracker; +import com.eu.habbo.habbohotel.gameclients.GameClient; + +public class PingCommand extends Command { + public PingCommand() { + super(null, new String[]{"ping"}); + } + + @Override + public boolean handle(GameClient gameClient, String[] params) throws Exception { + if (gameClient.getHabbo().getRoomUnit() == null) { + return true; + } + + final LatencyTracker latencyTracker = gameClient.getLatencyTracker(); + + if (latencyTracker.hasInitialized()) { + gameClient.getHabbo().whisper(String.format("Average ping %dms, last ping %dms", + latencyTracker.getAverageMs(), + latencyTracker.getLastMs())); + } else { + gameClient.getHabbo().whisper("\n" + "Ping speed has not been calculated yet, please try again in a minute."); + } + + return true; + } +} \ No newline at end of file diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/gameclients/GameClient.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/gameclients/GameClient.java index a05ef0a..6c8d580 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/gameclients/GameClient.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/gameclients/GameClient.java @@ -2,6 +2,7 @@ package com.eu.habbo.habbohotel.gameclients; import com.eu.habbo.Emulator; import com.eu.habbo.crypto.HabboEncryption; +import com.eu.habbo.habbohotel.LatencyTracker; import com.eu.habbo.habbohotel.users.Habbo; import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.incoming.MessageHandler; @@ -10,9 +11,6 @@ import io.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; @@ -22,7 +20,7 @@ public class GameClient { private final Channel channel; private final HabboEncryption encryption; - + private final LatencyTracker latencyTracker; private Habbo habbo; private boolean handshakeFinished; private String machineId = ""; @@ -39,6 +37,7 @@ public class GameClient { Emulator.getCrypto().getModulus(), Emulator.getCrypto().getPrivateExponent()) : null; + this.latencyTracker = new LatencyTracker(); } public Channel getChannel() { @@ -49,6 +48,8 @@ public class GameClient { return encryption; } + public LatencyTracker getLatencyTracker() { return latencyTracker; } + public Habbo getHabbo() { return this.habbo; } diff --git a/Emulator/src/main/java/com/eu/habbo/networking/gameserver/handlers/IdleTimeoutHandler.java b/Emulator/src/main/java/com/eu/habbo/networking/gameserver/handlers/IdleTimeoutHandler.java index 26c5566..e17e2d9 100644 --- a/Emulator/src/main/java/com/eu/habbo/networking/gameserver/handlers/IdleTimeoutHandler.java +++ b/Emulator/src/main/java/com/eu/habbo/networking/gameserver/handlers/IdleTimeoutHandler.java @@ -18,7 +18,9 @@ public class IdleTimeoutHandler extends ChannelDuplexHandler { private final long pongTimeoutNanos; volatile ScheduledFuture pingScheduleFuture; - volatile long lastPongTime;// in nanoseconds + volatile boolean sentPing; + volatile long lastPingTime; // in nanoseconds + volatile long lastPongTime; // in nanoseconds private volatile int state; // 0 - none, 1 - initialized, 2 - destroyed @@ -97,10 +99,18 @@ public class IdleTimeoutHandler extends ChannelDuplexHandler { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // check if its a pong message - if(msg instanceof ClientMessage) { + if (msg instanceof ClientMessage) { ClientMessage packet = (ClientMessage) msg; - if(packet.getMessageId() == Incoming.PongEvent) { + if (packet.getMessageId() == Incoming.PongEvent) { this.lastPongTime = System.nanoTime(); + + final GameClient client = ctx.channel().attr(GameServerAttributes.CLIENT).get(); + if (client != null) { + if (sentPing) { + sentPing = false; + client.getLatencyTracker().update(lastPongTime - lastPingTime); + } + } } } super.channelRead(ctx, msg); @@ -120,13 +130,15 @@ public class IdleTimeoutHandler extends ChannelDuplexHandler { } long currentTime = System.nanoTime(); - if(currentTime - lastPongTime > pongTimeoutNanos) { + if (currentTime - lastPongTime > pongTimeoutNanos) { ctx.close();// add a promise here ? return; } - GameClient client = ctx.channel().attr(GameServerAttributes.CLIENT).get(); + final GameClient client = ctx.channel().attr(GameServerAttributes.CLIENT).get(); if (client != null) { + lastPingTime = System.nanoTime(); + sentPing = true; client.sendResponse(new PingComposer()); }