Basic updates to existing classes and added EnumLookup

This commit is contained in:
Josh Larson
2017-05-21 11:27:55 -05:00
parent 13265130cb
commit 820ddfe4a2
14 changed files with 434 additions and 202 deletions

View File

@@ -32,31 +32,65 @@ import java.util.concurrent.locks.LockSupport;
public class Delay {
/**
* Sleeps for the specified number of nanoseconds
* @param nanos the number of nanoseconds to sleep
* @return TRUE if this operation has been interrupted
*/
public static boolean sleepNano(long nanos) {
LockSupport.parkNanos(nanos);
return isInterrupted();
}
/**
* Sleeps for the specified number of microseconds
* @param micro the number of microseconds to sleep
* @return TRUE if this operation has been interrupted
*/
public static boolean sleepMicro(long micro) {
return sleepNano(micro * 1000);
}
/**
* Sleeps for the specified number of milliseconds
* @param milli the number of milliseconds to sleep
* @return TRUE if this operation has been interrupted
*/
public static boolean sleepMilli(long milli) {
return sleepNano(milli * 1000000);
}
/**
* Sleeps for the specified number of seconds
* @param sec the number of seconds to sleep
* @return TRUE if this operation has been interrupted
*/
public static boolean sleepSeconds(long sec) {
return sleepNano(sec * 1000000000);
}
/**
* Sleeps for the specified amount of time
* @param time the amount of time to sleep
* @param unit the unit of time
* @return TRUE if this operation has been interrupted
*/
public static boolean sleep(long time, TimeUnit unit) {
return sleepNano(unit.toNanos(time));
}
/**
* Returns whether or not this thread has been interrupted
* @return TRUE if interrupted, FALSE otherwise
*/
public static boolean isInterrupted() {
return Thread.currentThread().isInterrupted();
}
/**
* Clears the interrupted flag so future calls to isInterrupted will return
* FALSE
*/
public static void clearInterrupted() {
Thread.interrupted();
}

View File

@@ -27,6 +27,8 @@
***********************************************************************************/
package com.projectswg.common.control;
import com.projectswg.common.debug.Assert;
public class IntentChain {
private final IntentManager intentManager;
@@ -64,4 +66,12 @@ public class IntentChain {
}
}
public static void broadcastChain(Intent ... intents) {
Assert.test(intents.length > 0, "Intent length must be greater than 0!");
for (int i = 1; i < intents.length; i++) {
intents[i].broadcastAfterIntent(intents[i-1]);
}
intents[0].broadcast();
}
}

View File

@@ -27,8 +27,6 @@
***********************************************************************************/
package com.projectswg.common.data;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import com.projectswg.common.encoding.Encodable;
@@ -110,11 +108,16 @@ public class CRC implements Encodable, Persistable {
}
@Override
public void decode(ByteBuffer data) {
this.crc = data.order(ByteOrder.LITTLE_ENDIAN).getInt();
public void decode(NetBuffer data) {
this.crc = data.getInt();
this.str = getString(crc);
}
@Override
public int getLength() {
return 4;
}
@Override
public void save(NetBufferStream stream) {
stream.addInt(crc);

View File

@@ -0,0 +1,36 @@
package com.projectswg.common.data;
import java.util.HashMap;
import java.util.Map;
public class EnumLookup<K, T extends Enum<?>> {
private final Map<K, T> lookup;
public EnumLookup(Class<T> c, CustomLookupAdder<K, T> adder) {
lookup = new HashMap<>();
for (T t : c.getEnumConstants()) {
lookup.put(adder.getKey(t), t);
}
}
public T getEnum(K k, T def) {
T t = lookup.get(k);
if (t == null)
return def;
return t;
}
public boolean containsEnum(K k) {
return lookup.containsKey(k);
}
public int size() {
return lookup.size();
}
public interface CustomLookupAdder<K, T> {
K getKey(T t);
}
}

View File

@@ -28,7 +28,6 @@
package com.projectswg.common.data;
import java.awt.Color;
import java.nio.ByteBuffer;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
@@ -63,10 +62,15 @@ public class RGB implements Encodable {
}
@Override
public void decode(ByteBuffer data) {
r = data.get();
g = data.get();
b = data.get();
public void decode(NetBuffer data) {
r = data.getByte();
g = data.getByte();
b = data.getByte();
}
@Override
public int getLength() {
return 3;
}
public byte getR() {

View File

@@ -27,8 +27,6 @@
***********************************************************************************/
package com.projectswg.common.data.location;
import java.nio.ByteBuffer;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
@@ -44,7 +42,7 @@ public class Location implements Encodable, Persistable {
this(Double.NaN, Double.NaN, Double.NaN, null);
}
public Location(Location l) {
public Location(Location l) {
this(l.getX(), l.getY(), l.getZ(), l.terrain);
orientation.set(l.orientation);
}
@@ -55,19 +53,44 @@ public class Location implements Encodable, Persistable {
this.terrain = terrain;
}
public void setTerrain(Terrain terrain) { this.terrain = terrain; }
public void setX(double x) { point.setX(x); }
public void setY(double y) { point.setY(y); }
public void setZ(double z) { point.setZ(z); }
public void setOrientationX(double oX) { orientation.setX(oX); }
public void setOrientationY(double oY) { orientation.setY(oY); }
public void setOrientationZ(double oZ) { orientation.setZ(oZ); }
public void setOrientationW(double oW) { orientation.setW(oW); }
public void setTerrain(Terrain terrain) {
this.terrain = terrain;
}
public void setX(double x) {
point.setX(x);
}
public void setY(double y) {
point.setY(y);
}
public void setZ(double z) {
point.setZ(z);
}
public void setOrientationX(double oX) {
orientation.setX(oX);
}
public void setOrientationY(double oY) {
orientation.setY(oY);
}
public void setOrientationZ(double oZ) {
orientation.setZ(oZ);
}
public void setOrientationW(double oW) {
orientation.setW(oW);
}
public void setPosition(double x, double y, double z) {
setX(x);
setY(y);
setZ(z);
}
public void setOrientation(double oX, double oY, double oZ, double oW) {
setOrientationX(oX);
setOrientationY(oY);
@@ -75,24 +98,56 @@ public class Location implements Encodable, Persistable {
setOrientationW(oW);
}
public Terrain getTerrain() { return terrain; }
public double getX() { return point.getX(); }
public double getY() { return point.getY(); }
public double getZ() { return point.getZ(); }
public Point3D getPosition() { return new Point3D(point); }
public double getOrientationX() { return orientation.getX(); }
public double getOrientationY() { return orientation.getY(); }
public double getOrientationZ() { return orientation.getZ(); }
public double getOrientationW() { return orientation.getW(); }
public Quaternion getOrientation() { return new Quaternion(orientation); }
public Terrain getTerrain() {
return terrain;
}
public double getX() {
return point.getX();
}
public double getY() {
return point.getY();
}
public double getZ() {
return point.getZ();
}
public Point3D getPosition() {
return new Point3D(point);
}
public double getOrientationX() {
return orientation.getX();
}
public double getOrientationY() {
return orientation.getY();
}
public double getOrientationZ() {
return orientation.getZ();
}
public double getOrientationW() {
return orientation.getW();
}
public Quaternion getOrientation() {
return new Quaternion(orientation);
}
public boolean isWithinDistance(Location l, double x, double y, double z) {
if (getTerrain() != l.getTerrain())
return false;
double xD = Math.abs(getX() - l.getX());
double yD = Math.abs(getY() - l.getY());
double zD = Math.abs(getZ() - l.getZ());
return xD <= x && yD <= y && zD <= z;
if (Math.abs(getX() - l.getX()) > x)
return false;
if (Math.abs(getY() - l.getY()) > y)
return false;
if (Math.abs(getZ() - l.getZ()) > z)
return false;
return true;
}
public boolean isWithinDistance(Location l, double radius) {
@@ -102,14 +157,14 @@ public class Location implements Encodable, Persistable {
public boolean isWithinDistance(Terrain t, double x, double y, double z, double radius) {
if (getTerrain() != t)
return false;
return square(getX()-x) + square(getY()-y) + square(getZ()-z) <= square(radius);
return square(getX() - x) + square(getY() - y) + square(getZ() - z) <= square(radius);
}
public boolean isWithinFlatDistance(Location l, double radius) {
return isWithinFlatDistance(l.point, radius);
}
public boolean isWithinFlatDistance(Point3D target, double radius){
public boolean isWithinFlatDistance(Point3D target, double radius) {
return square(getX() - target.getX()) + square(getZ() - target.getZ()) <= square(radius);
}
@@ -120,7 +175,7 @@ public class Location implements Encodable, Persistable {
}
public void translateLocation(Location l) {
point.rotateAround(l.getX(), l.getY(), l.getZ(), l.orientation);
point.rotateAround(l.getX(), l.getY(), l.getZ(), l.orientation);
orientation.rotateByQuaternion(l.orientation);
}
@@ -132,6 +187,7 @@ public class Location implements Encodable, Persistable {
/**
* Sets the orientation to be facing the specified heading
*
* @param heading the heading to face, in degrees
*/
public void setHeading(double heading) {
@@ -140,6 +196,7 @@ public class Location implements Encodable, Persistable {
/**
* Rotates the orientation by the specified angle along the Y-axis
*
* @param angle the angle to rotate by in degrees
*/
public void rotateHeading(double angle) {
@@ -148,6 +205,7 @@ public class Location implements Encodable, Persistable {
/**
* Rotates the orientation by the specified angle along the specified axises
*
* @param angle the angle to rotate by in degrees
* @param axisX the amount of rotation about the x-axis
* @param axisY the amount of rotation about the x-axis
@@ -158,34 +216,13 @@ public class Location implements Encodable, Persistable {
}
public void mergeWith(Location l) {
if (terrain == null || terrain != l.getTerrain())
terrain = l.getTerrain();
mergeLocation(l.getX(), l.getY(), l.getZ());
mergeOrientation(l);
}
public void mergeLocation(double lX, double lY, double lZ) {
if (!isEqual(getX(), lX))
point.setX(lX);
if (!isEqual(getY(), lY))
point.setY(lY);
if (!isEqual(getZ(), lZ))
point.setZ(lZ);
}
private void mergeOrientation(Location l) {
if (!isEqual(getOrientationX(), l.getOrientationX()))
orientation.setX(l.getOrientationX());
if (!isEqual(getOrientationY(), l.getOrientationY()))
orientation.setY(l.getOrientationY());
if (!isEqual(getOrientationZ(), l.getOrientationZ()))
orientation.setZ(l.getOrientationZ());
if (!isEqual(getOrientationW(), l.getOrientationW()))
orientation.setW(l.getOrientationW());
this.terrain = l.getTerrain();
this.point.set(l.getX(), l.getY(), l.getZ());
this.orientation.set(l.getOrientationX(), l.getOrientationY(), l.getOrientationZ(), l.getOrientationW());
}
public double getSpeed(Location l, double deltaTime) {
double dist = Math.sqrt(square(getX()-l.getX()) + square(getY()-l.getY()) + square(getZ()-l.getZ()));
double dist = Math.sqrt(square(getX() - l.getX()) + square(getY() - l.getY()) + square(getZ() - l.getZ()));
return dist / deltaTime;
}
@@ -194,9 +231,10 @@ public class Location implements Encodable, Persistable {
}
private double square(double x) {
return x*x;
return x * x;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Location))
return false;
@@ -223,13 +261,14 @@ public class Location implements Encodable, Persistable {
return true;
}
@Override
public int hashCode() {
return hash(getX())*13 + hash(getY())*17 + hash(getZ())*19 + hash(getOrientationX())*23 + hash(getOrientationY())*29 + hash(getOrientationZ())*31 + hash(getOrientationW())*37;
return hash(getX()) * 13 + hash(getY()) * 17 + hash(getZ()) * 19 + hash(getOrientationX()) * 23 + hash(getOrientationY()) * 29 + hash(getOrientationZ()) * 31 + hash(getOrientationW()) * 37;
}
private int hash(double x) {
long v = Double.doubleToLongBits(x);
return (int)(v^(v>>>32));
return (int) (v ^ (v >>> 32));
}
private boolean isEqual(double x, double y) {
@@ -239,26 +278,31 @@ public class Location implements Encodable, Persistable {
return false;
return Math.abs(x - y) <= 1E-7;
}
@Override
public byte[] encode() {
NetBuffer buf = NetBuffer.allocate(28);
buf.addFloat(safeEncodeDouble(orientation.getX()));
buf.addFloat(safeEncodeDouble(orientation.getY()));
buf.addFloat(safeEncodeDouble(orientation.getZ()));
buf.addFloat(safeEncodeDouble(orientation.getW()));
buf.addFloat(safeEncodeDouble(point.getX()));
buf.addFloat(safeEncodeDouble(point.getY()));
buf.addFloat(safeEncodeDouble(point.getZ()));
buf.addFloat((float) orientation.getX());
buf.addFloat((float) orientation.getY());
buf.addFloat((float) orientation.getZ());
buf.addFloat((float) orientation.getW());
buf.addFloat((float) point.getX());
buf.addFloat((float) point.getY());
buf.addFloat((float) point.getZ());
return buf.array();
}
@Override
public void decode(ByteBuffer data) {
public void decode(NetBuffer data) {
orientation.decode(data);
point.decode(data);
}
@Override
public int getLength() {
return 28;
}
@Override
public void save(NetBufferStream stream) {
stream.addByte(0);
@@ -277,7 +321,7 @@ public class Location implements Encodable, Persistable {
if (stream.getBoolean())
terrain = Terrain.valueOf(stream.getAscii());
}
@Override
public String toString() {
return String.format("Location[TRN=%s, %s %s]", terrain, point, orientation);
@@ -295,8 +339,12 @@ public class Location implements Encodable, Persistable {
return Math.sqrt(square(dstX - getX()) + square(dstY - getY()) + square(dstZ - getZ()));
}
private float safeEncodeDouble(double d) {
return (float) (Double.isNaN(d) ? 0 : d);
public double flatDistanceTo(Location destination) {
return flatDistanceTo(destination.getX(), destination.getZ());
}
public double flatDistanceTo(double dstX, double dstZ) {
return Math.sqrt(square(dstX - getX()) + square(dstZ - getZ()));
}
}

View File

@@ -27,8 +27,6 @@
***********************************************************************************/
package com.projectswg.common.data.location;
import java.nio.ByteBuffer;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
@@ -107,11 +105,15 @@ public class Point3D implements Encodable, Persistable {
}
@Override
public void decode(ByteBuffer data) {
NetBuffer buf = NetBuffer.wrap(data);
x = buf.getFloat();
y = buf.getFloat();
z = buf.getFloat();
public void decode(NetBuffer data) {
x = data.getFloat();
y = data.getFloat();
z = data.getFloat();
}
@Override
public int getLength() {
return 12;
}
@Override
@@ -128,6 +130,7 @@ public class Point3D implements Encodable, Persistable {
z = stream.getFloat();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Point3D))
return false;
@@ -140,10 +143,12 @@ public class Point3D implements Encodable, Persistable {
return true;
}
@Override
public int hashCode() {
return Double.hashCode(getX()) ^ Double.hashCode(getY()) ^ Double.hashCode(getZ());
}
@Override
public String toString() {
return String.format("Point3D[%.2f, %.2f, %.2f]", x, y, z);
}

View File

@@ -27,8 +27,6 @@
***********************************************************************************/
package com.projectswg.common.data.location;
import java.nio.ByteBuffer;
import com.projectswg.common.encoding.Encodable;
import com.projectswg.common.network.NetBuffer;
import com.projectswg.common.network.NetBufferStream;
@@ -162,15 +160,19 @@ public class Quaternion implements Encodable, Persistable {
}
@Override
public void decode(ByteBuffer data) {
NetBuffer buf = NetBuffer.wrap(data);
x = buf.getFloat();
y = buf.getFloat();
z = buf.getFloat();
w = buf.getFloat();
public void decode(NetBuffer data) {
x = data.getFloat();
y = data.getFloat();
z = data.getFloat();
w = data.getFloat();
updateRotationMatrix();
}
@Override
public int getLength() {
return 16;
}
@Override
public void save(NetBufferStream stream) {
stream.addFloat((float) x);
@@ -188,6 +190,7 @@ public class Quaternion implements Encodable, Persistable {
updateRotationMatrix();
}
@Override
public String toString() {
return String.format("Quaternion[%.3f, %.3f, %.3f, %.3f]", x, y, z, w);
}

View File

@@ -28,11 +28,10 @@
package com.projectswg.common.data.location;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import com.projectswg.common.data.CRC;
import com.projectswg.common.data.EnumLookup;
public enum Terrain {
ADVENTURE1 ("terrain/adventure1.trn"),
@@ -103,35 +102,34 @@ public enum Terrain {
WATERTABLETEST ("terrain/watertabletest.trn"),
YAVIN4 ("terrain/yavin4.trn");
private static final Map <Integer, String> CRC_TO_NAME = new ConcurrentHashMap<>();
private static final Map <String, Integer> NAME_TO_CRC = new ConcurrentHashMap<>();
private static final Map <String, Terrain> NAME_TO_TERRAIN = new ConcurrentHashMap<>();
private static final Map <Integer, Terrain> CRC_TO_TERRAIN = new ConcurrentHashMap<>();
private static final EnumLookup<Integer, Terrain> CRC_LOOKUP = new EnumLookup<>(Terrain.class, t -> t.getCrc());
private static final EnumLookup<String, Terrain> NAME_LOOKUP = new EnumLookup<>(Terrain.class, t -> t.getName());
private String file;
private String name;
private int crc;
static {
for (Terrain p : values()) {
CRC_TO_TERRAIN.put(p.getCrc(), p);
CRC_TO_NAME.put(p.getCrc(), p.name());
NAME_TO_CRC.put(p.name().toLowerCase(Locale.US), p.getCrc());
NAME_TO_CRC.put(p.name().toLowerCase(Locale.US), p.getCrc());
NAME_TO_TERRAIN.put(p.name().toLowerCase(Locale.US), p);
}
}
Terrain(String file) {
this.file = file;
this.name = file.substring(8, file.length() - 4);
this.crc = CRC.getCrc(name);
}
public String getFile() { return file; }
public String getName() { return name; }
public String getNameCapitalized() { return Character.toUpperCase(name.charAt(0)) + name.substring(1); }
public int getCrc() { return crc; }
public String getFile() {
return file;
}
public String getName() {
return name;
}
public String getNameCapitalized() {
return Character.toUpperCase(name.charAt(0)) + name.substring(1);
}
public int getCrc() {
return crc;
}
public Location getStartLocation() {
Location l = new Location();
@@ -149,45 +147,35 @@ public enum Terrain {
}
public static int getTerrainCount() {
return CRC_TO_TERRAIN.size();
return CRC_LOOKUP.size();
}
public static String getNameFromCrc(int crc) {
String name = CRC_TO_NAME.get(crc);
if (name == null)
return "";
return name;
Terrain t = CRC_LOOKUP.getEnum(crc, null);
return (t == null) ? "" : t.getName();
}
public static int getCrcFromName(String name) {
Integer crc = NAME_TO_CRC.get(name.toLowerCase(Locale.ENGLISH));
if (crc == null)
return 0;
return crc;
Terrain t = NAME_LOOKUP.getEnum(name.toLowerCase(Locale.ENGLISH), null);
return (t == null) ? 0 : t.getCrc();
}
/**
* Note: Defaults to TATOOINE
*/
public static Terrain getTerrainFromCrc(int crc) {
Terrain p = CRC_TO_TERRAIN.get(crc);
if (p == null)
return TATOOINE;
return p;
return CRC_LOOKUP.getEnum(crc, null);
}
/**
* Note: Defaults to TATOOINE
*/
public static Terrain getTerrainFromName(String name) {
Terrain p = NAME_TO_TERRAIN.get(name.toLowerCase(Locale.ENGLISH));
if (p == null)
return TATOOINE;
return p;
return NAME_LOOKUP.getEnum(name.toLowerCase(Locale.ENGLISH), null);
}
public static boolean doesTerrainExistForName(String name) {
return NAME_TO_TERRAIN.containsKey(name.toLowerCase(Locale.ENGLISH));
return NAME_LOOKUP.containsEnum(name.toLowerCase(Locale.ENGLISH));
}
}

View File

@@ -92,7 +92,7 @@ public class Assert {
Log.e(e);
}
private static class AssertionException extends RuntimeException {
public static class AssertionException extends RuntimeException {
private static final long serialVersionUID = 1L;

View File

@@ -26,9 +26,10 @@
******************************************************************************/
package com.projectswg.common.encoding;
import java.nio.ByteBuffer;
import com.projectswg.common.network.NetBuffer;
public interface Encodable {
void decode(NetBuffer data);
byte [] encode();
void decode(ByteBuffer data);
int getLength();
}

View File

@@ -29,8 +29,10 @@ package com.projectswg.common.network;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.projectswg.common.debug.Log;
import com.projectswg.common.encoding.Encodable;
@@ -39,8 +41,8 @@ import com.projectswg.common.encoding.StringType;
public class NetBuffer {
public static final Charset ASCII = Charset.forName("UTF-8");
public static final Charset UNICODE = Charset.forName("UTF-16LE");
public final Charset ASCII = Charset.forName("UTF-8");
public final Charset UNICODE = Charset.forName("UTF-16LE");
private final ByteBuffer data;
private final int size;
@@ -74,6 +76,14 @@ public class NetBuffer {
return data.position();
}
public int limit() {
return data.limit();
}
public int capacity() {
return data.capacity();
}
public void position(int position) {
data.position(position);
}
@@ -82,32 +92,32 @@ public class NetBuffer {
data.position(data.position()+relative);
}
public void flip() {
data.flip();
}
public ByteBuffer getBuffer() {
return data;
}
public void add(NetBuffer buffer) {
add(buffer.getBuffer());
}
public void add(ByteBuffer buffer) {
data.put(buffer);
}
public void addBoolean(boolean b) {
data.put(b ? (byte)1 : (byte)0);
}
public void addAscii(String s) {
data.order(ByteOrder.LITTLE_ENDIAN);
data.putShort((short)s.length());
data.put(s.getBytes(ASCII));
}
public void addAscii(char [] s) {
data.order(ByteOrder.LITTLE_ENDIAN);
data.putShort((short)s.length);
ByteBuffer bb = ASCII.encode(CharBuffer.wrap(s));
byte [] bData = new byte[bb.limit()];
bb.get(bData);
data.put(bData);
addArray(s.getBytes(ASCII));
}
public void addUnicode(String s) {
data.order(ByteOrder.LITTLE_ENDIAN);
data.putInt(s.length());
addInt(s.length());
data.put(s.getBytes(UNICODE));
}
@@ -120,7 +130,7 @@ public class NetBuffer {
}
public void addFloat(float f) {
data.putFloat(f);
data.order(ByteOrder.LITTLE_ENDIAN).putFloat(f);
}
public void addShort(int i) {
@@ -148,10 +158,47 @@ public class NetBuffer {
data.put(b);
}
public void addArrayLarge(byte [] b) {
addInt(b.length);
data.put(b);
}
public void addRawArray(byte [] b) {
data.put(b);
}
public void addList(Collection<? extends Encodable> list) {
if (list == null) {
addInt(0);
return;
}
addInt(list.size());
for (Encodable encodable : list) {
addEncodable(encodable);
}
}
public void addList(List<String> list, StringType type) {
addInt(list.size());
switch (type) {
case ASCII:
for (String s : list) {
addAscii(s);
}
break;
case UNICODE:
for (String s : list) {
addUnicode(s);
}
break;
default:
Log.e("Cannot encode StringType " + type);
break;
}
}
public void addEncodable(Encodable e) {
data.put(e.encode());
}
@@ -161,23 +208,11 @@ public class NetBuffer {
}
public String getAscii() {
data.order(ByteOrder.LITTLE_ENDIAN);
short length = data.getShort();
if (length > data.remaining())
return "";
byte [] str = new byte[length];
data.get(str);
return new String(str, ASCII);
return new String(getArray(), ASCII);
}
public String getUnicode() {
data.order(ByteOrder.LITTLE_ENDIAN);
int length = data.getInt() * 2;
if (length > data.remaining())
return "";
byte [] str = new byte[length];
data.get(str);
return new String(str, UNICODE);
return new String(getArray(getInt() * 2), UNICODE);
}
public String getString(StringType type) {
@@ -221,9 +256,11 @@ public class NetBuffer {
}
public byte [] getArray() {
byte [] bData = new byte[getShort()];
data.get(bData);
return bData;
return getArray(getShort());
}
public byte [] getArrayLarge() {
return getArray(getInt());
}
public byte [] getArray(int size) {
@@ -232,12 +269,33 @@ public class NetBuffer {
return bData;
}
public int [] getIntArray() {
int [] ints = new int[getInt()];
for (int i = 0; i < ints.length; i++)
ints[i] = getInt();
return ints;
}
public int [] getIntArray(int size) {
int [] ints = new int[size];
for (int i = 0; i < ints.length; i++)
ints[i] = getInt();
return ints;
}
public boolean[] getBooleanArray() {
boolean[] booleans = new boolean[getInt()];
for(int i = 0; i < booleans.length; i++)
booleans[i] = getBoolean();
return booleans;
}
public <T> Object getGeneric(Class<T> type) {
if (Encodable.class.isAssignableFrom(type)) {
T instance = null;
try {
instance = type.newInstance();
((Encodable) instance).decode(data);
((Encodable) instance).decode(this);
} catch (InstantiationException | IllegalAccessException e) {
Log.e(e);
}
@@ -256,11 +314,69 @@ public class NetBuffer {
return null;
}
public <T extends Encodable> List<T> getList(Class<T> type) {
int size = getInt();
if (size < 0) {
Log.e("Read list with size less than zero!");
return null;
} else if (size == 0) {
return new ArrayList<>();
}
List<T> list = new ArrayList<>();
try {
for (int i = 0; i < size; i++) {
T instance = type.newInstance();
instance.decode(this);
list.add(instance);
}
} catch (InstantiationException | IllegalAccessException e) {
Log.e(e);
}
if (size != list.size())
Log.e("Expected list size %d but only have %d elements in the list", size, list.size());
return list;
}
public List<String> getList(StringType type) {
int size = getInt();
if (size < 0) {
Log.e("Read list with size less than zero!");
return null;
} else if (size == 0) {
return new ArrayList<>();
}
List<String> list = new ArrayList<>();
switch (type) {
case ASCII:
for (int i = 0; i < size; i++) {
list.add(getAscii());
}
break;
case UNICODE:
for (int i = 0; i < size; i++) {
list.add(getUnicode());
}
break;
default:
Log.e("Do not know how to read list of StringType " + type);
break;
}
return list;
}
public <T extends Encodable> T getEncodable(Class<T> type) {
T instance = null;
try {
instance = type.newInstance();
instance.decode(data);
instance.decode(this);
} catch (InstantiationException | IllegalAccessException e) {
Log.e(e);
}

View File

@@ -110,10 +110,12 @@ public class NetBufferStream extends OutputStream {
}
}
@Override
public void write(byte [] data) {
write(data, 0, data.length);
}
@Override
public void write(byte [] data, int offset, int length) {
ensureCapacity(size + length);
synchronized (bufferMutex) {
@@ -281,14 +283,6 @@ public class NetBufferStream extends OutputStream {
}
}
public void addAscii(char[] s) {
ensureCapacity(size+2+s.length);
synchronized (bufferMutex) {
buffer.addAscii(s);
size += 2 + s.length;
}
}
public void addUnicode(String s) {
ensureCapacity(size+4+s.length()*2);
synchronized (bufferMutex) {

View File

@@ -30,7 +30,6 @@ package com.projectswg.common.network;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedByInterruptException;
@@ -95,12 +94,12 @@ public class TCPServer {
Assert.notNull(sock);
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
Assert.notNull(sc);
if (sc == null)
return true;
sockets.remove(sock);
try {
Socket s = sc.socket();
sc.close();
callbackManager.callOnEach((callback) -> callback.onConnectionDisconnect(s, sock));
callbackManager.callOnEach((callback) -> callback.onConnectionDisconnect(sc, sock));
return true;
} catch (IOException e) {
Log.e(e);
@@ -133,22 +132,10 @@ public class TCPServer {
return false;
}
public boolean send(InetSocketAddress sock, ByteBuffer data) {
public SocketChannel getChannel(SocketAddress sock) {
synchronized (sockets) {
SocketChannel sc = sockets.get(sock);
Assert.notNull(sc);
Assert.test(sc.isConnected());
Assert.test(data.hasRemaining());
try {
while (data.hasRemaining())
sc.write(data);
return true;
} catch (IOException e) {
Log.e("TCPServer", "Terminated connection with %s. Error: %s", sock.toString(), e.getMessage());
disconnect(sc);
}
return sockets.get(sock);
}
return false;
}
public void setCallback(TCPCallback callback) {
@@ -156,9 +143,9 @@ public class TCPServer {
}
public interface TCPCallback {
void onIncomingConnection(Socket s);
void onConnectionDisconnect(Socket s, SocketAddress addr);
void onIncomingData(Socket s, byte [] data);
void onIncomingConnection(SocketChannel s, SocketAddress addr);
void onConnectionDisconnect(SocketChannel s, SocketAddress addr);
void onIncomingData(SocketChannel s, SocketAddress addr, byte [] data);
}
private class TCPServerListener implements Runnable {
@@ -186,6 +173,7 @@ public class TCPServer {
thread = null;
}
@Override
public void run() {
try (Selector selector = setupSelector()) {
while (running) {
@@ -241,7 +229,8 @@ public class TCPServer {
sockets.put(sc.getRemoteAddress(), sc);
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ);
callbackManager.callOnEach((callback) -> callback.onIncomingConnection(sc.socket()));
SocketAddress addr = sc.getRemoteAddress();
callbackManager.callOnEach((callback) -> callback.onIncomingConnection(sc, addr));
}
} catch (IOException e) {
Log.e(e);
@@ -260,7 +249,8 @@ public class TCPServer {
} else if (n > 0) {
ByteBuffer smaller = ByteBuffer.allocate(n);
smaller.put(buffer);
callbackManager.callOnEach((callback) -> callback.onIncomingData(s.socket(), smaller.array()));
SocketAddress addr = s.getRemoteAddress();
callbackManager.callOnEach((callback) -> callback.onIncomingData(s, addr, smaller.array()));
return true;
}
} catch (IOException e) {