From cdc73e12d61fb38258f8a107bc5552164d9ee127 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Sun, 7 Jun 2020 00:23:00 -0700 Subject: [PATCH] Added support for Ping packet Added Ping to Networking fbs Created Riiablo.ping long to store current ping in ms Changed Client draw fps to draw Riiablo.ping below fps Created Pinger system which manages Riiablo.ping and sending and receiving Ping packets Riiablo.ping is really more like RTT+frame_time and should be ironed out better Created issue #77 related to the work done in this commit and deficiencies to be addressed --- .../com/riiablo/net/packet/d2gs/D2GSData.java | 27 +++++---- .../gen/com/riiablo/net/packet/d2gs/Ping.java | 37 ++++++++++++ core/src/com/riiablo/Client.java | 7 ++- core/src/com/riiablo/Riiablo.java | 1 + .../engine/client/ClientNetworkReceiver.java | 5 ++ .../src/com/riiablo/engine/client/Pinger.java | 59 +++++++++++++++++++ core/src/com/riiablo/net/d2gs/D2GS.fbs | 1 + core/src/com/riiablo/net/d2gs/Networking.fbs | 8 +++ .../riiablo/screen/NetworkedGameScreen.java | 4 +- .../src/com/riiablo/server/d2gs/D2GS.java | 9 +++ 10 files changed, 143 insertions(+), 15 deletions(-) create mode 100644 core/gen/com/riiablo/net/packet/d2gs/Ping.java create mode 100644 core/src/com/riiablo/engine/client/Pinger.java diff --git a/core/gen/com/riiablo/net/packet/d2gs/D2GSData.java b/core/gen/com/riiablo/net/packet/d2gs/D2GSData.java index 42917d4d..37981f54 100644 --- a/core/gen/com/riiablo/net/packet/d2gs/D2GSData.java +++ b/core/gen/com/riiablo/net/packet/d2gs/D2GSData.java @@ -11,20 +11,21 @@ public final class D2GSData { public static final byte RunToEntity = 4; public static final byte Connection = 5; public static final byte Disconnect = 6; - public static final byte EntitySync = 7; - public static final byte GroundToCursor = 8; - public static final byte CursorToGround = 9; - public static final byte StoreToCursor = 10; - public static final byte CursorToStore = 11; - public static final byte SwapStoreItem = 12; - public static final byte BodyToCursor = 13; - public static final byte CursorToBody = 14; - public static final byte SwapBodyItem = 15; - public static final byte BeltToCursor = 16; - public static final byte CursorToBelt = 17; - public static final byte SwapBeltItem = 18; + public static final byte Ping = 7; + public static final byte EntitySync = 8; + public static final byte GroundToCursor = 9; + public static final byte CursorToGround = 10; + public static final byte StoreToCursor = 11; + public static final byte CursorToStore = 12; + public static final byte SwapStoreItem = 13; + public static final byte BodyToCursor = 14; + public static final byte CursorToBody = 15; + public static final byte SwapBodyItem = 16; + public static final byte BeltToCursor = 17; + public static final byte CursorToBelt = 18; + public static final byte SwapBeltItem = 19; - public static final String[] names = { "NONE", "WalkToLocation", "WalkToEntity", "RunToLocation", "RunToEntity", "Connection", "Disconnect", "EntitySync", "GroundToCursor", "CursorToGround", "StoreToCursor", "CursorToStore", "SwapStoreItem", "BodyToCursor", "CursorToBody", "SwapBodyItem", "BeltToCursor", "CursorToBelt", "SwapBeltItem", }; + public static final String[] names = { "NONE", "WalkToLocation", "WalkToEntity", "RunToLocation", "RunToEntity", "Connection", "Disconnect", "Ping", "EntitySync", "GroundToCursor", "CursorToGround", "StoreToCursor", "CursorToStore", "SwapStoreItem", "BodyToCursor", "CursorToBody", "SwapBodyItem", "BeltToCursor", "CursorToBelt", "SwapBeltItem", }; public static String name(int e) { return names[e]; } } diff --git a/core/gen/com/riiablo/net/packet/d2gs/Ping.java b/core/gen/com/riiablo/net/packet/d2gs/Ping.java new file mode 100644 index 00000000..3021ae87 --- /dev/null +++ b/core/gen/com/riiablo/net/packet/d2gs/Ping.java @@ -0,0 +1,37 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package com.riiablo.net.packet.d2gs; + +import java.nio.*; +import java.lang.*; +import java.util.*; +import com.google.flatbuffers.*; + +@SuppressWarnings("unused") +public final class Ping extends Table { + public static Ping getRootAsPing(ByteBuffer _bb) { return getRootAsPing(_bb, new Ping()); } + public static Ping getRootAsPing(ByteBuffer _bb, Ping obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); } + public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; vtable_start = bb_pos - bb.getInt(bb_pos); vtable_size = bb.getShort(vtable_start); } + public Ping __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public int tickCount() { int o = __offset(4); return o != 0 ? bb.getInt(o + bb_pos) : 0; } + public long time() { int o = __offset(6); return o != 0 ? bb.getLong(o + bb_pos) : 0L; } + + public static int createPing(FlatBufferBuilder builder, + int tickCount, + long time) { + builder.startObject(2); + Ping.addTime(builder, time); + Ping.addTickCount(builder, tickCount); + return Ping.endPing(builder); + } + + public static void startPing(FlatBufferBuilder builder) { builder.startObject(2); } + public static void addTickCount(FlatBufferBuilder builder, int tickCount) { builder.addInt(0, tickCount, 0); } + public static void addTime(FlatBufferBuilder builder, long time) { builder.addLong(1, time, 0L); } + public static int endPing(FlatBufferBuilder builder) { + int o = builder.endObject(); + return o; + } +} + diff --git a/core/src/com/riiablo/Client.java b/core/src/com/riiablo/Client.java index 4b216eed..e9daff2d 100644 --- a/core/src/com/riiablo/Client.java +++ b/core/src/com/riiablo/Client.java @@ -441,7 +441,12 @@ public class Client extends Game { BitmapFont font = console.getFont(); if (font == null) return; - fps.setText(font, Integer.toString(Gdx.graphics.getFramesPerSecond())); + StringBuilder builder = new StringBuilder(64); + builder + .append(Gdx.graphics.getFramesPerSecond()) + .append('\n').append(Riiablo.ping).append(" ms") + ; + fps.setText(font, builder.toString()); int drawFpsMethod = this.drawFpsMethod; if (forceDrawFps && drawFpsMethod == FPS_NONE) { drawFpsMethod = FPS_TOPLEFT; diff --git a/core/src/com/riiablo/Riiablo.java b/core/src/com/riiablo/Riiablo.java index 90a3995b..2a8be66f 100644 --- a/core/src/com/riiablo/Riiablo.java +++ b/core/src/com/riiablo/Riiablo.java @@ -67,4 +67,5 @@ public class Riiablo { public static World engine; public static GameScreen game; public static D2 anim; + public static long ping; } diff --git a/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java b/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java index fb31cf17..e1d4df36 100644 --- a/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java +++ b/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java @@ -54,6 +54,7 @@ import com.riiablo.net.packet.d2gs.EntitySync; import com.riiablo.net.packet.d2gs.GroundToCursor; import com.riiablo.net.packet.d2gs.ItemP; import com.riiablo.net.packet.d2gs.MonsterP; +import com.riiablo.net.packet.d2gs.Ping; import com.riiablo.net.packet.d2gs.PlayerP; import com.riiablo.net.packet.d2gs.PositionP; import com.riiablo.net.packet.d2gs.StoreToCursor; @@ -97,6 +98,7 @@ public class ClientNetworkReceiver extends IntervalSystem { protected CofManager cofs; protected NetworkIdManager syncIds; protected ItemManager items; + protected Pinger pinger; @Wire(name="client.socket") protected Socket socket; @@ -150,6 +152,9 @@ public class ClientNetworkReceiver extends IntervalSystem { case D2GSData.Disconnect: Disconnect(packet); break; + case D2GSData.Ping: + pinger.Ping((Ping) packet.data(new Ping())); + break; case D2GSData.EntitySync: Synchronize(packet); break; diff --git a/core/src/com/riiablo/engine/client/Pinger.java b/core/src/com/riiablo/engine/client/Pinger.java new file mode 100644 index 00000000..e1d07249 --- /dev/null +++ b/core/src/com/riiablo/engine/client/Pinger.java @@ -0,0 +1,59 @@ +package com.riiablo.engine.client; + +import com.google.flatbuffers.FlatBufferBuilder; + +import com.artemis.annotations.All; +import com.artemis.annotations.Wire; +import com.artemis.systems.IntervalSystem; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.net.Socket; +import com.badlogic.gdx.utils.TimeUtils; +import com.riiablo.Riiablo; +import com.riiablo.net.packet.d2gs.D2GS; +import com.riiablo.net.packet.d2gs.D2GSData; +import com.riiablo.net.packet.d2gs.Ping; + +import java.io.OutputStream; +import java.nio.channels.Channels; +import java.nio.channels.WritableByteChannel; + +@All +public class Pinger extends IntervalSystem { + private static final String TAG = "Pinger"; + private static final boolean DEBUG = !true; + + @Wire(name = "client.socket") + protected Socket socket; + + // TODO: this system depends on a 32-bit int -- at some point will need to figure out if this will become an issue + // it may be possible to use Gdx.graphics.getFrameId() -- but that isn't related to engine tick + private int tick; + +// TODO: provide a running average of past N RTTs +// private final double deltas[] = new double[5]; +// private int deltaCount; + + public Pinger() { + super(null, 1.0f); + } + + @Override + protected void processSystem() { + FlatBufferBuilder builder = new FlatBufferBuilder(0); + int dataOffset = Ping.createPing(builder, tick++, TimeUtils.millis()); + int root = D2GS.createD2GS(builder, D2GSData.Ping, dataOffset); + D2GS.finishSizePrefixedD2GSBuffer(builder, root); + + try { + OutputStream out = socket.getOutputStream(); + WritableByteChannel channelOut = Channels.newChannel(out); + channelOut.write(builder.dataBuffer()); + } catch (Throwable t) { + Gdx.app.error(TAG, t.getMessage(), t); + } + } + + public void Ping(Ping packet) { + Riiablo.ping = TimeUtils.timeSinceMillis(packet.time()); + } +} diff --git a/core/src/com/riiablo/net/d2gs/D2GS.fbs b/core/src/com/riiablo/net/d2gs/D2GS.fbs index 8e6d6382..9f1d653d 100644 --- a/core/src/com/riiablo/net/d2gs/D2GS.fbs +++ b/core/src/com/riiablo/net/d2gs/D2GS.fbs @@ -12,6 +12,7 @@ union D2GSData { RunToEntity, Connection, Disconnect, + Ping, EntitySync, GroundToCursor, CursorToGround, diff --git a/core/src/com/riiablo/net/d2gs/Networking.fbs b/core/src/com/riiablo/net/d2gs/Networking.fbs index 819be16d..1c213b4d 100644 --- a/core/src/com/riiablo/net/d2gs/Networking.fbs +++ b/core/src/com/riiablo/net/d2gs/Networking.fbs @@ -17,5 +17,13 @@ table Disconnect { // request entityId:int32; + // response +} + +table Ping { + // request + tickCount:int32; + time:int64; + // response } \ No newline at end of file diff --git a/core/src/com/riiablo/screen/NetworkedGameScreen.java b/core/src/com/riiablo/screen/NetworkedGameScreen.java index 676b0fb6..20fc0652 100644 --- a/core/src/com/riiablo/screen/NetworkedGameScreen.java +++ b/core/src/com/riiablo/screen/NetworkedGameScreen.java @@ -2,9 +2,10 @@ package com.riiablo.screen; import com.artemis.WorldConfigurationBuilder; import com.badlogic.gdx.net.Socket; -import com.riiablo.save.CharData; import com.riiablo.engine.client.ClientNetworkReceiver; import com.riiablo.engine.client.ClientNetworkSyncronizer; +import com.riiablo.engine.client.Pinger; +import com.riiablo.save.CharData; public class NetworkedGameScreen extends GameScreen { private static final String TAG = "NetworkedGameScreen"; @@ -22,6 +23,7 @@ public class NetworkedGameScreen extends GameScreen { WorldConfigurationBuilder builder = super.getWorldConfigurationBuilder(); builder.with(WorldConfigurationBuilder.Priority.HIGH, new ClientNetworkReceiver()); builder.with(new ClientNetworkSyncronizer()); + builder.with(new Pinger()); return builder; } diff --git a/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java b/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java index 9626a085..8c466b5b 100644 --- a/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java +++ b/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java @@ -427,6 +427,9 @@ public class D2GS extends ApplicationAdapter { case D2GSData.SwapBeltItem: SwapBeltItem(packet); break; + case D2GSData.Ping: + Ping(packet); + break; default: Gdx.app.error(TAG, "Unknown packet type: " + packet.data.dataType()); } @@ -531,6 +534,12 @@ public class D2GS extends ApplicationAdapter { } } + private void Ping(Packet packet) { +// Ping ping = (Ping) packet.data.data(new Ping()); + packet.id = (1 << packet.id); + outPackets.offer(packet); + } + private void Synchronize(Packet packet) { int entityId = player.get(packet.id, Engine.INVALID_ENTITY); assert entityId != Engine.INVALID_ENTITY;