Added more mongo persistence functions and HCAP reading/writing utilities

This commit is contained in:
Josh Larson
2019-02-04 19:53:40 -06:00
parent d08a091fd4
commit 9f0e9fd4fa
13 changed files with 592 additions and 63 deletions

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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)

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;