From b8a5049adbf8f1b9136f58ebd7619a3f3b42bb34 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Tue, 24 Dec 2019 02:22:50 -0800 Subject: [PATCH] Added networking support for monster entities Added networking support for dynamic object entities Fixed issues with multiple packets in stream by prepending packet size Fixed connection protocol for clients to wait until response received Created Box2DDisposer system to destroy box2d bodies when an entity has Box2DBody removed Created EntitySystemAdapter to simplify systems which are aspect event based (insert, removed, etc) Removed Entity reference from Connection and changed to entity id instead Renamed transform and alpha flag variables to tFlags and aFlags to remain consistent with elsewhere Added DS1ObjectWrapperP to network DS1 objects (DS1 object reference is needed only for server-side/host) --- .../net/packet/d2gs/DS1ObjectWrapperP.java | 38 +++++++++++ .../com/riiablo/net/packet/d2gs/SyncData.java | 3 +- .../riiablo/engine/EntitySystemAdapter.java | 7 ++ .../engine/client/ClientNetworkReceiver.java | 54 ++++++++++----- .../client/ClientNetworkSyncronizer.java | 66 +++++++++++-------- .../riiablo/engine/server/Box2DDisposer.java | 22 +++++++ .../engine/server/ServerEntityFactory.java | 2 +- core/src/com/riiablo/screen/GameScreen.java | 2 + .../src/com/riiablo/server/d2gs/D2GS.java | 50 +++++++------- .../server/d2gs/NetworkSynchronizer.java | 12 ++-- 10 files changed, 180 insertions(+), 76 deletions(-) create mode 100644 core/gen/com/riiablo/net/packet/d2gs/DS1ObjectWrapperP.java create mode 100644 core/src/com/riiablo/engine/EntitySystemAdapter.java create mode 100644 core/src/com/riiablo/engine/server/Box2DDisposer.java diff --git a/core/gen/com/riiablo/net/packet/d2gs/DS1ObjectWrapperP.java b/core/gen/com/riiablo/net/packet/d2gs/DS1ObjectWrapperP.java new file mode 100644 index 00000000..e318a380 --- /dev/null +++ b/core/gen/com/riiablo/net/packet/d2gs/DS1ObjectWrapperP.java @@ -0,0 +1,38 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +package com.riiablo.net.packet.d2gs; + +import com.google.flatbuffers.FlatBufferBuilder; +import com.google.flatbuffers.Table; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +@SuppressWarnings("unused") +public final class DS1ObjectWrapperP extends Table { + public static DS1ObjectWrapperP getRootAsDS1ObjectWrapperP(ByteBuffer _bb) { return getRootAsDS1ObjectWrapperP(_bb, new DS1ObjectWrapperP()); } + public static DS1ObjectWrapperP getRootAsDS1ObjectWrapperP(ByteBuffer _bb, DS1ObjectWrapperP 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 DS1ObjectWrapperP __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; } + + public int act() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 0; } + public int id() { int o = __offset(6); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 0; } + + public static int createDS1ObjectWrapperP(FlatBufferBuilder builder, + int act, + int id) { + builder.startObject(2); + DS1ObjectWrapperP.addId(builder, id); + DS1ObjectWrapperP.addAct(builder, act); + return DS1ObjectWrapperP.endDS1ObjectWrapperP(builder); + } + + public static void startDS1ObjectWrapperP(FlatBufferBuilder builder) { builder.startObject(2); } + public static void addAct(FlatBufferBuilder builder, int act) { builder.addByte(0, (byte)act, (byte)0); } + public static void addId(FlatBufferBuilder builder, int id) { builder.addByte(1, (byte)id, (byte)0); } + public static int endDS1ObjectWrapperP(FlatBufferBuilder builder) { + int o = builder.endObject(); + return o; + } +} + diff --git a/core/gen/com/riiablo/net/packet/d2gs/SyncData.java b/core/gen/com/riiablo/net/packet/d2gs/SyncData.java index 5189b38e..35985b28 100644 --- a/core/gen/com/riiablo/net/packet/d2gs/SyncData.java +++ b/core/gen/com/riiablo/net/packet/d2gs/SyncData.java @@ -13,8 +13,9 @@ public final class SyncData { public static final byte VelocityP = 6; public static final byte AngleP = 7; public static final byte PlayerP = 8; + public static final byte DS1ObjectWrapperP = 9; - public static final String[] names = { "NONE", "ClassP", "CofComponentsP", "CofTransformsP", "CofAlphasP", "PositionP", "VelocityP", "AngleP", "PlayerP", }; + public static final String[] names = { "NONE", "ClassP", "CofComponentsP", "CofTransformsP", "CofAlphasP", "PositionP", "VelocityP", "AngleP", "PlayerP", "DS1ObjectWrapperP", }; public static String name(int e) { return names[e]; } } diff --git a/core/src/com/riiablo/engine/EntitySystemAdapter.java b/core/src/com/riiablo/engine/EntitySystemAdapter.java new file mode 100644 index 00000000..2ec18692 --- /dev/null +++ b/core/src/com/riiablo/engine/EntitySystemAdapter.java @@ -0,0 +1,7 @@ +package com.riiablo.engine; + +import com.artemis.BaseEntitySystem; + +public class EntitySystemAdapter extends BaseEntitySystem { + @Override protected void processSystem() {} +} diff --git a/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java b/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java index 789b1d5b..d4aca944 100644 --- a/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java +++ b/core/src/com/riiablo/engine/client/ClientNetworkReceiver.java @@ -1,5 +1,7 @@ package com.riiablo.engine.client; +import com.google.flatbuffers.ByteBufferUtil; + import com.artemis.ComponentMapper; import com.artemis.annotations.All; import com.artemis.annotations.Wire; @@ -21,6 +23,7 @@ import com.riiablo.engine.server.component.Box2DBody; import com.riiablo.engine.server.component.Class; import com.riiablo.engine.server.component.CofAlphas; import com.riiablo.engine.server.component.CofComponents; +import com.riiablo.engine.server.component.CofReference; import com.riiablo.engine.server.component.CofTransforms; import com.riiablo.engine.server.component.Player; import com.riiablo.engine.server.component.Position; @@ -47,6 +50,7 @@ import com.riiablo.widget.TextArea; import java.io.InputStream; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.util.Arrays; @@ -54,8 +58,12 @@ import java.util.Arrays; @All public class ClientNetworkReceiver extends IntervalSystem { private static final String TAG = "ClientNetworkReceiver"; + private static final boolean DEBUG = true; + private static final boolean DEBUG_PACKET = DEBUG && !true; + private static final boolean DEBUG_SYNC = DEBUG && !true; // protected ComponentMapper mNetworked; + protected ComponentMapper mCofReference; protected ComponentMapper mCofComponents; protected ComponentMapper mCofTransforms; protected ComponentMapper mCofAlphas; @@ -80,7 +88,7 @@ public class ClientNetworkReceiver extends IntervalSystem { @Wire(name = "output") protected TextArea output; - private final ByteBuffer buffer = ByteBuffer.allocate(8192); + private final ByteBuffer buffer = ByteBuffer.allocate(1 << 20).order(ByteOrder.LITTLE_ENDIAN); public ClientNetworkReceiver() { super(null, 1 / 60f); @@ -90,14 +98,21 @@ public class ClientNetworkReceiver extends IntervalSystem { protected void processSystem() { InputStream in = socket.getInputStream(); try { - while (in.available() > 0) { + if (in.available() > 0) { ReadableByteChannel channel = Channels.newChannel(in); buffer.clear(); - channel.read(buffer); - buffer.limit(buffer.position()).rewind(); - D2GS packet = D2GS.getRootAsD2GS(buffer); - System.out.println("packet type " + D2GSData.name(packet.dataType())); - process(packet); + int i = channel.read(buffer); + buffer.rewind().limit(i); + D2GS d2gs = new D2GS(); + int p = 0; + while (buffer.hasRemaining()) { + int size = ByteBufferUtil.getSizePrefix(buffer); + D2GS.getRootAsD2GS(ByteBufferUtil.removeSizePrefix(buffer), d2gs); + if (DEBUG_PACKET) Gdx.app.debug(TAG, p++ + " packet type " + D2GSData.name(d2gs.dataType()) + ":" + size + "B"); + process(d2gs); +// System.out.println(buffer.position() + "->" + (buffer.position() + size + 4)); + buffer.position(buffer.position() + size + 4); + } } } catch (Throwable t) { Gdx.app.error(TAG, t.getMessage(), t); @@ -145,8 +160,6 @@ public class ClientNetworkReceiver extends IntervalSystem { int alphaFlags = Dirty.NONE; int transformFlags = Dirty.NONE; - cofs.setMode(entityId, Engine.Player.MODE_TN); - cofs.setWClass(entityId, Engine.WEAPON_1HS); // TODO... for (int i = 0; i < 16; i++) { cofs.setComponent(entityId, i, connection.cofComponents(i)); } @@ -158,6 +171,7 @@ public class ClientNetworkReceiver extends IntervalSystem { cofs.updateAlpha(entityId, alphaFlags); cofs.updateTransform(entityId, transformFlags); cofs.setMode(entityId, Engine.Player.MODE_TN, true); + cofs.setWClass(entityId, Engine.WEAPON_1HS); // TODO... System.out.println(" " + DebugUtils.toByteArray(ArrayUtils.toByteArray(component))); System.out.println(" " + Arrays.toString(alpha)); @@ -176,6 +190,8 @@ public class ClientNetworkReceiver extends IntervalSystem { output.appendText("\n"); world.delete(entityId); + Body body = mBox2DBody.get(entityId).body; + if (body != null) ; } private int findType(Sync s) { @@ -259,9 +275,9 @@ public class ClientNetworkReceiver extends IntervalSystem { syncIds.put(sync.entityId(), entityId = createEntity(sync)); } - int flags1 = Dirty.NONE; - int flags2 = Dirty.NONE; - Gdx.app.log(TAG, "syncing " + entityId); + int tFlags = Dirty.NONE; + int aFlags = Dirty.NONE; + if (DEBUG_SYNC) Gdx.app.debug(TAG, "syncing " + entityId); for (int i = 0, len = sync.dataTypeLength(); i < len; i++) { switch (sync.dataType(i)) { case SyncData.ClassP: @@ -278,14 +294,14 @@ public class ClientNetworkReceiver extends IntervalSystem { case SyncData.CofTransformsP: { CofTransformsP data = (CofTransformsP) sync.data(new CofTransformsP(), i); for (int j = 0, s0 = data.transformLength(); j < s0; j++) { - flags1 |= cofs.setTransform(entityId, j, (byte) data.transform(j)); + tFlags |= cofs.setTransform(entityId, j, (byte) data.transform(j)); } break; } case SyncData.CofAlphasP: { CofAlphasP data = (CofAlphasP) sync.data(new CofAlphasP(), i); for (int j = 0, s0 = data.alphaLength(); j < s0; j++) { - flags2 |= cofs.setAlpha(entityId, j, data.alpha(j)); + aFlags |= cofs.setAlpha(entityId, j, data.alpha(j)); } break; } @@ -294,8 +310,10 @@ public class ClientNetworkReceiver extends IntervalSystem { PositionP data = (PositionP) sync.data(new PositionP(), i); position.x = data.x(); position.y = data.y(); - Body body = mBox2DBody.get(entityId).body; - if (body != null) body.setTransform(position, body.getAngle()); + if (mBox2DBody.has(entityId)) { + Body body = mBox2DBody.get(entityId).body; + if (body != null) body.setTransform(position, body.getAngle()); + } //Gdx.app.log(TAG, " " + position); break; } @@ -320,7 +338,7 @@ public class ClientNetworkReceiver extends IntervalSystem { } } - cofs.updateTransform(entityId, flags1); - cofs.updateAlpha(entityId, flags2); + cofs.updateTransform(entityId, tFlags); + cofs.updateAlpha(entityId, aFlags); } } diff --git a/core/src/com/riiablo/engine/client/ClientNetworkSyncronizer.java b/core/src/com/riiablo/engine/client/ClientNetworkSyncronizer.java index 9f87d1e4..fd6dcd65 100644 --- a/core/src/com/riiablo/engine/client/ClientNetworkSyncronizer.java +++ b/core/src/com/riiablo/engine/client/ClientNetworkSyncronizer.java @@ -1,9 +1,9 @@ package com.riiablo.engine.client; +import com.google.flatbuffers.ByteBufferUtil; import com.google.flatbuffers.FlatBufferBuilder; import com.artemis.ComponentMapper; -import com.artemis.Entity; import com.artemis.annotations.All; import com.artemis.annotations.Wire; import com.artemis.systems.IntervalSystem; @@ -32,6 +32,7 @@ import com.riiablo.net.packet.d2gs.VelocityP; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; @@ -39,6 +40,9 @@ import java.nio.channels.WritableByteChannel; @All public class ClientNetworkSyncronizer extends IntervalSystem { private static final String TAG = "ClientNetworkSyncronizer"; + private static final boolean DEBUG = true; + private static final boolean DEBUG_PACKET = DEBUG && !true; + private static final boolean DEBUG_CONNECT = DEBUG && !true; protected ComponentMapper mNetworked; protected ComponentMapper mCofComponents; @@ -73,16 +77,16 @@ public class ClientNetworkSyncronizer extends IntervalSystem { FlatBufferBuilder builder = new FlatBufferBuilder(); int charNameOffset = builder.createString(Riiablo.charData.getD2S().header.name); - Entity player = world.getEntity(Riiablo.game.player); - int[] component = player.getComponent(CofComponents.class).component; + int entityId = Riiablo.game.player; + int[] component = mCofComponents.get(entityId).component; builder.startVector(1, component.length, 1); for (int i = component.length - 1; i >= 0; i--) builder.addByte((byte) component[i]); int componentsOffset = builder.endVector(); - float[] alphas = player.getComponent(CofAlphas.class).alpha; + float[] alphas = mCofAlphas.get(entityId).alpha; int alphasOffset = Connection.createCofAlphasVector(builder, alphas); - byte[] transforms = player.getComponent(CofTransforms.class).transform; + byte[] transforms = mCofTransforms.get(entityId).transform; int transformsOffset = Connection.createCofTransformsVector(builder, transforms); Connection.startConnection(builder); @@ -93,38 +97,46 @@ public class ClientNetworkSyncronizer extends IntervalSystem { Connection.addCofTransforms(builder, transformsOffset); int connectionOffset = Connection.endConnection(builder); int offset = D2GS.createD2GS(builder, D2GSData.Connection, connectionOffset); - builder.finish(offset); - ByteBuffer data = builder.dataBuffer(); + D2GS.finishSizePrefixedD2GSBuffer(builder, offset); OutputStream out = socket.getOutputStream(); WritableByteChannel channelOut = Channels.newChannel(out); - channelOut.write(data); + channelOut.write(builder.dataBuffer()); boolean connected = false; - ByteBuffer buffer = ByteBuffer.allocate(4096); + ByteBuffer buffer = ByteBuffer.allocate(1 << 20).order(ByteOrder.LITTLE_ENDIAN); while (!connected) { try { buffer.clear(); ReadableByteChannel channelIn = Channels.newChannel(socket.getInputStream()); int i = channelIn.read(buffer); - System.out.println("read " + i + ": " + buffer.position()); - buffer.rewind(); - D2GS response = D2GS.getRootAsD2GS(buffer); - System.out.println("packet type " + D2GSData.name(response.dataType())); - connected = response.dataType() == D2GSData.Connection; - if (!connected) { - System.out.println("dropping..."); - continue; + buffer.rewind().limit(i); + D2GS d2gs = new D2GS(); + while (buffer.hasRemaining()) { + int size = ByteBufferUtil.getSizePrefix(buffer); + D2GS.getRootAsD2GS(ByteBufferUtil.removeSizePrefix(buffer), d2gs); + if (DEBUG_PACKET) Gdx.app.debug(TAG, "packet type " + D2GSData.name(d2gs.dataType()) + ":" + ByteBufferUtil.getSizePrefix(buffer) + "B"); + connected = d2gs.dataType() == D2GSData.Connection; + if (!connected) { + if (DEBUG_CONNECT) Gdx.app.debug(TAG, "dropping... "); +// System.out.println(buffer.position() + "->" + (buffer.position() + size + 4)); + buffer.position(buffer.position() + size + 4); + continue; + } + Connection connection = (Connection) d2gs.data(new Connection()); + connected = connection.charName() == null; + if (!connected) { + if (DEBUG_CONNECT) Gdx.app.debug(TAG, "dropping... "); +// System.out.println(buffer.position() + "->" + (buffer.position() + size + 4)); + buffer.position(buffer.position() + size + 4); + continue; + } + + int serverId = connection.entityId(); + Gdx.app.log(TAG, "assign " + entityId + " to " + serverId); + idManager.put(connection.entityId(), Riiablo.game.player); + break; } - Connection connection = (Connection) response.data(new Connection()); - connected = connection.charName() == null; - if (!connected) { - System.out.println("dropping..."); - continue; - } - int serverId = connection.entityId(); - System.out.println("assign " + player + " to " + serverId); - idManager.put(connection.entityId(), Riiablo.game.player); } catch (Throwable t) { Gdx.app.error(TAG, t.getMessage(), t); } @@ -181,7 +193,7 @@ public class ClientNetworkSyncronizer extends IntervalSystem { //int syncOffset = Sync.createSync(builder, entityId, dataTypesOffset, dataOffset); int root = D2GS.createD2GS(builder, D2GSData.Sync, syncOffset); - builder.finish(root); + D2GS.finishSizePrefixedD2GSBuffer(builder, root); try { OutputStream out = socket.getOutputStream(); diff --git a/core/src/com/riiablo/engine/server/Box2DDisposer.java b/core/src/com/riiablo/engine/server/Box2DDisposer.java new file mode 100644 index 00000000..e843cad4 --- /dev/null +++ b/core/src/com/riiablo/engine/server/Box2DDisposer.java @@ -0,0 +1,22 @@ +package com.riiablo.engine.server; + +import com.artemis.ComponentMapper; +import com.artemis.annotations.All; +import com.badlogic.gdx.physics.box2d.Body; +import com.riiablo.engine.EntitySystemAdapter; +import com.riiablo.engine.server.component.Box2DBody; +import com.riiablo.map.Box2DPhysics; + +@All(Box2DBody.class) +public class Box2DDisposer extends EntitySystemAdapter { + protected ComponentMapper mBox2DBody; + + protected Box2DPhysics box2d; + + @Override + protected void removed(int entityId) { + if (!mBox2DBody.has(entityId)) return; + Body body = mBox2DBody.get(entityId).body; + if (body != null) box2d.getPhysics().destroyBody(body); + } +} diff --git a/core/src/com/riiablo/engine/server/ServerEntityFactory.java b/core/src/com/riiablo/engine/server/ServerEntityFactory.java index cff5659b..4f00a27d 100644 --- a/core/src/com/riiablo/engine/server/ServerEntityFactory.java +++ b/core/src/com/riiablo/engine/server/ServerEntityFactory.java @@ -113,7 +113,7 @@ public class ServerEntityFactory extends EntityFactory { int id = createMonster(map, zone, monstats, x, y); mDS1ObjectWrapper.create(id).set(preset.getDS1(), object); if (object.path != null) mPathWrapper.create(id).path = object.path; -// mNetworked.create(id); + mNetworked.create(id); return id; } diff --git a/core/src/com/riiablo/screen/GameScreen.java b/core/src/com/riiablo/screen/GameScreen.java index 79d2ef4c..c7ca561d 100644 --- a/core/src/com/riiablo/screen/GameScreen.java +++ b/core/src/com/riiablo/screen/GameScreen.java @@ -78,6 +78,7 @@ import com.riiablo.engine.server.AIStepper; import com.riiablo.engine.server.AngularVelocity; import com.riiablo.engine.server.AnimDataResolver; import com.riiablo.engine.server.AnimStepper; +import com.riiablo.engine.server.Box2DDisposer; import com.riiablo.engine.server.Box2DSynchronizerPre; import com.riiablo.engine.server.Box2DSynchronizerPost; import com.riiablo.engine.server.CofManager; @@ -552,6 +553,7 @@ public class GameScreen extends ScreenAdapter implements GameLoadingScreen.Loada .with(new VelocityModeChanger()) // .with(new VelocityAdder()) + .with(new Box2DDisposer()) .with(new Box2DSynchronizerPre()) .with(new Box2DPhysics(1 / 60f)) .with(new Box2DSynchronizerPost()) diff --git a/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java b/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java index 22dc48f5..dd46aae2 100644 --- a/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java +++ b/server/d2gs/src/com/riiablo/server/d2gs/D2GS.java @@ -1,5 +1,6 @@ package com.riiablo.server.d2gs; +import com.google.flatbuffers.ByteBufferUtil; import com.google.flatbuffers.FlatBufferBuilder; import com.artemis.ComponentMapper; @@ -146,6 +147,7 @@ public class D2GS extends ApplicationAdapter { ThreadGroup clientThreads; final Client[] clients = new Client[MAX_CLIENTS]; int numClients = 0; + int connected = 0; final BlockingQueue packets = new ArrayBlockingQueue<>(32); final Collection cache = new ArrayList<>(); @@ -162,7 +164,6 @@ public class D2GS extends ApplicationAdapter { EntityFactory factory; MapManager mapManager; NetworkSynchronizer sync; - SerializationManager serializer; protected ComponentMapper mNetworked; @@ -281,6 +282,7 @@ public class D2GS extends ApplicationAdapter { Gdx.app.log(TAG, "assigned " + socket.getRemoteAddress() + " to " + id); Client client = clients[id] = new Client(id, socket); numClients++; + connected |= (1 << id); client.start(); } } catch (Throwable t) { @@ -302,6 +304,7 @@ public class D2GS extends ApplicationAdapter { } } numClients = 0; + connected = 0; } Gdx.app.log(TAG, "killing thread..."); @@ -339,12 +342,12 @@ public class D2GS extends ApplicationAdapter { for (Packet packet : cache) { Gdx.app.log(TAG, "dispatching " + D2GSData.name(packet.data.dataType()) + " packet to " + String.format("0x%08X", packet.id)); for (int i = 0, flag = 1; i < MAX_CLIENTS; i++, flag <<= 1) { - if ((packet.id & flag) == flag) { + if ((packet.id & flag) == flag && (connected & flag) == flag) { Client client = clients[i]; if (client == null) continue; try { System.out.println(" dispatching packet to " + i); - client.send(packet.data); + client.send(packet); } catch (Throwable t) { Gdx.app.error(TAG, t.getMessage(), t); } @@ -400,10 +403,8 @@ public class D2GS extends ApplicationAdapter { Connection.addEntityId(builder, entityId); int connectionOffset = Connection.endConnection(builder); int offset = com.riiablo.net.packet.d2gs.D2GS.createD2GS(builder, D2GSData.Connection, connectionOffset); - builder.finish(offset); - ByteBuffer buffer = builder.dataBuffer(); - com.riiablo.net.packet.d2gs.D2GS responseData = com.riiablo.net.packet.d2gs.D2GS.getRootAsD2GS(buffer); - Packet response = Packet.obtain(1 << packet.id, responseData); + com.riiablo.net.packet.d2gs.D2GS.finishSizePrefixedD2GSBuffer(builder, offset); + Packet response = Packet.obtain(1 << packet.id, builder.dataBuffer()); outPackets.offer(response); Synchronize(packet.id, entityId); @@ -439,10 +440,9 @@ public class D2GS extends ApplicationAdapter { Connection.addCofTransforms(builder, transformsOffset); int connectionOffset = Connection.endConnection(builder); int offset = com.riiablo.net.packet.d2gs.D2GS.createD2GS(builder, D2GSData.Connection, connectionOffset); - builder.finish(offset); - com.riiablo.net.packet.d2gs.D2GS data = com.riiablo.net.packet.d2gs.D2GS.getRootAsD2GS(builder.dataBuffer()); + com.riiablo.net.packet.d2gs.D2GS.finishSizePrefixedD2GSBuffer(builder, offset); - Packet broadcast = Packet.obtain(~(1 << id), data); + Packet broadcast = Packet.obtain(~(1 << id), builder.dataBuffer()); boolean success = outPackets.offer(broadcast); assert success; } @@ -453,10 +453,8 @@ public class D2GS extends ApplicationAdapter { FlatBufferBuilder builder = new FlatBufferBuilder(); int disconnectOffset = Disconnect.createDisconnect(builder, entityId); int offset = com.riiablo.net.packet.d2gs.D2GS.createD2GS(builder, D2GSData.Disconnect, disconnectOffset); - builder.finish(offset); - ByteBuffer buffer = builder.dataBuffer(); - com.riiablo.net.packet.d2gs.D2GS responseData = com.riiablo.net.packet.d2gs.D2GS.getRootAsD2GS(buffer); - Packet broadcast = Packet.obtain(~(1 << id), responseData); + com.riiablo.net.packet.d2gs.D2GS.finishSizePrefixedD2GSBuffer(builder, offset); + Packet broadcast = Packet.obtain(~(1 << id), builder.dataBuffer()); outPackets.offer(broadcast); world.delete(entityId); @@ -464,6 +462,7 @@ public class D2GS extends ApplicationAdapter { synchronized (clients) { clients[id] = null; numClients--; + connected &= ~(1 << id); } } @@ -492,10 +491,11 @@ public class D2GS extends ApplicationAdapter { this.socket = socket; } - public void send(com.riiablo.net.packet.d2gs.D2GS data) throws IOException { - ByteBuffer buffer = data.getByteBuffer(); + public void send(Packet packet) throws IOException { WritableByteChannel out = Channels.newChannel(socket.getOutputStream()); - out.write(buffer); + packet.buffer.mark(); + out.write(packet.buffer); + packet.buffer.reset(); } @Override @@ -513,9 +513,9 @@ public class D2GS extends ApplicationAdapter { buffer.reset(); ByteBuffer copy = (ByteBuffer) ByteBuffer.wrap(new byte[buffer.limit()]).put(buffer).rewind(); - com.riiablo.net.packet.d2gs.D2GS data = com.riiablo.net.packet.d2gs.D2GS.getRootAsD2GS(copy); - Gdx.app.log(TAG, "received " + D2GSData.name(data.dataType()) + " packet from " + socket.getRemoteAddress()); - boolean success = packets.offer(Packet.obtain(id, data), 5, TimeUnit.MILLISECONDS); + Packet packet = Packet.obtain(id, copy); + Gdx.app.log(TAG, "received " + D2GSData.name(packet.data.dataType()) + " packet from " + socket.getRemoteAddress()); + boolean success = packets.offer(packet, 5, TimeUnit.MILLISECONDS); if (!success) { Gdx.app.log(TAG, "failed to add to queue -- closing " + socket.getRemoteAddress()); kill = true; @@ -533,13 +533,15 @@ public class D2GS extends ApplicationAdapter { } public static class Packet { - int id; - com.riiablo.net.packet.d2gs.D2GS data; + public int id; + public ByteBuffer buffer; + public com.riiablo.net.packet.d2gs.D2GS data; - public static Packet obtain(int id, com.riiablo.net.packet.d2gs.D2GS data) { + public static Packet obtain(int id, ByteBuffer buffer) { Packet packet = new Packet(); packet.id = id; - packet.data = data; + packet.buffer = buffer; + packet.data = com.riiablo.net.packet.d2gs.D2GS.getRootAsD2GS(ByteBufferUtil.removeSizePrefix(buffer)); return packet; } } diff --git a/server/d2gs/src/com/riiablo/server/d2gs/NetworkSynchronizer.java b/server/d2gs/src/com/riiablo/server/d2gs/NetworkSynchronizer.java index e7e8d061..e3e6fa9d 100644 --- a/server/d2gs/src/com/riiablo/server/d2gs/NetworkSynchronizer.java +++ b/server/d2gs/src/com/riiablo/server/d2gs/NetworkSynchronizer.java @@ -12,6 +12,7 @@ import com.riiablo.engine.server.component.Networked; import com.riiablo.net.packet.d2gs.D2GS; import com.riiablo.net.packet.d2gs.D2GSData; +import java.nio.ByteBuffer; import java.util.concurrent.BlockingQueue; @All(Networked.class) @@ -33,18 +34,19 @@ public class NetworkSynchronizer extends IteratingSystem { @Override protected void process(int entityId) { - D2GS sync = sync(entityId); + ByteBuffer sync = sync(entityId); int id = players.findKey(entityId, -1); - boolean success = outPackets.offer(com.riiablo.server.d2gs.D2GS.Packet.obtain(id != -1 ? ~(1 << id) : 0xFFFFFFFF, sync)); + boolean success = outPackets.offer(com.riiablo.server.d2gs.D2GS.Packet + .obtain(id != -1 ? ~(1 << id) : 0xFFFFFFFF, sync)); assert success; } - public D2GS sync(int entityId) { + public ByteBuffer sync(int entityId) { FlatBufferBuilder builder = new FlatBufferBuilder(0); int syncOffset = serializer.serialize(builder, entityId); int root = D2GS.createD2GS(builder, D2GSData.Sync, syncOffset); - builder.finish(root); - return D2GS.getRootAsD2GS(builder.dataBuffer()); + D2GS.finishSizePrefixedD2GSBuffer(builder, root); + return builder.dataBuffer(); } public void sync(int entityId, D2GS packet) {