From b266516fadee05148405b36ed1c3e6bd80dda49c Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 16 Jan 2018 23:30:24 -0500 Subject: [PATCH] Implemented new custom serialization --- core/assets/bundles/bundle.properties | 1 + .../io/anuke/mindustry/core/NetClient.java | 19 +- .../io/anuke/mindustry/core/NetServer.java | 11 +- .../anuke/mindustry/entities/BulletType.java | 2 +- .../anuke/mindustry/entities/effect/EMP.java | 2 +- core/src/io/anuke/mindustry/graphics/Fx.java | 4 +- .../io/anuke/mindustry/input/PlaceMode.java | 2 +- .../io/anuke/mindustry/mapeditor/MapView.java | 4 +- core/src/io/anuke/mindustry/net/Packet.java | 8 + core/src/io/anuke/mindustry/net/Packets.java | 405 ++++++++++++++++-- .../io/anuke/mindustry/net/Registrator.java | 99 ++--- .../io/anuke/mindustry/net/Streamable.java | 36 +- .../src/io/anuke/kryonet/ByteSerializer.java | 61 +++ .../io/anuke/kryonet/FrameworkSerializer.java | 69 +++ kryonet/src/io/anuke/kryonet/KryoClient.java | 9 +- kryonet/src/io/anuke/kryonet/KryoServer.java | 11 +- 16 files changed, 638 insertions(+), 105 deletions(-) create mode 100644 core/src/io/anuke/mindustry/net/Packet.java create mode 100644 kryonet/src/io/anuke/kryonet/ByteSerializer.java create mode 100644 kryonet/src/io/anuke/kryonet/FrameworkSerializer.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 671b3db77a..f9859472c7 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -16,6 +16,7 @@ text.about.button=About text.name=Name: text.public=Public text.players={0} players online +text.server.player.host={0} (host) text.players.single={0} player online text.server.mismatch=Packet error: possible client/server version mismatch.\nMake sure you and the host have the\nlatest version of Mindustry! text.server.closing=[accent]Closing server... diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 0a3f81c5e4..d3a24a5179 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -272,12 +272,21 @@ public class NetClient extends Module { } }); - Net.handle(Player.class, player -> { + Net.handle(PlayerSpawnPacket.class, packet -> { Gdx.app.postRunnable(() -> { //duplicates. - if(Vars.control.enemyGroup.getByID(player.id) != null || - recieved.contains(player.id)) return; - recieved.add(player.id); + if(Vars.control.enemyGroup.getByID(packet.id) != null || + recieved.contains(packet.id)) return; + recieved.add(packet.id); + + Player player = new Player(); + player.x = packet.x; + player.y = packet.y; + player.isAndroid = packet.android; + player.name = packet.name; + player.id = packet.id; + player.weaponLeft = (Weapon) Upgrade.getByID(packet.weaponleft); + player.weaponRight = (Weapon) Upgrade.getByID(packet.weaponright); player.interpolator.last.set(player.x, player.y); player.interpolator.target.set(player.x, player.y); @@ -291,7 +300,7 @@ public class NetClient extends Module { kicked = true; Net.disconnect(); GameState.set(State.menu); - Gdx.app.postRunnable(() -> Vars.ui.showError("$text.server.kicked." + KickReason.values()[packet.reason].name())); + Gdx.app.postRunnable(() -> Vars.ui.showError("$text.server.kicked." + packet.reason.name())); }); Net.handle(WeaponSwitchPacket.class, packet -> { diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index ad1d7e02af..b3274e7828 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -190,7 +190,16 @@ public class NetServer extends Module{ int dest = Net.getLastConnection(); Gdx.app.postRunnable(() -> { if(Vars.control.playerGroup.getByID(id) != null){ - Net.sendTo(dest, Vars.control.playerGroup.getByID(id), SendMode.tcp); + Player player = Vars.control.playerGroup.getByID(id); + PlayerSpawnPacket p = new PlayerSpawnPacket(); + p.x = player.x; + p.y = player.y; + p.id = player.id; + p.name = player.name; + p.weaponleft = player.weaponLeft.id; + p.weaponright = player.weaponRight.id; + p.android = player.isAndroid; + Net.sendTo(dest, p, SendMode.tcp); Gdx.app.error("Mindustry", "Replying to entity request ("+Net.getLastConnection()+"): player, " + id); }else if (Vars.control.enemyGroup.getByID(id) != null){ Enemy enemy = Vars.control.enemyGroup.getByID(id); diff --git a/core/src/io/anuke/mindustry/entities/BulletType.java b/core/src/io/anuke/mindustry/entities/BulletType.java index fae051e255..7236e90fd2 100644 --- a/core/src/io/anuke/mindustry/entities/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/BulletType.java @@ -352,7 +352,7 @@ public abstract class BulletType extends BaseBulletType{ public void draw(Bullet b){ Draw.thick(2f); Draw.color(lightOrange, Color.WHITE, 0.4f); - Draw.polygon(b.y, b.x, 3, 1.6f, b.angle()); + Draw.polygon(b.x, b.y, 3, 1.6f, b.angle()); Draw.thick(1f); Draw.color(Color.WHITE, lightOrange, b.ifract()/2f); Draw.alpha(b.ifract()); diff --git a/core/src/io/anuke/mindustry/entities/effect/EMP.java b/core/src/io/anuke/mindustry/entities/effect/EMP.java index 1f597faa3f..39891a9cb3 100644 --- a/core/src/io/anuke/mindustry/entities/effect/EMP.java +++ b/core/src/io/anuke/mindustry/entities/effect/EMP.java @@ -84,7 +84,7 @@ public class EMP extends TimedEntity{ } Draw.thick(fract()*2f); - Draw.polygon(y, x, 34, radius * Vars.tilesize); + Draw.polygon(x, y, 34, radius * Vars.tilesize); Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/graphics/Fx.java b/core/src/io/anuke/mindustry/graphics/Fx.java index a0a99490d7..a67d5ccf9b 100644 --- a/core/src/io/anuke/mindustry/graphics/Fx.java +++ b/core/src/io/anuke/mindustry/graphics/Fx.java @@ -121,7 +121,7 @@ public class Fx{ nuclearShockwave = new Effect(10f, 200f, e -> { Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.ifract()); Draw.thick(e.fract()*3f + 0.2f); - Draw.polygon(e.y, e.x, 40, e.ifract()*140f); + Draw.polygon(e.x, e.y, 40, e.ifract()*140f); Draw.reset(); }), @@ -452,7 +452,7 @@ public class Fx{ clusterbomb = new Effect(10f, e -> { Draw.color(Color.WHITE, lightOrange, e.ifract()); Draw.thick(e.fract()*1.5f); - Draw.polygon(e.y, e.x, 4, e.fract()*8f); + Draw.polygon(e.x, e.y, 4, e.fract()*8f); Draw.circle(e.x, e.y, e.ifract()*14f); Draw.reset(); }), diff --git a/core/src/io/anuke/mindustry/input/PlaceMode.java b/core/src/io/anuke/mindustry/input/PlaceMode.java index d75256573f..9773804bd1 100644 --- a/core/src/io/anuke/mindustry/input/PlaceMode.java +++ b/core/src/io/anuke/mindustry/input/PlaceMode.java @@ -96,7 +96,7 @@ public enum PlaceMode{ if(android && control.getInput().breaktime > 0){ Draw.color(Colors.get("breakStart"), Colors.get("break"), fract); - Draw.polygon(tile.worldx() + offset.y, tile.worldy() + offset.x, 25, 4 + (1f - fract) * 26); + Draw.polygon(tile.worldx() + offset.x, tile.worldy() + offset.y, 25, 4 + (1f - fract) * 26); } Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/mapeditor/MapView.java b/core/src/io/anuke/mindustry/mapeditor/MapView.java index 0cc7ddabc1..29f04ce1dd 100644 --- a/core/src/io/anuke/mindustry/mapeditor/MapView.java +++ b/core/src/io/anuke/mindustry/mapeditor/MapView.java @@ -238,9 +238,9 @@ public class MapView extends Element implements GestureListener{ Draw.thick(Unit.dp.scl(3f * zoom)); Draw.line(sx, sy, v2.x, v2.y); - Draw.polygon(sy, sx, 40, editor.getBrushSize() * zoom * 3); + Draw.polygon(sx, sy, 40, editor.getBrushSize() * zoom * 3); - Draw.polygon(v2.y, v2.x, 40, editor.getBrushSize() * zoom * 3); + Draw.polygon(v2.x, v2.y, 40, editor.getBrushSize() * zoom * 3); } batch.flush(); diff --git a/core/src/io/anuke/mindustry/net/Packet.java b/core/src/io/anuke/mindustry/net/Packet.java new file mode 100644 index 0000000000..a2c0c6e1d3 --- /dev/null +++ b/core/src/io/anuke/mindustry/net/Packet.java @@ -0,0 +1,8 @@ +package io.anuke.mindustry.net; + +import java.nio.ByteBuffer; + +public interface Packet { + void read(ByteBuffer buffer); + void write(ByteBuffer buffer); +} diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 0cdabc7280..b0db9dba22 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -1,9 +1,15 @@ package io.anuke.mindustry.net; +import io.anuke.mindustry.entities.Player; +import io.anuke.mindustry.entities.SyncEntity; +import io.anuke.mindustry.resource.Item; + +import java.nio.ByteBuffer; + /**Class for storing all packets.*/ public class Packets { - public static class Connect { + public static class Connect{ public int id; public String addressTCP; } @@ -17,128 +23,477 @@ public class Packets { } - public static class SyncPacket{ + public static class SyncPacket implements Packet{ public byte[] data; + + @Override + public void write(ByteBuffer buffer) { + buffer.putShort((short)data.length); + buffer.put(data); + } + + @Override + public void read(ByteBuffer buffer) { + data = new byte[buffer.getShort()]; + buffer.get(data); + } } public static class BlockSyncPacket extends Streamable{ } - public static class ConnectPacket{ + public static class ConnectPacket implements Packet{ public String name; public boolean android; + + @Override + public void write(ByteBuffer buffer) { + buffer.put((byte)name.length()); + buffer.put(name.getBytes()); + buffer.put(android ? (byte)1 : 0); + } + + @Override + public void read(ByteBuffer buffer) { + byte length = buffer.get(); + byte[] bytes = new byte[length]; + buffer.get(bytes); + name = new String(bytes); + android = buffer.get() == 1; + } } - public static class ConnectConfirmPacket{ + public static class ConnectConfirmPacket implements Packet{ + @Override + public void write(ByteBuffer buffer) { } + @Override + public void read(ByteBuffer buffer) { } } - public static class DisconnectPacket{ + public static class DisconnectPacket implements Packet{ public int playerid; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(playerid); + } + + @Override + public void read(ByteBuffer buffer) { + playerid = buffer.getInt(); + } } - public static class StateSyncPacket{ + public static class StateSyncPacket implements Packet{ public int[] items; public float countdown, time; public int enemies, wave; public long timestamp; + + @Override + public void write(ByteBuffer buffer) { + for(int i = 0; i < items.length; i ++){ + buffer.putInt(items[i]); + } + + buffer.putFloat(countdown); + buffer.putFloat(time); + buffer.putShort((short)enemies); + buffer.putShort((short)wave); + buffer.putLong(timestamp); + } + + @Override + public void read(ByteBuffer buffer) { + items = new int[Item.getAllItems().size]; + + for(int i = 0; i < items.length; i ++){ + items[i] = buffer.getInt(); + } + + countdown = buffer.getFloat(); + time = buffer.getFloat(); + enemies = buffer.getShort(); + wave = buffer.getShort(); + timestamp = buffer.getLong(); + } } - public static class PositionPacket{ + public static class PositionPacket implements Packet{ public byte[] data; + + @Override + public void write(ByteBuffer buffer) { + buffer.put(data); + } + + @Override + public void read(ByteBuffer buffer) { + data = new byte[SyncEntity.getWriteSize(Player.class)]; + buffer.get(data); + } } + //not a real packet. public static class EffectPacket{ public int id; public float x, y, rotation; public int color; } - public static class ShootPacket{ + public static class ShootPacket implements Packet{ public byte weaponid; public float x, y, rotation; public int playerid; + + @Override + public void write(ByteBuffer buffer) { + buffer.put(weaponid); + buffer.putFloat(x); + buffer.putFloat(y); + buffer.putFloat(rotation); + buffer.putInt(playerid); + } + + @Override + public void read(ByteBuffer buffer) { + weaponid = buffer.get(); + x = buffer.getFloat(); + y = buffer.getFloat(); + rotation = buffer.getFloat(); + playerid = buffer.getInt(); + } } - public static class BulletPacket{ + public static class BulletPacket implements Packet{ public int type, owner; public float x, y, angle; public short damage; + + @Override + public void write(ByteBuffer buffer) { + buffer.putShort((short)type); + buffer.putInt(owner); + buffer.putFloat(x); + buffer.putFloat(y); + buffer.putFloat(angle); + buffer.putShort(damage); + } + + @Override + public void read(ByteBuffer buffer) { + type = buffer.getShort(); + owner = buffer.getInt(); + x = buffer.getFloat(); + y = buffer.getFloat(); + angle = buffer.getFloat(); + damage = buffer.getShort(); + } } - public static class PlacePacket{ + public static class PlacePacket implements Packet{ public int playerid; public byte rotation; public short x, y; public int block; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(playerid); + buffer.put(rotation); + buffer.putShort(x); + buffer.putShort(y); + buffer.putInt(block); + } + + @Override + public void read(ByteBuffer buffer) { + playerid = buffer.getInt(); + rotation = buffer.get(); + x = buffer.getShort(); + y = buffer.getShort(); + block = buffer.getInt(); + } } - public static class BreakPacket{ + public static class BreakPacket implements Packet{ public int playerid; public short x, y; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(playerid); + buffer.putShort(x); + buffer.putShort(y); + } + + @Override + public void read(ByteBuffer buffer) { + playerid = buffer.getInt(); + x = buffer.getShort(); + y = buffer.getShort(); + } } - public static class EnemySpawnPacket{ + public static class EnemySpawnPacket implements Packet{ public byte type, lane, tier; public float x, y; public short health; public int id; + + @Override + public void write(ByteBuffer buffer) { + buffer.put(type); + buffer.put(lane); + buffer.put(tier); + buffer.putFloat(x); + buffer.putFloat(y); + buffer.putShort(health); + buffer.putInt(id); + } + + @Override + public void read(ByteBuffer buffer) { + type = buffer.get(); + lane = buffer.get(); + tier = buffer.get(); + x = buffer.getFloat(); + y = buffer.getFloat(); + health = buffer.getShort(); + id = buffer.getInt(); + } } - public static class EnemyDeathPacket{ + public static class PlayerSpawnPacket implements Packet{ + public byte weaponleft, weaponright; + public boolean android; + public String name; + public float x, y; public int id; + + @Override + public void write(ByteBuffer buffer) { + buffer.put((byte)name.length()); + buffer.put(name.getBytes()); + buffer.put(weaponleft); + buffer.put(weaponright); + buffer.put(android ? 1 : (byte)0); + buffer.putFloat(x); + buffer.putFloat(y); + buffer.putInt(id); + } + + @Override + public void read(ByteBuffer buffer) { + byte nlength = buffer.get(); + byte[] n = new byte[nlength]; + buffer.get(n); + name = new String(n); + weaponleft = buffer.get(); + weaponright = buffer.get(); + android = buffer.get() == 1; + x = buffer.getFloat(); + y = buffer.getFloat(); + id = buffer.getInt(); + } } - public static class BlockDestroyPacket{ + public static class EnemyDeathPacket implements Packet{ + public int id; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(id); + } + + @Override + public void read(ByteBuffer buffer) { + id = buffer.getInt(); + } + } + + public static class BlockDestroyPacket implements Packet{ public int position; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(position); + } + + @Override + public void read(ByteBuffer buffer) { + position = buffer.getInt(); + } } - public static class BlockUpdatePacket{ + public static class BlockUpdatePacket implements Packet{ public int health, position; + + @Override + public void write(ByteBuffer buffer) { + buffer.putShort((short)health); + buffer.putInt(position); + } + + @Override + public void read(ByteBuffer buffer) { + health = buffer.getShort(); + position = buffer.getInt(); + } } - public static class ChatPacket{ + public static class ChatPacket implements Packet{ public String name; public String text; public int id; + + @Override + public void write(ByteBuffer buffer) { + if(name != null) { + buffer.putShort((short) name.length()); + buffer.put(name.getBytes()); + }else{ + buffer.putShort((short)-1); + } + buffer.putShort((short)text.length()); + buffer.put(text.getBytes()); + buffer.putInt(id); + } + + @Override + public void read(ByteBuffer buffer) { + short nlength = buffer.getShort(); + if(nlength != -1) { + byte[] n = new byte[nlength]; + buffer.get(n); + name = new String(n); + } + short tlength = buffer.getShort(); + byte[] t = new byte[tlength]; + buffer.get(t); + + id = buffer.getInt(); + text = new String(t); + } } - public static class KickPacket{ - public byte reason; + public static class KickPacket implements Packet{ + public KickReason reason; + + @Override + public void write(ByteBuffer buffer) { + buffer.put((byte)reason.ordinal()); + } + + @Override + public void read(ByteBuffer buffer) { + reason = KickReason.values()[buffer.get()]; + } } public enum KickReason{ kick, invalidPassword } - public static class UpgradePacket{ + public static class UpgradePacket implements Packet{ public byte id; //weapon ID only, currently + + @Override + public void write(ByteBuffer buffer) { + buffer.put(id); + } + + @Override + public void read(ByteBuffer buffer) { + id = buffer.get(); + } } - public static class WeaponSwitchPacket{ + public static class WeaponSwitchPacket implements Packet{ public int playerid; public byte left, right; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(playerid); + buffer.put(left); + buffer.put(right); + } + + @Override + public void read(ByteBuffer buffer) { + playerid = buffer.getInt(); + left = buffer.get(); + right = buffer.get(); + } } - public static class BlockTapPacket{ + public static class BlockTapPacket implements Packet{ public int position; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(position); + } + + @Override + public void read(ByteBuffer buffer) { + position = buffer.getInt(); + } } - public static class BlockConfigPacket{ + public static class BlockConfigPacket implements Packet{ public int position; public byte data; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(position); + buffer.put(data); + } + + @Override + public void read(ByteBuffer buffer) { + position = buffer.getInt(); + data = buffer.get(); + } } - public static class EntityRequestPacket{ + public static class EntityRequestPacket implements Packet{ public int id; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(id); + } + + @Override + public void read(ByteBuffer buffer) { + id = buffer.getInt(); + } } - public static class GameOverPacket{ + public static class GameOverPacket implements Packet{ + @Override + public void write(ByteBuffer buffer) { } + @Override + public void read(ByteBuffer buffer) { } } - public static class FriendlyFireChangePacket{ + public static class FriendlyFireChangePacket implements Packet{ public boolean enabled; + + @Override + public void write(ByteBuffer buffer) { + buffer.put(enabled ? 1 : (byte)0); + } + + @Override + public void read(ByteBuffer buffer) { + enabled = buffer.get() == 1; + } } } diff --git a/core/src/io/anuke/mindustry/net/Registrator.java b/core/src/io/anuke/mindustry/net/Registrator.java index a551a4c87e..6e740f862c 100644 --- a/core/src/io/anuke/mindustry/net/Registrator.java +++ b/core/src/io/anuke/mindustry/net/Registrator.java @@ -1,59 +1,62 @@ package io.anuke.mindustry.net; -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Array; -import io.anuke.mindustry.entities.Player; -import io.anuke.mindustry.entities.enemies.Enemy; +import com.badlogic.gdx.utils.ObjectIntMap; +import com.badlogic.gdx.utils.reflect.ClassReflection; import io.anuke.mindustry.net.Packets.*; import io.anuke.mindustry.net.Streamable.StreamBegin; import io.anuke.mindustry.net.Streamable.StreamChunk; -import io.anuke.ucore.entities.Entity; public class Registrator { + private static Class[] classes = { + StreamBegin.class, + StreamChunk.class, + WorldData.class, + SyncPacket.class, + PositionPacket.class, + ShootPacket.class, + PlacePacket.class, + BreakPacket.class, + StateSyncPacket.class, + BlockSyncPacket.class, + EnemySpawnPacket.class, + PlayerSpawnPacket.class, + BulletPacket.class, + EnemyDeathPacket.class, + BlockUpdatePacket.class, + BlockDestroyPacket.class, + ConnectPacket.class, + DisconnectPacket.class, + ChatPacket.class, + KickPacket.class, + UpgradePacket.class, + WeaponSwitchPacket.class, + BlockTapPacket.class, + BlockConfigPacket.class, + EntityRequestPacket.class, + ConnectConfirmPacket.class, + GameOverPacket.class, + FriendlyFireChangePacket.class, + }; + private static ObjectIntMap> ids = new ObjectIntMap<>(); + + static{ + if(classes.length > 127) throw new RuntimeException("Can't have more than 127 registered classes!"); + for(int i = 0; i < classes.length; i ++){ + if(!ClassReflection.isAssignableFrom(Packet.class, classes[i]) && + !ClassReflection.isAssignableFrom(Streamable.class, classes[i])) throw new RuntimeException("Not a packet: " + classes[i]); + ids.put(classes[i], i); + } + } + + public static Class getByID(byte id){ + return classes[id]; + } + + public static byte getID(Class type){ + return (byte)ids.get(type, -1); + } public static Class[] getClasses(){ - return new Class[]{ - StreamBegin.class, - StreamChunk.class, - WorldData.class, - SyncPacket.class, - PositionPacket.class, - ShootPacket.class, - PlacePacket.class, - BreakPacket.class, - StateSyncPacket.class, - BlockSyncPacket.class, - EnemySpawnPacket.class, - BulletPacket.class, - EnemyDeathPacket.class, - BlockUpdatePacket.class, - BlockDestroyPacket.class, - ConnectPacket.class, - DisconnectPacket.class, - ChatPacket.class, - KickPacket.class, - UpgradePacket.class, - WeaponSwitchPacket.class, - BlockTapPacket.class, - BlockConfigPacket.class, - EntityRequestPacket.class, - ConnectConfirmPacket.class, - GameOverPacket.class, - FriendlyFireChangePacket.class, - - Class.class, - byte[].class, - float[].class, - float[][].class, - int[].class, - int[][].class, - Entity[].class, - Array.class, - Vector2.class, - - Entity.class, - Player.class, - Enemy.class - }; + return classes; } } diff --git a/core/src/io/anuke/mindustry/net/Streamable.java b/core/src/io/anuke/mindustry/net/Streamable.java index a6f22be3ce..e115dd5bfb 100644 --- a/core/src/io/anuke/mindustry/net/Streamable.java +++ b/core/src/io/anuke/mindustry/net/Streamable.java @@ -6,23 +6,51 @@ import com.badlogic.gdx.utils.reflect.ReflectionException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.InputStream; +import java.nio.ByteBuffer; -public class Streamable { +public class Streamable{ public transient ByteArrayInputStream stream; /**Marks the beginning of a stream.*/ - public static class StreamBegin{ + public static class StreamBegin implements Packet{ private static int lastid; public int id = lastid ++; public int total; public Class type; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(id); + buffer.putInt(total); + buffer.put(Registrator.getID(type)); + } + + @Override + public void read(ByteBuffer buffer) { + id = buffer.getInt(); + total = buffer.getInt(); + type = (Class)Registrator.getByID(buffer.get()); + } } - public static class StreamChunk{ + public static class StreamChunk implements Packet{ public int id; public byte[] data; + + @Override + public void write(ByteBuffer buffer) { + buffer.putInt(id); + buffer.putShort((short)data.length); + buffer.put(data); + } + + @Override + public void read(ByteBuffer buffer) { + id = buffer.getInt(); + data = new byte[buffer.getShort()]; + buffer.get(data); + } } public static class StreamBuilder{ diff --git a/kryonet/src/io/anuke/kryonet/ByteSerializer.java b/kryonet/src/io/anuke/kryonet/ByteSerializer.java new file mode 100644 index 0000000000..257ffce93c --- /dev/null +++ b/kryonet/src/io/anuke/kryonet/ByteSerializer.java @@ -0,0 +1,61 @@ +package io.anuke.kryonet; + +import com.badlogic.gdx.utils.reflect.ClassReflection; +import com.badlogic.gdx.utils.reflect.ReflectionException; +import com.esotericsoftware.kryonet.FrameworkMessage; +import com.esotericsoftware.kryonet.serialization.Serialization; +import io.anuke.mindustry.net.Packet; +import io.anuke.mindustry.net.Registrator; + +import java.nio.ByteBuffer; + +public class ByteSerializer implements Serialization { + + @Override + public void write(ByteBuffer byteBuffer, Object o) { + if(o instanceof FrameworkMessage){ + byteBuffer.put((byte)-2); //code for framework message + FrameworkSerializer.write(byteBuffer, (FrameworkMessage)o); + }else { + if (!(o instanceof Packet)) + throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass()); + byte id = Registrator.getID(o.getClass()); + if (id == -1) + throw new RuntimeException("Unregistered class: " + ClassReflection.getSimpleName(o.getClass())); + byteBuffer.put(id); + ((Packet) o).write(byteBuffer); + } + } + + @Override + public Object read(ByteBuffer byteBuffer) { + try { + byte id = byteBuffer.get(); + if(id == -2){ + return FrameworkSerializer.read(byteBuffer); + }else { + Class type = Registrator.getByID(id); + Packet packet = (Packet) ClassReflection.newInstance(type); + packet.read(byteBuffer); + return packet; + } + }catch (ReflectionException e){ + throw new RuntimeException(e); + } + } + + @Override + public int getLengthLength() { + return 2; + } + + @Override + public void writeLength(ByteBuffer byteBuffer, int i) { + byteBuffer.putShort((short)i); + } + + @Override + public int readLength(ByteBuffer byteBuffer) { + return byteBuffer.getShort(); + } +} diff --git a/kryonet/src/io/anuke/kryonet/FrameworkSerializer.java b/kryonet/src/io/anuke/kryonet/FrameworkSerializer.java new file mode 100644 index 0000000000..ac3d8ae65d --- /dev/null +++ b/kryonet/src/io/anuke/kryonet/FrameworkSerializer.java @@ -0,0 +1,69 @@ +package io.anuke.kryonet; + +import com.esotericsoftware.kryonet.FrameworkMessage; +import com.esotericsoftware.kryonet.FrameworkMessage.*; + +import java.nio.ByteBuffer; + +public class FrameworkSerializer { + + public static void write(ByteBuffer buffer, FrameworkMessage message){ + if(message instanceof Ping){ + Ping p = (Ping)message; + + buffer.put((byte)0); + buffer.putInt(p.id); + buffer.put(p.isReply ? 1 : (byte)0); + }else if(message instanceof DiscoverHost){ + DiscoverHost p = (DiscoverHost)message; + + buffer.put((byte)1); + }else if(message instanceof KeepAlive){ + KeepAlive p = (KeepAlive)message; + + buffer.put((byte)2); + }else if(message instanceof RegisterUDP){ + RegisterUDP p = (RegisterUDP)message; + + buffer.put((byte)3); + buffer.putInt(p.connectionID); + }else if(message instanceof RegisterTCP){ + RegisterTCP p = (RegisterTCP)message; + + buffer.put((byte)4); + buffer.putInt(p.connectionID); + } + } + + public static FrameworkMessage read(ByteBuffer buffer){ + byte id = buffer.get(); + + if(id == 0){ + Ping p = new Ping(); + p.id = buffer.getInt(); + p.isReply = buffer.get() == 1; + + return p; + }else if(id == 1){ + DiscoverHost p = new DiscoverHost(); + + return p; + }else if(id == 2){ + KeepAlive p = new KeepAlive(); + + return p; + }else if(id == 3){ + RegisterUDP p = new RegisterUDP(); + p.connectionID = buffer.getInt(); + + return p; + }else if(id == 4){ + RegisterTCP p = new RegisterTCP(); + p.connectionID = buffer.getInt(); + + return p; + }else{ + throw new RuntimeException("Unknown framework message!"); + } + } +} diff --git a/kryonet/src/io/anuke/kryonet/KryoClient.java b/kryonet/src/io/anuke/kryonet/KryoClient.java index fc358225ed..3a4bc0dd50 100644 --- a/kryonet/src/io/anuke/kryonet/KryoClient.java +++ b/kryonet/src/io/anuke/kryonet/KryoClient.java @@ -52,7 +52,7 @@ public class KryoClient implements ClientProvider{ } }; - client = new Client(8192, 2048); + client = new Client(8192, 2048, connection -> new ByteSerializer()); client.setDiscoveryHandler(handler); Listener listener = new Listener(){ @@ -211,12 +211,7 @@ public class KryoClient implements ClientProvider{ } @Override - public void register(Class... types) { - for(Class c : types){ - client.getKryo().register(c); - } - KryoRegistrator.register(client.getKryo()); - } + public void register(Class... types) { } @Override public void dispose(){ diff --git a/kryonet/src/io/anuke/kryonet/KryoServer.java b/kryonet/src/io/anuke/kryonet/KryoServer.java index e312177724..a507b7f081 100644 --- a/kryonet/src/io/anuke/kryonet/KryoServer.java +++ b/kryonet/src/io/anuke/kryonet/KryoServer.java @@ -30,7 +30,7 @@ public class KryoServer implements ServerProvider { IntArray connections = new IntArray(); public KryoServer(){ - server = new Server(4096*2, 2048); //TODO tweak + server = new Server(4096*2, 2048, connection -> new ByteSerializer()); //TODO tweak server.setDiscoveryHandler((datagramChannel, fromAddress) -> { ByteBuffer buffer = KryoRegistrator.writeServerData(); UCore.log("Replying to discover request with buffer of size " + buffer.capacity()); @@ -107,7 +107,7 @@ public class KryoServer implements ServerProvider { } KickPacket p = new KickPacket(); - p.reason = (byte)KickReason.kick.ordinal(); + p.reason = KickReason.kick; conn.sendTCP(p); Timers.runTask(1f, () -> { @@ -198,12 +198,7 @@ public class KryoServer implements ServerProvider { } @Override - public void register(Class... types) { - for(Class c : types){ - server.getKryo().register(c); - } - KryoRegistrator.register(server.getKryo()); - } + public void register(Class... types) { } @Override public void dispose(){