mirror of
https://bitbucket.org/projectswg/pswgcommon.git
synced 2026-01-16 23:04:32 -05:00
Added more mongo persistence functions and HCAP reading/writing utilities
This commit is contained in:
@@ -26,6 +26,8 @@
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.customization;
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData;
|
||||
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
|
||||
import com.projectswg.common.data.swgfile.ClientFactory;
|
||||
import com.projectswg.common.data.swgfile.visitors.CustomizationIDManagerData;
|
||||
import com.projectswg.common.encoding.Encodable;
|
||||
@@ -45,19 +47,21 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* The Customization string is used to set special properties
|
||||
* on objects. This can be lightsaber color, vehicle speed,
|
||||
* facial hair style...
|
||||
*/
|
||||
public class CustomizationString implements Encodable, Persistable {
|
||||
public class CustomizationString implements Encodable, Persistable, MongoPersistable {
|
||||
|
||||
private CustomizationIDManagerData table = (CustomizationIDManagerData) ClientFactory.getInfoFromFile("customization/customization_id_manager.iff");
|
||||
private Map<String, CustomizationVariable> variables;
|
||||
private final CustomizationIDManagerData table;
|
||||
private final Map<String, CustomizationVariable> variables;
|
||||
|
||||
public CustomizationString() {
|
||||
variables = Collections.synchronizedMap(new LinkedHashMap<>()); // Ordered and synchronized
|
||||
this.table = (CustomizationIDManagerData) ClientFactory.getInfoFromFile("customization/customization_id_manager.iff");
|
||||
this.variables = Collections.synchronizedMap(new LinkedHashMap<>()); // Ordered and synchronized
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
@@ -89,6 +93,17 @@ public class CustomizationString implements Encodable, Persistable {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putMap("variables", variables, Function.identity(), CustomizationVariable::getValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMongo(MongoData data) {
|
||||
variables.clear();
|
||||
variables.putAll(data.getMap("variables", Integer.class, CustomizationVariable::new));
|
||||
}
|
||||
|
||||
/**
|
||||
* Puts a new {@link CustomizationVariable} in this {@code CustomizationString}.
|
||||
* @param name is the variable to set
|
||||
|
||||
@@ -28,22 +28,30 @@
|
||||
package com.projectswg.common.data.encodables.mongo;
|
||||
|
||||
import org.bson.Document;
|
||||
import org.bson.types.Binary;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MongoData {
|
||||
public class MongoData implements Map<String, Object> {
|
||||
|
||||
private final @NotNull Document doc;
|
||||
|
||||
public MongoData() {
|
||||
this(new Document());
|
||||
this(0);
|
||||
}
|
||||
|
||||
public MongoData(int version) {
|
||||
this(null);
|
||||
if (version != 0)
|
||||
doc.put("_ver", version);
|
||||
}
|
||||
|
||||
public MongoData(Document doc) {
|
||||
@@ -54,10 +62,29 @@ public class MongoData {
|
||||
return new Document(doc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return doc.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return doc.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof MongoData && doc.equals(((MongoData) o).doc)) || (o instanceof Document && doc.equals(o));
|
||||
}
|
||||
|
||||
public boolean containsKey(String key) {
|
||||
return doc.containsKey(key);
|
||||
}
|
||||
|
||||
public int version() {
|
||||
return doc.getInteger("_ver", 0);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Integer getInteger(String key) {
|
||||
return doc.getInteger(key);
|
||||
@@ -129,24 +156,60 @@ public class MongoData {
|
||||
return d == null ? null : d.toInstant();
|
||||
}
|
||||
|
||||
public byte [] getByteArray(String key) {
|
||||
return getByteArray(key, null);
|
||||
}
|
||||
|
||||
public byte [] getByteArray(String key, byte [] defaultValue) {
|
||||
Binary b = doc.get(key, Binary.class);
|
||||
if (b == null)
|
||||
return defaultValue;
|
||||
return b.getData();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T> List<T> getArray(String key, Class<T> klass) {
|
||||
List<?> mdbArray = doc.get(key, List.class);
|
||||
List<T> ret = new ArrayList<>(mdbArray.size());
|
||||
if (klass == Instant.class) {
|
||||
for (Object o : mdbArray) {
|
||||
if (o == null)
|
||||
ret.add(null);
|
||||
else
|
||||
//noinspection UseOfObsoleteDateTimeApi
|
||||
ret.add(klass.cast(((Date) o).toInstant()));
|
||||
for (Object o : mdbArray) {
|
||||
if (o == null)
|
||||
ret.add(null);
|
||||
else if (klass == Instant.class)
|
||||
//noinspection UseOfObsoleteDateTimeApi
|
||||
ret.add(klass.cast(((Date) o).toInstant()));
|
||||
else if (klass == MongoData.class)
|
||||
ret.add(klass.cast(new MongoData((Document) o)));
|
||||
else
|
||||
ret.add(klass.cast(o));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends MongoPersistable> List<T> getArray(String key, Supplier<T> generator) {
|
||||
List<?> mdbArray = doc.get(key, List.class);
|
||||
List<T> ret = new ArrayList<>(mdbArray.size());
|
||||
for (Object o : mdbArray) {
|
||||
if (o == null) {
|
||||
ret.add(null);
|
||||
} else {
|
||||
T t = generator.get();
|
||||
t.readMongo(new MongoData((Document) o));
|
||||
ret.add(t);
|
||||
}
|
||||
} else {
|
||||
for (Object o : mdbArray) {
|
||||
if (o == null)
|
||||
ret.add(null);
|
||||
else
|
||||
ret.add(klass.cast(o));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends MongoPersistable> List<T> getArray(String key, Function<MongoData, T> generator) {
|
||||
List<?> mdbArray = doc.get(key, List.class);
|
||||
List<T> ret = new ArrayList<>(mdbArray.size());
|
||||
for (Object o : mdbArray) {
|
||||
if (o == null) {
|
||||
ret.add(null);
|
||||
} else {
|
||||
ret.add(generator.apply(new MongoData((Document) o)));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -168,30 +231,50 @@ public class MongoData {
|
||||
public <T extends MongoPersistable> T getDocument(String key, T dataInstance) {
|
||||
Document doc = this.doc.get(key, Document.class);
|
||||
if (doc != null)
|
||||
dataInstance.read(new MongoData(doc));
|
||||
dataInstance.readMongo(new MongoData(doc));
|
||||
return dataInstance;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T> Map<String, T> getMap(String key, Class<T> klass) {
|
||||
return getMap(key, klass, Function.identity(), (k, v) -> v);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T extends MongoPersistable> Map<String, T> getMap(String key, Class<T> klass, Supplier<T> supplier) {
|
||||
return getMap(key, MongoData.class, Function.identity(), (k, v) -> {
|
||||
T ret = supplier.get();
|
||||
ret.readMongo(v);
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <T, V> Map<String, V> getMap(String key, Class<T> klass, Function<T, V> valueParser) {
|
||||
return getMap(key, klass, Function.identity(), valueParser);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <K, T, V> Map<K, V> getMap(String key, Class<T> klass, Function<String, K> keyParser, Function<T, V> valueParser) {
|
||||
return getMap(key, klass, keyParser, (k, v) -> valueParser.apply(v));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public <K, T, V> Map<K, V> getMap(String key, Class<T> klass, Function<String, K> keyParser, BiFunction<K, T, V> valueParser) {
|
||||
Document mdbMap = doc.get(key, Document.class);
|
||||
Map<String, T> ret = new HashMap<>(mdbMap.size());
|
||||
if (klass == Instant.class) {
|
||||
for (Entry<String, Object> e : mdbMap.entrySet()) {
|
||||
Object o = e.getValue();
|
||||
if (o == null)
|
||||
ret.put(e.getKey(), null);
|
||||
else
|
||||
//noinspection UseOfObsoleteDateTimeApi
|
||||
ret.put(e.getKey(), klass.cast(((Date) o).toInstant()));
|
||||
}
|
||||
} else {
|
||||
for (Entry<String, Object> e : mdbMap.entrySet()) {
|
||||
Object o = e.getValue();
|
||||
if (o == null)
|
||||
ret.put(e.getKey(), null);
|
||||
else
|
||||
ret.put(e.getKey(), klass.cast(o));
|
||||
Map<K, V> ret = new HashMap<>(mdbMap.size());
|
||||
for (Entry<String, Object> e : mdbMap.entrySet()) {
|
||||
K childKey = keyParser.apply(e.getKey());
|
||||
Object o = e.getValue();
|
||||
if (o == null) {
|
||||
ret.put(childKey, null);
|
||||
} else if (klass == Instant.class) {
|
||||
//noinspection UseOfObsoleteDateTimeApi
|
||||
ret.put(childKey, valueParser.apply(childKey, klass.cast(((Date) o).toInstant())));
|
||||
} else if (MongoData.class.isAssignableFrom(klass)) {
|
||||
ret.put(childKey, valueParser.apply(childKey, klass.cast(new MongoData((Document) o))));
|
||||
} else {
|
||||
ret.put(childKey, valueParser.apply(childKey, klass.cast(o)));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -209,7 +292,7 @@ public class MongoData {
|
||||
|
||||
public void putFloat(String key, float f) {
|
||||
assert !containsKey(key) : "key already exists";
|
||||
doc.put(key, f);
|
||||
doc.put(key, (double) f);
|
||||
}
|
||||
|
||||
public void putDouble(String key, double d) {
|
||||
@@ -237,12 +320,9 @@ public class MongoData {
|
||||
doc.put(key, Date.from(date));
|
||||
}
|
||||
|
||||
public void putArray(String key, byte [] array) {
|
||||
public void putByteArray(String key, byte [] array) {
|
||||
assert !containsKey(key) : "key already exists";
|
||||
List<Integer> mdbArray = new ArrayList<>(array.length);
|
||||
for (byte b : array)
|
||||
mdbArray.add((int) b);
|
||||
doc.put(key, mdbArray);
|
||||
doc.put(key, new Binary(array));
|
||||
}
|
||||
|
||||
public void putArray(String key, short [] array) {
|
||||
@@ -282,7 +362,7 @@ public class MongoData {
|
||||
doc.put(key, mdbArray);
|
||||
}
|
||||
|
||||
public void putArray(String key, List<?> array) {
|
||||
public void putArray(String key, Collection<?> array) {
|
||||
assert !containsKey(key) : "key already exists";
|
||||
List<Object> mdbArray = new ArrayList<>(array.size());
|
||||
for (Object o : array) {
|
||||
@@ -291,7 +371,7 @@ public class MongoData {
|
||||
doc.put(key, mdbArray);
|
||||
}
|
||||
|
||||
public <T> void putArray(String key, List<T> array, Function<T, ?> converter) {
|
||||
public <T> void putArray(String key, Collection<T> array, Function<T, ?> converter) {
|
||||
assert !containsKey(key) : "key already exists";
|
||||
List<Object> mdbArray = new ArrayList<>(array.size());
|
||||
for (T o : array) {
|
||||
@@ -309,7 +389,7 @@ public class MongoData {
|
||||
assert !containsKey(key) : "key already exists";
|
||||
if (data != null) {
|
||||
MongoData dataDoc = new MongoData();
|
||||
data.save(dataDoc);
|
||||
data.saveMongo(dataDoc);
|
||||
doc.put(key, dataDoc.doc);
|
||||
}
|
||||
}
|
||||
@@ -330,6 +410,14 @@ public class MongoData {
|
||||
putDocument(key, doc);
|
||||
}
|
||||
|
||||
public <T, S> void putMap(String key, Map<T, S> data, Function<T, String> keyExtractor, Function<S, ?> valueExtractor) {
|
||||
MongoData doc = new MongoData();
|
||||
for (Entry<T, S> e : data.entrySet()) {
|
||||
doc.doc.put(keyExtractor.apply(e.getKey()), translatePut(valueExtractor.apply(e.getValue())));
|
||||
}
|
||||
putDocument(key, doc);
|
||||
}
|
||||
|
||||
public <T, S> void putMap(String key, Map<T, S> data, Function<T, String> keyExtractor, BiFunction<T, S, ?> valueExtractor) {
|
||||
MongoData doc = new MongoData();
|
||||
for (Entry<T, S> e : data.entrySet()) {
|
||||
@@ -344,13 +432,95 @@ public class MongoData {
|
||||
return Date.from((Instant) input);
|
||||
} else if (input instanceof String || input instanceof Boolean || input instanceof Long || input instanceof Date || input instanceof Document) {
|
||||
return input;
|
||||
} else if (input instanceof MongoData) {
|
||||
return ((MongoData) input).toDocument();
|
||||
} else if (input instanceof Float || input instanceof Double) {
|
||||
return ((Number) input).doubleValue();
|
||||
} else if (input instanceof Number) {
|
||||
return ((Number) input).intValue();
|
||||
} else
|
||||
assert false : "bad object type: " + input;
|
||||
} else if (input instanceof MongoPersistable) {
|
||||
return store((MongoPersistable) input).toDocument();
|
||||
}
|
||||
assert false : "bad object type: " + input;
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Map functions */
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return doc.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return doc.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return doc.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return doc.containsValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object key) {
|
||||
return doc.get(key);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object put(String key, Object value) {
|
||||
throw new UnsupportedOperationException("must use another put method");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object remove(Object key) {
|
||||
return doc.remove(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void putAll(@NotNull Map<? extends String, ?> m) {
|
||||
throw new UnsupportedOperationException("must use another put method");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
doc.clear();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<String> keySet() {
|
||||
return new HashSet<>(doc.keySet());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return new ArrayList<>(doc.values());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<String, Object>> entrySet() {
|
||||
return doc.entrySet().stream().map(e -> Map.entry(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static MongoData store(MongoPersistable obj) {
|
||||
MongoData data = new MongoData();
|
||||
obj.saveMongo(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
public static <T extends MongoPersistable> T create(MongoData data, Supplier<T> generator) {
|
||||
T ret = generator.get();
|
||||
ret.readMongo(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ package com.projectswg.common.data.encodables.mongo;
|
||||
|
||||
public interface MongoPersistable {
|
||||
|
||||
void read(MongoData data);
|
||||
void save(MongoData data);
|
||||
void readMongo(MongoData data);
|
||||
void saveMongo(MongoData data);
|
||||
|
||||
}
|
||||
|
||||
@@ -97,13 +97,13 @@ public class StringId implements OutOfBandData, Persistable, MongoPersistable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
file = data.getString("file");
|
||||
key = data.getString("key");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putString("file", file);
|
||||
data.putString("key", key);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.encodables.oob.waypoint;
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData;
|
||||
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
|
||||
import com.projectswg.common.data.encodables.oob.OutOfBandData;
|
||||
import com.projectswg.common.data.encodables.oob.OutOfBandPackage;
|
||||
import com.projectswg.common.data.encodables.oob.OutOfBandPackage.Type;
|
||||
@@ -34,7 +36,7 @@ import com.projectswg.common.data.location.Terrain;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.NetBufferStream;
|
||||
|
||||
public class WaypointPackage implements OutOfBandData {
|
||||
public class WaypointPackage implements OutOfBandData, MongoPersistable {
|
||||
|
||||
private Point3D position;
|
||||
|
||||
@@ -146,7 +148,29 @@ public class WaypointPackage implements OutOfBandData {
|
||||
public int getLength() {
|
||||
return 42 + name.length() * 2;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putLong("objectId", objectId);
|
||||
data.putLong("cellId", cellId);
|
||||
data.putDocument("position", position);
|
||||
data.putString("terrain", terrain.name());
|
||||
data.putString("name", name);
|
||||
data.putInteger("color", color.getValue());
|
||||
data.putBoolean("active", active);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMongo(MongoData data) {
|
||||
objectId = data.getLong("objectId", 0);
|
||||
cellId = data.getLong("cellId", 0);
|
||||
data.getDocument("position", position);
|
||||
terrain = Terrain.valueOf(data.getString("terrain", "GONE"));
|
||||
name = data.getString("name", "New Waypoint");
|
||||
color = WaypointColor.valueOf(data.getString("color", "BLUE"));
|
||||
active = data.getBoolean("active", true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(NetBufferStream stream) {
|
||||
stream.addByte(0);
|
||||
|
||||
@@ -26,12 +26,14 @@
|
||||
***********************************************************************************/
|
||||
package com.projectswg.common.data.encodables.tangible;
|
||||
|
||||
import com.projectswg.common.data.encodables.mongo.MongoData;
|
||||
import com.projectswg.common.data.encodables.mongo.MongoPersistable;
|
||||
import com.projectswg.common.encoding.Encodable;
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.NetBufferStream;
|
||||
import com.projectswg.common.persistable.Persistable;
|
||||
|
||||
public class SkillMod implements Encodable, Persistable {
|
||||
public class SkillMod implements Encodable, Persistable, MongoPersistable {
|
||||
|
||||
private int base, modifier;
|
||||
|
||||
@@ -65,6 +67,18 @@ public class SkillMod implements Encodable, Persistable {
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readMongo(MongoData data) {
|
||||
base = data.getInteger("base", 0);
|
||||
modifier = data.getInteger("modifier", 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putInteger("base", base);
|
||||
data.putInteger("modifier", modifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(NetBufferStream stream) {
|
||||
stream.addInt(base);
|
||||
@@ -76,7 +90,7 @@ public class SkillMod implements Encodable, Persistable {
|
||||
base = stream.getInt();
|
||||
modifier = stream.getInt();
|
||||
}
|
||||
|
||||
|
||||
public void adjustBase(int adjustment) {
|
||||
base += adjustment;
|
||||
}
|
||||
|
||||
@@ -246,14 +246,14 @@ public class Location implements Encodable, Persistable, MongoPersistable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
data.getDocument("orientation", orientation);
|
||||
data.getDocument("point", point);
|
||||
terrain = data.containsKey("terrain") ? Terrain.valueOf(data.getString("terrain")) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putDocument("orientation", orientation);
|
||||
data.putDocument("point", point);
|
||||
if (terrain != null)
|
||||
|
||||
@@ -206,14 +206,14 @@ public class Point3D implements Encodable, Persistable, MongoPersistable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
x = data.getDouble("x", 0);
|
||||
y = data.getDouble("y", 0);
|
||||
z = data.getDouble("z", 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putDouble("x", x);
|
||||
data.putDouble("y", y);
|
||||
data.putDouble("z", z);
|
||||
|
||||
@@ -240,7 +240,7 @@ public class Quaternion implements Encodable, Persistable, MongoPersistable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(MongoData data) {
|
||||
public void readMongo(MongoData data) {
|
||||
x = data.getDouble("x", 0);
|
||||
y = data.getDouble("y", 0);
|
||||
z = data.getDouble("z", 0);
|
||||
@@ -248,7 +248,7 @@ public class Quaternion implements Encodable, Persistable, MongoPersistable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(MongoData data) {
|
||||
public void saveMongo(MongoData data) {
|
||||
data.putDouble("x", x);
|
||||
data.putDouble("y", y);
|
||||
data.putDouble("z", z);
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2019 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
|
||||
package com.projectswg.common.network.hcap;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HcapInputStream implements AutoCloseable {
|
||||
|
||||
private final DataInputStream is;
|
||||
private final Map<String, Object> systemInformation;
|
||||
private final byte version;
|
||||
|
||||
public HcapInputStream(InputStream is) throws IOException {
|
||||
this.is = new DataInputStream(is);
|
||||
this.systemInformation = new ConcurrentHashMap<>();
|
||||
|
||||
this.version = this.is.readByte();
|
||||
readSystemInformation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources
|
||||
* associated with the stream.
|
||||
* This method simply performs <code>is.close()</code>.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
* @see DataInputStream#close
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
is.close();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<String, Object> getSystemInformation() {
|
||||
return Collections.unmodifiableMap(systemInformation);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PacketRecord readPacket() throws IOException {
|
||||
if (is.available() >= 11) {
|
||||
boolean server = is.readBoolean();
|
||||
Instant time = Instant.ofEpochMilli(is.readLong());
|
||||
int dataLength = version < 4 ? is.readUnsignedShort() : is.readInt();
|
||||
byte [] data = new byte[dataLength];
|
||||
int ret = is.read(data, 0, dataLength);
|
||||
int n = ret;
|
||||
while (n < dataLength && ret >= 0) {
|
||||
ret = is.read(data, n, dataLength - n);
|
||||
n += ret;
|
||||
}
|
||||
if (n != dataLength)
|
||||
return null;
|
||||
return new PacketRecord(server, time, data);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void readSystemInformation() throws IOException {
|
||||
int count = is.readByte();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Map.Entry<String, Object> entry = parseEntry(version, is.readUTF());
|
||||
systemInformation.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static Map.Entry<String, Object> parseEntry(byte version, String str) {
|
||||
String [] keyValue = str.split("=", 2);
|
||||
assert keyValue.length == 2;
|
||||
String key = keyValue[0].toLowerCase(Locale.US);
|
||||
String value = keyValue[1];
|
||||
|
||||
if (version == 2) {
|
||||
switch (key) {
|
||||
case "time.current_time":
|
||||
return Map.entry(key, Instant.ofEpochMilli(Long.parseLong(value)));
|
||||
case "time.time_zone":
|
||||
return Map.entry(key, ZoneId.of(value.split(":")[0]));
|
||||
default:
|
||||
return Map.entry(key, value);
|
||||
}
|
||||
} else if (version >= 3) {
|
||||
switch (key) {
|
||||
case "time.current_time":
|
||||
return Map.entry(key, Instant.parse(value));
|
||||
case "time.time_zone":
|
||||
return Map.entry(key, ZoneId.of(value));
|
||||
default:
|
||||
return Map.entry(key, value);
|
||||
}
|
||||
} else {
|
||||
return Map.entry(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2019 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
|
||||
package com.projectswg.common.network.hcap;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.OperatingSystemMXBean;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public class HcapOutputStream implements AutoCloseable {
|
||||
|
||||
private final DataOutputStream os;
|
||||
|
||||
public HcapOutputStream(OutputStream os) throws IOException {
|
||||
this.os = new DataOutputStream(os);
|
||||
|
||||
this.os.writeByte(3);
|
||||
writeSystemHeader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this input stream and releases any system resources
|
||||
* associated with the stream.
|
||||
* This method simply performs <code>is.close()</code>.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
* @see DataInputStream#close
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
os.close();
|
||||
}
|
||||
|
||||
public void record(PacketRecord record) throws IOException {
|
||||
this.os.writeBoolean(record.isServer());
|
||||
this.os.writeLong(record.getTime().toEpochMilli());
|
||||
this.os.writeShort(record.getData().length);
|
||||
this.os.write(record.getData());
|
||||
}
|
||||
|
||||
private void writeSystemHeader() throws IOException {
|
||||
OperatingSystemMXBean os = ManagementFactory.getOperatingSystemMXBean();
|
||||
Map<String, String> systemStrings = new TreeMap<>();
|
||||
systemStrings.put("os.arch", os.getArch());
|
||||
systemStrings.put("os.details", os.getName()+":"+os.getVersion());
|
||||
systemStrings.put("os.processor_count", Integer.toString(os.getAvailableProcessors()));
|
||||
systemStrings.put("java.version", System.getProperty("java.version"));
|
||||
systemStrings.put("java.vendor", System.getProperty("java.vendor"));
|
||||
systemStrings.put("time.time_zone", ZoneId.systemDefault().getId());
|
||||
systemStrings.put("time.current_time", Instant.now().toString());
|
||||
this.os.writeByte(systemStrings.size()); // Count of strings
|
||||
for (Entry<String, String> e : systemStrings.entrySet())
|
||||
this.os.writeUTF(e.getKey() + "=" + e.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
/***********************************************************************************
|
||||
* Copyright (c) 2019 /// Project SWG /// www.projectswg.com *
|
||||
* *
|
||||
* ProjectSWG is the first NGE emulator for Star Wars Galaxies founded on *
|
||||
* July 7th, 2011 after SOE announced the official shutdown of Star Wars Galaxies. *
|
||||
* Our goal is to create an emulator which will provide a server for players to *
|
||||
* continue playing a game similar to the one they used to play. We are basing *
|
||||
* it on the final publish of the game prior to end-game events. *
|
||||
* *
|
||||
* This file is part of Holocore. *
|
||||
* *
|
||||
* --------------------------------------------------------------------------------*
|
||||
* *
|
||||
* Holocore is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU Affero General Public License as *
|
||||
* published by the Free Software Foundation, either version 3 of the *
|
||||
* License, or (at your option) any later version. *
|
||||
* *
|
||||
* Holocore is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU Affero General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU Affero General Public License *
|
||||
* along with Holocore. If not, see <http://www.gnu.org/licenses/>. *
|
||||
***********************************************************************************/
|
||||
|
||||
package com.projectswg.common.network.hcap;
|
||||
|
||||
import com.projectswg.common.network.NetBuffer;
|
||||
import com.projectswg.common.network.packets.PacketType;
|
||||
import com.projectswg.common.network.packets.SWGPacket;
|
||||
import com.projectswg.common.network.packets.swg.zone.object_controller.ObjectController;
|
||||
import com.projectswg.common.utilities.ByteUtilities;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.time.Instant;
|
||||
|
||||
public class PacketRecord {
|
||||
|
||||
private final boolean server;
|
||||
private final Instant time;
|
||||
private final byte[] data;
|
||||
|
||||
public PacketRecord(boolean server, Instant time, byte[] data) {
|
||||
this.server = server;
|
||||
this.time = time;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return server;
|
||||
}
|
||||
|
||||
public Instant getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public PacketType parseType() {
|
||||
NetBuffer data = NetBuffer.wrap(this.data);
|
||||
data.position(2);
|
||||
return PacketType.fromCrc(data.getInt());
|
||||
}
|
||||
|
||||
public SWGPacket parse() {
|
||||
NetBuffer data = NetBuffer.wrap(this.data);
|
||||
data.position(2);
|
||||
PacketType type = PacketType.fromCrc(data.getInt());
|
||||
data.position(0);
|
||||
SWGPacket packet;
|
||||
if (type == PacketType.OBJECT_CONTROLLER) {
|
||||
return ObjectController.decodeController(data);
|
||||
} else {
|
||||
packet = PacketType.getForCrc(type.getCrc());
|
||||
if (packet != null)
|
||||
packet.decode(data);
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@ module com.projectswg.common {
|
||||
requires transitive me.joshlarson.jlcommon;
|
||||
requires static java.sql;
|
||||
requires static java.desktop;
|
||||
requires transitive java.management;
|
||||
requires org.mongodb.bson;
|
||||
requires org.jetbrains.annotations;
|
||||
requires org.bouncycastle.provider;
|
||||
|
||||
Reference in New Issue
Block a user