diff --git a/src/resources/Location.java b/src/resources/Location.java index db0c5e196..b08120bbf 100644 --- a/src/resources/Location.java +++ b/src/resources/Location.java @@ -29,15 +29,14 @@ package resources; import network.packets.Packet; import resources.encodables.Encodable; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; -public class Location implements Encodable, Serializable { - - private static final long serialVersionUID = 1L; +public class Location implements Encodable, Persistable { private final Point3D point; private final Quaternion orientation; @@ -284,6 +283,25 @@ public class Location implements Encodable, Serializable { orientation.decode(data); point.decode(data); } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + orientation.save(stream); + point.save(stream); + stream.addBoolean(terrain != null); + if (terrain != null) + stream.addAscii(terrain.name()); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + orientation.read(stream); + point.read(stream); + if (stream.getBoolean()) + terrain = Terrain.valueOf(stream.getAscii()); + } @Override public String toString() { diff --git a/src/resources/Point3D.java b/src/resources/Point3D.java index 177510436..6455446ea 100644 --- a/src/resources/Point3D.java +++ b/src/resources/Point3D.java @@ -29,13 +29,12 @@ package resources; import network.packets.Packet; import resources.encodables.Encodable; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; -import java.io.Serializable; import java.nio.ByteBuffer; -public class Point3D implements Encodable, Serializable { - - private static final long serialVersionUID = 1L; +public class Point3D implements Encodable, Persistable { private double x; private double y; @@ -111,6 +110,20 @@ public class Point3D implements Encodable, Serializable { z = Packet.getFloat(data); } + @Override + public void save(NetBufferStream stream) { + stream.addFloat((float) x); + stream.addFloat((float) y); + stream.addFloat((float) z); + } + + @Override + public void read(NetBufferStream stream) { + x = stream.getFloat(); + y = stream.getFloat(); + z = stream.getFloat(); + } + public boolean equals(Object o) { if (!(o instanceof Point3D)) return false; diff --git a/src/resources/Quaternion.java b/src/resources/Quaternion.java index f04c390c3..d54e8999d 100644 --- a/src/resources/Quaternion.java +++ b/src/resources/Quaternion.java @@ -29,13 +29,12 @@ package resources; import network.packets.Packet; import resources.encodables.Encodable; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; -import java.io.Serializable; import java.nio.ByteBuffer; -public class Quaternion implements Encodable, Serializable { - - private static final long serialVersionUID = 1L; +public class Quaternion implements Encodable, Persistable { private double x; private double y; @@ -153,6 +152,22 @@ public class Quaternion implements Encodable, Serializable { z = Packet.getFloat(data); w = Packet.getFloat(data); } + + @Override + public void save(NetBufferStream stream) { + stream.addFloat((float) x); + stream.addFloat((float) y); + stream.addFloat((float) z); + stream.addFloat((float) w); + } + + @Override + public void read(NetBufferStream stream) { + x = stream.getFloat(); + y = stream.getFloat(); + z = stream.getFloat(); + w = stream.getFloat(); + } public String toString() { return String.format("Quaternion[%.3f, %.3f, %.3f, %.3f]", x, y, z, w); diff --git a/src/resources/SkillMod.java b/src/resources/SkillMod.java index c8f6fe01f..33db0c4c8 100644 --- a/src/resources/SkillMod.java +++ b/src/resources/SkillMod.java @@ -27,16 +27,15 @@ ***********************************************************************************/ package resources; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import resources.encodables.Encodable; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; -public class SkillMod implements Encodable, Serializable { +public class SkillMod implements Encodable, Persistable { - private static final long serialVersionUID = 1L; - private int base, modifier; public SkillMod() { @@ -64,6 +63,18 @@ public class SkillMod implements Encodable, Serializable { modifier = data.getInt(); } + @Override + public void save(NetBufferStream stream) { + stream.addInt(base); + stream.addInt(modifier); + } + + @Override + public void read(NetBufferStream stream) { + base = stream.getInt(); + modifier = stream.getInt(); + } + public void adjustBase(int adjustment) { base += adjustment; } diff --git a/src/resources/chat/ChatAvatar.java b/src/resources/chat/ChatAvatar.java index 994fffa06..37ef44fa2 100644 --- a/src/resources/chat/ChatAvatar.java +++ b/src/resources/chat/ChatAvatar.java @@ -24,25 +24,24 @@ * You should have received a copy of the GNU Affero General Public License * along with Holocore. If not, see ******************************************************************************/ - package resources.chat; import network.packets.Packet; import resources.encodables.Encodable; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; import resources.player.Player; import java.io.IOException; import java.io.ObjectInputStream; -import java.io.Serializable; import java.nio.ByteBuffer; import java.util.Locale; /** * @author Waverunner */ -public class ChatAvatar implements Encodable, Serializable { - private static final long serialVersionUID = 1L; - +public class ChatAvatar implements Encodable, Persistable { + private long networkId; private String name; private String game = "SWG"; @@ -133,7 +132,21 @@ public class ChatAvatar implements Encodable, Serializable { galaxy = Packet.getAscii(data); name = Packet.getAscii(data).toLowerCase(Locale.US); } - + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addAscii(galaxy); + stream.addAscii(name); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + galaxy = stream.getAscii(); + name = stream.getAscii(); + } + @Override public String toString() { return "ChatAvatar[networkId=" + networkId + diff --git a/src/resources/chat/ChatRoom.java b/src/resources/chat/ChatRoom.java index d3749e91f..88701afec 100644 --- a/src/resources/chat/ChatRoom.java +++ b/src/resources/chat/ChatRoom.java @@ -24,7 +24,6 @@ * You should have received a copy of the GNU Affero General Public License * along with Holocore. If not, see ******************************************************************************/ - package resources.chat; import network.packets.Packet; @@ -32,13 +31,14 @@ import network.packets.swg.SWGPacket; import network.packets.swg.zone.chat.ChatRoomMessage; import resources.encodables.Encodable; import resources.encodables.OutOfBandPackage; +import resources.network.NetBufferStream; import resources.objects.player.PlayerObject; +import resources.persistable.Persistable; import resources.player.Player; import services.player.PlayerManager; import java.io.IOException; import java.io.ObjectInputStream; -import java.io.Serializable; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -46,9 +46,8 @@ import java.util.List; /** * @author Waverunner */ -public class ChatRoom implements Encodable, Serializable { - private static final long serialVersionUID = 1L; - +public class ChatRoom implements Encodable, Persistable { + private int id; private int type; private String path; @@ -306,10 +305,63 @@ public class ChatRoom implements Encodable, Serializable { return data; } + /* + private int id; + private int type; + private String path; + private ChatAvatar owner; + private ChatAvatar creator; + private String title; + private List moderators; + private List invited; + private boolean moderated; // No one but moderators can talk + private List banned; + */ + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + owner.save(stream); + creator.save(stream); + stream.addInt(id); + stream.addInt(type); + stream.addAscii(path); + stream.addUnicode(title); + stream.addBoolean(moderated); + stream.addList(moderators, (a) -> a.save(stream)); + stream.addList(invited, (a) -> a.save(stream)); + stream.addList(banned, (a) -> a.save(stream)); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + owner.read(stream); + creator.read(stream); + id = stream.getInt(); + type = stream.getInt(); + path = stream.getAscii(); + title = stream.getUnicode(); + moderated = stream.getBoolean(); + stream.getList((i) -> moderators.add(inflateAvatar(stream))); + stream.getList((i) -> invited.add(inflateAvatar(stream))); + stream.getList((i) -> banned.add(inflateAvatar(stream))); + } + + private ChatAvatar inflateAvatar(NetBufferStream stream) { + ChatAvatar avatar = new ChatAvatar(); + avatar.read(stream); + return avatar; + } @Override public String toString() { return "ChatRoom[id=" + id + ", type=" + type + ", path='" + path + "', title='" + title + '\'' + ", creator=" + creator + ", moderated=" + moderated + ", isPublic=" + isPublic() + "]"; } + + public static ChatRoom create(NetBufferStream stream) { + ChatRoom room = new ChatRoom(); + room.read(stream); + return room; + } } diff --git a/src/resources/collections/SWGBitSet.java b/src/resources/collections/SWGBitSet.java index 0bb195a66..576d42a3b 100644 --- a/src/resources/collections/SWGBitSet.java +++ b/src/resources/collections/SWGBitSet.java @@ -28,13 +28,15 @@ package resources.collections; import resources.encodables.Encodable; +import resources.network.NetBufferStream; import resources.objects.SWGObject; +import resources.persistable.Persistable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.BitSet; -public class SWGBitSet extends BitSet implements Encodable { +public class SWGBitSet extends BitSet implements Encodable, Persistable { private static final long serialVersionUID = 1L; @@ -64,6 +66,17 @@ public class SWGBitSet extends BitSet implements Encodable { throw new UnsupportedOperationException("Unable to decode bitset!"); } + @Override + public void save(NetBufferStream stream) { + stream.addArray(toByteArray()); + } + + @Override + public void read(NetBufferStream stream) { + clear(); + xor(valueOf(stream.getArray())); + } + public void sendDeltaMessage(SWGObject target) { target.sendDelta(view, updateType, encode()); } diff --git a/src/resources/collections/SWGFlag.java b/src/resources/collections/SWGFlag.java index 9f9145827..e6fcbbbef 100644 --- a/src/resources/collections/SWGFlag.java +++ b/src/resources/collections/SWGFlag.java @@ -29,14 +29,16 @@ package resources.collections; import network.packets.swg.zone.baselines.Baseline; import resources.encodables.Encodable; +import resources.network.NetBufferStream; import resources.objects.SWGObject; +import resources.persistable.Persistable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.BitSet; -public class SWGFlag extends BitSet implements Encodable { +public class SWGFlag extends BitSet implements Encodable, Persistable { private static final long serialVersionUID = 2L; @@ -77,6 +79,17 @@ public class SWGFlag extends BitSet implements Encodable { throw new UnsupportedOperationException("Unable to decode bitset!"); } + @Override + public void save(NetBufferStream stream) { + stream.addArray(toByteArray()); + } + + @Override + public void read(NetBufferStream stream) { + clear(); + xor(valueOf(stream.getArray())); + } + @Override public boolean equals(Object o) { if (!(o instanceof SWGFlag)) diff --git a/src/resources/commands/callbacks/QaToolCmdCallback.java b/src/resources/commands/callbacks/QaToolCmdCallback.java index 24be2e283..50acfb82c 100644 --- a/src/resources/commands/callbacks/QaToolCmdCallback.java +++ b/src/resources/commands/callbacks/QaToolCmdCallback.java @@ -150,7 +150,7 @@ public class QaToolCmdCallback implements ICmdCallback { private void forceDelete(final ObjectManager objManager, final Player player, final SWGObject target) { SuiMessageBox inputBox = new SuiMessageBox(SuiButtons.OK_CANCEL, "Force Delete?", "Are you sure you want to delete this object?"); inputBox.addOkButtonCallback("handleDeleteObject", (caller, actor, event, parameters) -> { - if (target instanceof CreatureObject && ((CreatureObject) target).getPlayerObject() != null) { + if (target instanceof CreatureObject && ((CreatureObject) target).isPlayer()) { Log.i("QA", "[%s] Requested deletion of character: %s", player.getUsername(), target.getName()); new DeleteCharacterIntent((CreatureObject) target).broadcast(); Player owner = target.getOwner(); diff --git a/src/resources/common/CRC.java b/src/resources/common/CRC.java index f6a82cccd..1611af3d1 100644 --- a/src/resources/common/CRC.java +++ b/src/resources/common/CRC.java @@ -27,18 +27,17 @@ ***********************************************************************************/ package resources.common; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.StandardCharsets; import resources.encodables.Encodable; import resources.network.NetBuffer; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; import resources.server_info.CrcDatabase; -public class CRC implements Encodable, Serializable { - - private static final long serialVersionUID = 1L; +public class CRC implements Encodable, Persistable { private static final int CRC_TABLE[] = { 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, @@ -117,6 +116,16 @@ public class CRC implements Encodable, Serializable { this.str = getString(crc); } + @Override + public void save(NetBufferStream stream) { + stream.addInt(crc); + } + + @Override + public void read(NetBufferStream stream) { + crc = stream.getInt(); + } + @Override public String toString() { return str; diff --git a/src/resources/containers/ContainerPermissions.java b/src/resources/containers/ContainerPermissions.java index 312580634..c0cee9bc4 100644 --- a/src/resources/containers/ContainerPermissions.java +++ b/src/resources/containers/ContainerPermissions.java @@ -24,21 +24,25 @@ * You should have received a copy of the GNU Affero General Public License * along with Holocore. If not, see ******************************************************************************/ - package resources.containers; -import resources.objects.SWGObject; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; -import java.io.Serializable; -import java.util.*; +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import resources.persistable.Persistable; /** * Structure for creating permission sets that will allow the object to be viewed/modified/added/removed by a requested * object depending on the implemented abstract methods. * @author Waverunner */ -public abstract class ContainerPermissions implements Serializable { - private static final long serialVersionUID = 1L; +public abstract class ContainerPermissions implements Persistable { public static final WorldPermissions WORLD = new WorldPermissions(); public static final InventoryPermissions INVENTORY = new InventoryPermissions(); @@ -130,6 +134,27 @@ public abstract class ContainerPermissions implements Serializable { public void addDefaultWorldPermissions() { addPermissions("world", Permission.VIEW, Permission.ENTER); } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + synchronized (permissionGroups) { + stream.addMap(permissionGroups, (e) -> { + stream.addAscii(e.getKey()); + stream.addInt(e.getValue()); + }); + } + synchronized (joinedGroups) { + stream.addList(joinedGroups, (g) -> stream.addAscii(g)); + } + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + stream.getList((i) -> permissionGroups.put(stream.getAscii(), stream.getInt())); + stream.getList((i) -> joinedGroups.add(stream.getAscii())); + } public abstract boolean canView(SWGObject viewer, SWGObject container); public abstract boolean canEnter(SWGObject requester, SWGObject container); diff --git a/src/resources/containers/DefaultPermissions.java b/src/resources/containers/DefaultPermissions.java index 558b5899f..94e0a85dc 100644 --- a/src/resources/containers/DefaultPermissions.java +++ b/src/resources/containers/DefaultPermissions.java @@ -36,8 +36,6 @@ import resources.objects.SWGObject; */ public class DefaultPermissions extends ContainerPermissions { - private static final long serialVersionUID = 200L; - @Override public boolean canView(SWGObject requester, SWGObject container) { return true; diff --git a/src/resources/containers/InventoryPermissions.java b/src/resources/containers/InventoryPermissions.java index 4d4b72c4a..5b039f600 100644 --- a/src/resources/containers/InventoryPermissions.java +++ b/src/resources/containers/InventoryPermissions.java @@ -36,8 +36,6 @@ import resources.objects.SWGObject; */ public class InventoryPermissions extends DefaultPermissions { - private static final long serialVersionUID = 200L; - @Override public boolean canView(SWGObject requester, SWGObject container) { return requester.getOwner() == container.getOwner(); diff --git a/src/resources/containers/WorldPermissions.java b/src/resources/containers/WorldPermissions.java index 3250b7936..301f9cb68 100644 --- a/src/resources/containers/WorldPermissions.java +++ b/src/resources/containers/WorldPermissions.java @@ -48,8 +48,6 @@ import resources.objects.SWGObject; */ public class WorldPermissions extends DefaultPermissions { - private static final long serialVersionUID = 200L; - @Override public boolean canView(SWGObject viewer, SWGObject container) { if (super.canView(viewer, container)) diff --git a/src/resources/encodables/OutOfBandData.java b/src/resources/encodables/OutOfBandData.java index e43c43820..272166791 100644 --- a/src/resources/encodables/OutOfBandData.java +++ b/src/resources/encodables/OutOfBandData.java @@ -27,10 +27,12 @@ package resources.encodables; +import resources.persistable.Persistable; + /** * @author Waverunner */ -public interface OutOfBandData extends Encodable{ +public interface OutOfBandData extends Encodable, Persistable { OutOfBandPackage.Type getOobType(); int getOobPosition(); } diff --git a/src/resources/encodables/OutOfBandFactory.java b/src/resources/encodables/OutOfBandFactory.java new file mode 100644 index 000000000..aff133d79 --- /dev/null +++ b/src/resources/encodables/OutOfBandFactory.java @@ -0,0 +1,70 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.encodables; + +import resources.network.NetBufferStream; +import resources.objects.waypoint.WaypointObject; +import resources.persistable.SWGObjectFactory; + +public class OutOfBandFactory { + + public static void save(OutOfBandData oob, NetBufferStream stream) { + if (oob instanceof StringId) + stream.addByte(1); + else if (oob instanceof ProsePackage) + stream.addByte(2); + else if (oob instanceof WaypointObject) { + stream.addByte(3); + SWGObjectFactory.save((WaypointObject) oob, stream); + return; + } else + throw new IllegalArgumentException("Unknown OOB data!"); + oob.save(stream); + } + + public static OutOfBandData create(NetBufferStream stream) { + OutOfBandData oob; + byte type = stream.getByte(); + switch (type) { + case 1: + oob = new StringId(); + break; + case 2: + oob = new ProsePackage(); + break; + case 3: + oob = (WaypointObject) SWGObjectFactory.create(stream); + return oob; + default: + throw new IllegalStateException("Unknown type byte! Type: " + type); + } + oob.read(stream); + return oob; + } + +} diff --git a/src/resources/encodables/OutOfBandPackage.java b/src/resources/encodables/OutOfBandPackage.java index 815a4ea66..9a016aa83 100644 --- a/src/resources/encodables/OutOfBandPackage.java +++ b/src/resources/encodables/OutOfBandPackage.java @@ -28,12 +28,13 @@ package resources.encodables; import network.packets.Packet; +import resources.network.NetBufferStream; import resources.objects.waypoint.WaypointObject; +import resources.persistable.Persistable; import resources.server_info.Log; import java.io.IOException; import java.io.ObjectInputStream; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; @@ -41,9 +42,8 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; -public class OutOfBandPackage implements Encodable, Serializable { - private static final long serialVersionUID = 1L; - +public class OutOfBandPackage implements Encodable, Persistable { + private List packages; private transient List data; private transient int dataSize; @@ -108,6 +108,16 @@ public class OutOfBandPackage implements Encodable, Serializable { read += data.position() - start; } } + + @Override + public void save(NetBufferStream stream) { + stream.addList(packages, (p) -> p.save(stream)); + } + + @Override + public void read(NetBufferStream stream) { + stream.getList((i) -> packages.add(OutOfBandFactory.create(stream))); + } private void unpackOutOfBandData(ByteBuffer data, Type type) { // Position doesn't seem to be reflective of it's spot in the package list, not sure if this can be automated diff --git a/src/resources/encodables/ProsePackage.java b/src/resources/encodables/ProsePackage.java index 99782430a..9c205dd0b 100644 --- a/src/resources/encodables/ProsePackage.java +++ b/src/resources/encodables/ProsePackage.java @@ -29,17 +29,17 @@ package resources.encodables; import network.packets.Packet; -import java.io.Serializable; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; import resources.server_info.Log; -public class ProsePackage implements OutOfBandData, Serializable { - private static final long serialVersionUID = 1L; - +public class ProsePackage implements OutOfBandData { + private StringId base = new StringId("", ""); private Prose actor = new Prose(); @@ -228,6 +228,30 @@ public class ProsePackage implements OutOfBandData, Serializable { df = Packet.getInt(data); grammarFlag = Packet.getBoolean(data); } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + base.save(stream); + actor.save(stream); + target.save(stream); + other.save(stream); + stream.addBoolean(grammarFlag); + stream.addInt(di); + stream.addFloat(df); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + base.read(stream); + actor.read(stream); + target.read(stream); + other.read(stream); + grammarFlag = stream.getBoolean(); + di = stream.getInt(); + df = stream.getFloat(); + } @Override public OutOfBandPackage.Type getOobType() { @@ -247,10 +271,8 @@ public class ProsePackage implements OutOfBandData, Serializable { "]"; } - private static class Prose implements Encodable, Serializable { - - private static final long serialVersionUID = 1L; - + private static class Prose implements Encodable, Persistable { + private long objectId; private StringId stringId; private String text; @@ -294,6 +316,22 @@ public class ProsePackage implements OutOfBandData, Serializable { stringId = Packet.getEncodable(data, StringId.class); text = Packet.getUnicode(data); } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stringId.save(stream); + stream.addLong(objectId); + stream.addUnicode(text); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + stringId.read(stream); + objectId = stream.getLong(); + text = stream.getUnicode(); + } @Override public String toString() { diff --git a/src/resources/encodables/StringId.java b/src/resources/encodables/StringId.java index 253a5f541..14b6eca57 100644 --- a/src/resources/encodables/StringId.java +++ b/src/resources/encodables/StringId.java @@ -29,13 +29,13 @@ package resources.encodables; import network.packets.Packet; -import java.io.Serializable; import java.nio.ByteBuffer; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; import resources.server_info.Log; -public class StringId implements OutOfBandData, Serializable { - private static final long serialVersionUID = 1L; +public class StringId implements OutOfBandData, Persistable { private String key = ""; private String file = ""; @@ -79,6 +79,18 @@ public class StringId implements OutOfBandData, Serializable { Packet.getInt(data); key = Packet.getAscii(data); } + + @Override + public void save(NetBufferStream stream) { + stream.addAscii(file); + stream.addAscii(key); + } + + @Override + public void read(NetBufferStream stream) { + file = stream.getAscii(); + key = stream.getAscii(); + } @Override public OutOfBandPackage.Type getOobType() { diff --git a/src/resources/encodables/player/Equipment.java b/src/resources/encodables/player/Equipment.java index 86ee0cb8a..3879747c8 100644 --- a/src/resources/encodables/player/Equipment.java +++ b/src/resources/encodables/player/Equipment.java @@ -31,18 +31,19 @@ import network.packets.swg.zone.baselines.Baseline; import resources.common.CRC; import resources.encodables.Encodable; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.SWGObject; import resources.objects.tangible.TangibleObject; import resources.objects.weapon.WeaponObject; +import resources.persistable.Persistable; +import resources.persistable.SWGObjectFactory; import resources.player.Player; import resources.server_info.Log; import services.objects.ObjectCreator; -import java.io.Serializable; import java.nio.ByteBuffer; -public class Equipment implements Encodable, Serializable { - private static final long serialVersionUID = 1L; +public class Equipment implements Encodable, Persistable { private TangibleObject weapon; private byte [] customizationString; @@ -96,6 +97,29 @@ public class Equipment implements Encodable, Serializable { if (data.getBoolean()) this.weapon = createWeaponFromData(data); } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addLong(objectId); + stream.addInt(arrangementId); + stream.addInt(template.getCrc()); + stream.addArray(customizationString); + stream.addBoolean(weapon != null); + if (weapon != null) + SWGObjectFactory.save(weapon, stream); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + objectId = stream.getLong(); + arrangementId = stream.getInt(); + template = new CRC(stream.getInt()); + customizationString = stream.getArray(); + if (stream.getBoolean()) + weapon = (TangibleObject) SWGObjectFactory.create(stream); + } public byte[] getCustomizationString() {return customizationString;} public void setCustomizationString(byte[] customizationString) { this.customizationString = customizationString; } diff --git a/src/resources/encodables/player/Mail.java b/src/resources/encodables/player/Mail.java index 92c648128..b1d28d5d4 100644 --- a/src/resources/encodables/player/Mail.java +++ b/src/resources/encodables/player/Mail.java @@ -30,15 +30,15 @@ package resources.encodables.player; import network.packets.Packet; import resources.encodables.Encodable; import resources.encodables.OutOfBandPackage; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; import utilities.Encoder; -import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; -public class Mail implements Encodable, Serializable { - private static final long serialVersionUID = 1L; - +public class Mail implements Encodable, Persistable { + private int id; private String sender; private long receiverId; @@ -123,6 +123,47 @@ public class Mail implements Encodable, Serializable { subject = Packet.getUnicode(data); outOfBandPackage = Packet.getEncodable(data, OutOfBandPackage.class); } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addByte(status); + stream.addInt(id); + stream.addInt(timestamp); + stream.addLong(receiverId); + stream.addUnicode(sender); + stream.addUnicode(subject); + stream.addUnicode(message); + stream.addBoolean(outOfBandPackage != null); + if (outOfBandPackage != null) + outOfBandPackage.save(stream); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + status = stream.getByte(); + id = stream.getInt(); + timestamp = stream.getInt(); + receiverId = stream.getLong(); + sender = stream.getUnicode(); + subject = stream.getUnicode(); + message = stream.getUnicode(); + if (stream.getBoolean()) { + outOfBandPackage = new OutOfBandPackage(); + outOfBandPackage.read(stream); + } + } + + public int hashCode() { + return id; + } + + public boolean equals(Object o) { + if (!(o instanceof Mail)) + return false; + return ((Mail) o).id == id; + } public byte[] encodeHeader() { ByteBuffer bb = ByteBuffer.allocate(12 + subject.length() * 2).order(ByteOrder.LITTLE_ENDIAN); @@ -131,4 +172,14 @@ public class Mail implements Encodable, Serializable { bb.putInt(0); return bb.array(); } + + public static Mail create(NetBufferStream stream) { + Mail m = new Mail("", "", "", 0); + m.read(stream); + return m; + } + + public static void saveMail(Mail m, NetBufferStream stream) { + m.save(stream); + } } diff --git a/src/resources/network/BaselineObject.java b/src/resources/network/BaselineObject.java index 94c99c426..24a8289a6 100644 --- a/src/resources/network/BaselineObject.java +++ b/src/resources/network/BaselineObject.java @@ -29,7 +29,6 @@ package resources.network; import java.io.IOException; import java.io.ObjectInputStream; -import java.io.Serializable; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.List; @@ -40,9 +39,7 @@ import utilities.Encoder.StringType; import network.packets.swg.zone.baselines.Baseline; import network.packets.swg.zone.baselines.Baseline.BaselineType; -public class BaselineObject implements Serializable { - - private static final long serialVersionUID = 1L; +public class BaselineObject { private transient List> baselineData; diff --git a/src/resources/network/NetBufferStream.java b/src/resources/network/NetBufferStream.java index 62ac229ba..34c255dd5 100644 --- a/src/resources/network/NetBufferStream.java +++ b/src/resources/network/NetBufferStream.java @@ -29,6 +29,10 @@ package resources.network; import java.io.OutputStream; import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import resources.collections.SWGList; import resources.collections.SWGMap; @@ -279,6 +283,12 @@ public class NetBufferStream extends OutputStream { } } + public void getList(NumericalIterator ni) { + int size = getInt(); + for (int i = 0; i < size; i++) + ni.onItem(i); + } + public SWGSet getSwgSet(int num, int var, StringType type) { synchronized (bufferMutex) { return buffer.getSwgSet(num, var, type); @@ -321,6 +331,136 @@ public class NetBufferStream extends OutputStream { } } + public void addBoolean(boolean b) { + ensureCapacity(size+1); + synchronized (bufferMutex) { + buffer.addBoolean(b); + size++; + } + } + + public void addAscii(String s) { + ensureCapacity(size+2+s.length()); + synchronized (bufferMutex) { + buffer.addAscii(s); + size += 2 + s.length(); + } + } + + 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) { + buffer.addUnicode(s); + size += 4 + s.length()*2; + } + } + + public void addLong(long l) { + ensureCapacity(size+8); + synchronized (bufferMutex) { + buffer.addLong(l); + size += 8; + } + } + + public void addInt(int i) { + ensureCapacity(size+4); + synchronized (bufferMutex) { + buffer.addInt(i); + size += 4; + } + } + + public void addFloat(float f) { + ensureCapacity(size+4); + synchronized (bufferMutex) { + buffer.addFloat(f); + size += 4; + } + } + + public void addShort(int i) { + ensureCapacity(size+2); + synchronized (bufferMutex) { + buffer.addShort(i); + size += 2; + } + } + + public void addNetLong(long l) { + ensureCapacity(size+8); + synchronized (bufferMutex) { + buffer.addNetLong(l); + size += 8; + } + } + + public void addNetInt(int i) { + ensureCapacity(size+4); + synchronized (bufferMutex) { + buffer.addNetInt(i); + size += 4; + } + } + + public void addNetShort(int i) { + ensureCapacity(size+2); + synchronized (bufferMutex) { + buffer.addNetShort(i); + size += 2; + } + } + + public void addByte(int b) { + ensureCapacity(size+1); + synchronized (bufferMutex) { + buffer.addByte(b); + size++; + } + } + + public void addArray(byte[] b) { + ensureCapacity(size+2+b.length); + synchronized (bufferMutex) { + buffer.addArray(b); + size += 2 + b.length; + } + } + + public void addList(List l, ListIterable r) { + addInt(l.size()); + for (T t : l) + r.onItem(t); + } + + public void addList(Set s, ListIterable r) { + addInt(s.size()); + for (T t : s) + r.onItem(t); + } + + public void addMap(Map m, MapIterable r) { + addInt(m.size()); + for (Entry e : m.entrySet()) + r.onItem(e); + } + + public void addRawArray(byte[] b) { + write(b); + } + + public void addEncodable(Encodable e) { + addRawArray(e.encode()); + } + public byte [] array() { synchronized (bufferMutex) { return buffer.array(); @@ -350,4 +490,16 @@ public class NetBufferStream extends OutputStream { } } + public static interface ListIterable { + void onItem(T item); + } + + public static interface MapIterable { + void onItem(Entry item); + } + + public static interface NumericalIterator { + void onItem(int index); + } + } diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index b3e24e624..91e73de5d 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -49,18 +49,18 @@ import resources.encodables.StringId; import resources.network.BaselineBuilder; import resources.network.BaselineObject; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.building.BuildingObject; import resources.objects.creature.CreatureObject; +import resources.persistable.Persistable; +import resources.persistable.SWGObjectFactory; import resources.player.Player; import resources.player.PlayerState; import resources.server_info.Log; import services.CoreManager; -import java.io.IOException; -import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Hashtable; @@ -69,17 +69,14 @@ import java.util.List; import java.util.Map; import java.util.Set; -public abstract class SWGObject extends BaselineObject implements Comparable { +public abstract class SWGObject extends BaselineObject implements Comparable, Persistable { - private static final long serialVersionUID = 1L; - private final Location location; private final long objectId; private final HashMap slots; // HashMap used for null value support - private final Map containedObjects; + private final Set containedObjects; private final Map attributes; private final Map dataAttributes; - private ContainerPermissions containerPermissions; private transient Set objectsAware; private transient Set customAware; private transient BuildoutArea buildoutArea; @@ -88,6 +85,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable(); this.customAware = new HashSet<>(); this.slots = new HashMap<>(); - this.containedObjects = Collections.synchronizedMap(new HashMap()); + this.containedObjects = new HashSet<>(); this.attributes = new LinkedHashMap<>(); this.dataAttributes = new Hashtable<>(); this.containerPermissions = new DefaultPermissions(); } - - private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - areaId = -1; - ois.defaultReadObject(); - objectsAware = new HashSet<>(); - customAware = new HashSet<>(); - buildoutArea = null; - owner = null; - } /** * Adds the specified object to this object and places it in the appropriate slot if needed @@ -137,7 +126,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable getContainedObjects() { synchronized (containedObjects) { - return new ArrayList<>(containedObjects.values()); + return new ArrayList<>(containedObjects); } } @@ -835,7 +813,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable getObservers(Player owner, SWGObject original, boolean initial) { Set nearby; synchronized (containedObjects) { - nearby = new HashSet<>(containedObjects.values()); + nearby = new HashSet<>(containedObjects); } if (initial) { nearby.addAll(getObjectsAware()); @@ -1003,7 +981,7 @@ public abstract class SWGObject extends BaselineObject implements Comparable attributes; + private ContainerPermissions containerPermissions; + private ObjectClassification classification = ObjectClassification.GENERATED; + private String objectName = ""; + private int volume = 0; + private float complexity = 1; + private int containerType = 0; + private double loadRange = 0; + private int areaId = -1; + + private final HashMap slots; + private final Map containedObjects; + */ + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + location.save(stream); + containerPermissions.save(stream); + synchronized (attributes) { + stream.addMap(attributes, (e) -> { + stream.addAscii(e.getKey()); + stream.addAscii(e.getValue()); + }); + } + stream.addAscii(classification.name()); + stream.addUnicode(objectName); + stream.addInt(volume); + stream.addFloat(complexity); + stream.addFloat((float) loadRange); + Set contained; + synchronized (containedObjects) { + contained = new HashSet<>(containedObjects); + } + synchronized (slots) { + contained.addAll(slots.values()); + contained.remove(null); + } + stream.addList(contained, (c) -> SWGObjectFactory.save(c, stream)); + } + + public void read(NetBufferStream stream) { + stream.getByte(); + location.read(stream); + containerPermissions.read(stream); + stream.getList((i) -> attributes.put(stream.getAscii(), stream.getAscii())); + classification = ObjectClassification.valueOf(stream.getAscii()); + objectName = stream.getUnicode(); + volume = stream.getInt(); + complexity = stream.getFloat(); + loadRange = stream.getFloat(); + Set contained = new HashSet<>(); + stream.getList((i) -> contained.add(SWGObjectFactory.create(stream))); + for (SWGObject obj : contained) + obj.moveToContainer(this); + } + public enum ObjectClassification { GENERATED, BUILDOUT, diff --git a/src/resources/objects/building/BuildingObject.java b/src/resources/objects/building/BuildingObject.java index b57d489d7..6cb63dca4 100644 --- a/src/resources/objects/building/BuildingObject.java +++ b/src/resources/objects/building/BuildingObject.java @@ -32,6 +32,7 @@ import resources.Location; import resources.client_info.ClientFactory; import resources.client_info.visitors.PortalLayoutData; import resources.client_info.visitors.ObjectData.ObjectDataAttribute; +import resources.network.NetBufferStream; import resources.objects.SWGObject; import resources.objects.cell.CellObject; import resources.objects.tangible.TangibleObject; @@ -44,8 +45,6 @@ import java.util.List; public class BuildingObject extends TangibleObject { - private static final long serialVersionUID = 1L; - public BuildingObject(long objectId) { super(objectId, BaselineType.BUIO); } @@ -121,4 +120,16 @@ public class BuildingObject extends TangibleObject { cellObject.setCellName(cellData.getName()); // System.out.println(cellObject + " cell name " + cellObject.getCellName()); } + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + } } diff --git a/src/resources/objects/cell/CellObject.java b/src/resources/objects/cell/CellObject.java index 17c5b87ee..377b0d87d 100644 --- a/src/resources/objects/cell/CellObject.java +++ b/src/resources/objects/cell/CellObject.java @@ -31,13 +31,12 @@ import network.packets.swg.zone.baselines.Baseline.BaselineType; import network.packets.swg.zone.building.UpdateCellPermissionMessage; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.SWGObject; import resources.player.Player; public class CellObject extends SWGObject { - private static final long serialVersionUID = 1L; - private boolean isPublic = true; private int number = 0; private String label = ""; @@ -121,4 +120,24 @@ public class CellObject extends SWGObject { buffer.getFloat(); labelZ = buffer.getFloat(); } + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addBoolean(isPublic); + stream.addAscii(label); + stream.addFloat((float) labelX); + stream.addFloat((float) labelZ); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + isPublic = stream.getBoolean(); + label = stream.getAscii(); + labelX = stream.getFloat(); + labelZ = stream.getFloat(); + } } diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 7e0489aaf..45fcdec6c 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -30,8 +30,6 @@ package resources.objects.creature; import java.util.ArrayList; import java.util.Collection; import java.util.Set; -import java.io.IOException; -import java.io.ObjectInputStream; import network.packets.swg.zone.UpdatePostureMessage; import network.packets.swg.zone.UpdatePvpStatusMessage; @@ -41,104 +39,51 @@ import resources.HologramColour; import resources.Posture; import resources.PvpFlag; import resources.Race; -import resources.SkillMod; import resources.collections.SWGList; -import resources.collections.SWGMap; import resources.collections.SWGSet; -import resources.common.CRC; -import resources.encodables.player.Equipment; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.GameObjectType; import resources.objects.SWGObject; import resources.objects.player.PlayerObject; import resources.objects.tangible.TangibleObject; import resources.objects.weapon.WeaponObject; +import resources.persistable.SWGObjectFactory; import resources.player.Player; import services.group.GroupInviterData; import utilities.Encoder.StringType; public class CreatureObject extends TangibleObject { - private static final long serialVersionUID = 2L; - - private transient GroupInviterData inviterData = new GroupInviterData(0, null, "", 0); private transient long lastReserveOperation = 0; - private transient long groupId = 0; + + private final CreatureObjectClientServerNP creo4 = new CreatureObjectClientServerNP(); + private final CreatureObjectSharedNP creo6 = new CreatureObjectSharedNP(); private Posture posture = Posture.UPRIGHT; private Race race = Race.HUMAN_MALE; - private double movementScale = 1; - private double movementPercent = 1; - private double walkSpeed = 1.549; - private double runSpeed = 7.3; - private double accelScale = 1; - private double accelPercent = 1; - private double turnScale = 1; - private double slopeModAngle = 1; - private double slopeModPercent = 1; - private double waterModPercent = 0.75; private double height = 0; - private long performanceListenTarget = 0; - private int guildId = 0; - private short level = 1; - private int levelHealthGranted = 0; - private int totalLevelXp = 0; - private CreatureDifficulty difficulty = CreatureDifficulty.NORMAL; private int cashBalance = 0; private int bankBalance = 0; private long reserveBalance = 0; // Galactic Reserve - capped at 3 billion - private String moodAnimation = "neutral"; - private String animation = ""; - private WeaponObject equippedWeapon = null; private WeaponObject defaultWeapon = null; - private byte moodId = 0; - private long lookAtTargetId = 0; - private long intendedTargetId = 0; - private int performanceCounter = 0; - private int performanceId = 0; - private String costume = ""; - private boolean visible = true; - private boolean performing = false; - private boolean shownOnRadar = true; - private boolean beast = false; private byte factionRank = 0; private long ownerId = 0; private int battleFatigue = 0; private long statesBitmask = 0; private String currentCity = ""; private long lastTransform = 0; - private HologramColour hologramColour = HologramColour.DEFAULT; - private SWGSet missionCriticalObjs = new SWGSet<>(4, 13); private SWGSet skills = new SWGSet(1, 3, StringType.ASCII); private SWGList baseAttributes = new SWGList(1, 2); - private SWGList hamEncumbList = new SWGList(4, 2); - private SWGList attributes = new SWGList(6, 21); - private SWGList maxAttributes = new SWGList(6, 22); - private SWGList equipmentList = new SWGList(6, 23); - private SWGList appearanceList = new SWGList(6, 33); - - private SWGMap skillMods = new SWGMap<>(4, 3, StringType.ASCII); // TODO: SkillMod structure - private SWGMap abilities = new SWGMap<>(4, 14, StringType.ASCII); - private SWGMap buffs = new SWGMap<>(6, 26); public CreatureObject(long objectId) { super(objectId, BaselineType.CREO); - initMaxAttributes(); - initCurrentAttributes(); initBaseAttributes(); } - private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { - ois.defaultReadObject(); - // Transient Variables - inviterData = new GroupInviterData(0, null, "", 0); - lastReserveOperation = 0; - groupId = 0; - } - @Override public void addObject(SWGObject obj) { super.addObject(obj); @@ -177,52 +122,20 @@ public class CreatureObject extends TangibleObject { } } - public void removeEquipment(SWGObject obj) { - synchronized (equipmentList) { - for (Equipment equipment : equipmentList) { - if (equipment.getObjectId() == obj.getObjectId()) { - equipmentList.remove(equipment); - equipmentList.sendDeltaMessage(this); - break; - } - } - } + public void addEquipment(SWGObject obj) { + creo6.addEquipment(obj, this); } - public void addEquipment(SWGObject obj) { - synchronized(equipmentList) { - if (obj instanceof WeaponObject) - equipmentList.add(new Equipment((WeaponObject) obj)); - else - equipmentList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); - equipmentList.sendDeltaMessage(this); - } + public void removeEquipment(SWGObject obj) { + creo6.removeEquipment(obj, this); } public void addAppearanceItem(SWGObject obj) { - synchronized(appearanceList) { - appearanceList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); - appearanceList.sendDeltaMessage(this); - } + creo6.addAppearanceItem(obj, this); } public void removeAppearanceItem(SWGObject obj) { - synchronized (appearanceList) { - for (Equipment equipment : appearanceList) { - if (equipment.getObjectId() == obj.getObjectId()) { - appearanceList.remove(equipment); - appearanceList.sendDeltaMessage(this); - } - } - } - } - - public SWGList getEquipmentList() { - return equipmentList; - } - - public SWGList getAppearanceList() { - return appearanceList; + creo6.removeAppearanceItem(obj, this); } public void addSkill(String skillName) { @@ -262,43 +175,43 @@ public class CreatureObject extends TangibleObject { } public double getMovementScale() { - return movementScale; + return creo4.getMovementScale(); } public double getMovementPercent() { - return movementPercent; + return creo4.getMovementPercent(); } public double getWalkSpeed() { - return walkSpeed; + return creo4.getWalkSpeed(); } public double getRunSpeed() { - return runSpeed; + return creo4.getRunSpeed(); } public double getAccelScale() { - return accelScale; + return creo4.getAccelScale(); } public double getAccelPercent() { - return accelPercent; + return creo4.getAccelPercent(); } public double getTurnScale() { - return turnScale; + return creo4.getTurnScale(); } public double getSlopeModAngle() { - return slopeModAngle; + return creo4.getSlopeModAngle(); } public double getSlopeModPercent() { - return slopeModPercent; + return creo4.getSlopeModPercent(); } public double getWaterModPercent() { - return waterModPercent; + return creo4.getWaterModPercent(); } public double getHeight() { @@ -306,27 +219,27 @@ public class CreatureObject extends TangibleObject { } public long getPerformanceListenTarget() { - return performanceListenTarget; + return creo4.getPerformanceListenTarget(); } public int getGuildId() { - return guildId; + return creo6.getGuildId(); } public short getLevel() { - return level; + return creo6.getLevel(); } public int getLevelHealthGranted() { - return levelHealthGranted; + return creo6.getLevelHealthGranted(); } public int getTotalLevelXp() { - return totalLevelXp; + return creo4.getTotalLevelXp(); } public CreatureDifficulty getDifficulty() { - return difficulty; + return creo6.getDifficulty(); } public String getCurrentCity() { @@ -427,52 +340,52 @@ public class CreatureObject extends TangibleObject { } public void setMovementScale(double movementScale) { - this.movementScale = movementScale; + creo4.setMovementScale(movementScale); sendDelta(4, 5, movementScale); } public void setMovementPercent(double movementPercent) { - this.movementPercent = movementPercent; + creo4.setMovementPercent(movementPercent); sendDelta(4, 4, movementPercent); } public void setWalkSpeed(double walkSpeed) { - this.walkSpeed = walkSpeed; + creo4.setWalkSpeed(walkSpeed); sendDelta(4, 11, walkSpeed); } public void setRunSpeed(double runSpeed) { - this.runSpeed = runSpeed; + creo4.setRunSpeed(runSpeed); sendDelta(4, 7, runSpeed); } public void setAccelScale(double accelScale) { - this.accelScale = accelScale; + creo4.setAccelScale(accelScale); sendDelta(4, 1, accelScale); } public void setAccelPercent(double accelPercent) { - this.accelPercent = accelPercent; + creo4.setAccelPercent(accelPercent); sendDelta(4, 0, accelPercent); } public void setTurnScale(double turnScale) { - this.turnScale = turnScale; + creo4.setTurnScale(turnScale); sendDelta(4, 10, turnScale); } public void setSlopeModAngle(double slopeModAngle) { - this.slopeModAngle = slopeModAngle; + creo4.setSlopeModAngle(slopeModAngle); sendDelta(4, 8, slopeModAngle); } public void setSlopeModPercent(double slopeModPercent) { - this.slopeModPercent = slopeModPercent; + creo4.setSlopeModPercent(slopeModPercent); sendDelta(4, 9, slopeModPercent); } public void setWaterModPercent(double waterModPercent) { - this.waterModPercent = waterModPercent; + creo4.setWaterModPercent(waterModPercent); sendDelta(4, 12, waterModPercent); } @@ -482,32 +395,32 @@ public class CreatureObject extends TangibleObject { } public void setPerformanceListenTarget(long performanceListenTarget) { - this.performanceListenTarget = performanceListenTarget; + creo4.setPerformanceListenTarget(performanceListenTarget); sendDelta(4, 6, performanceListenTarget); } public void setGuildId(int guildId) { - this.guildId = guildId; + creo6.setGuildId(guildId); sendDelta(6, 15, guildId); } public void setLevel(int level) { - this.level = (short) level; + creo6.setLevel(level); sendDelta(6, 8, (short) level); } public void setLevelHealthGranted(int levelHealthGranted) { - this.levelHealthGranted = levelHealthGranted; + creo6.setLevelHealthGranted(levelHealthGranted); sendDelta(6, 9, levelHealthGranted); } public void setTotalLevelXp(int totalLevelXp) { - this.totalLevelXp = totalLevelXp; + creo4.setTotalLevelXp(totalLevelXp); sendDelta(4, 15, totalLevelXp); } public void setDifficulty(CreatureDifficulty difficulty) { - this.difficulty = difficulty; + creo6.setDifficulty(difficulty); sendDelta(6, 26, difficulty.getDifficulty()); } @@ -520,38 +433,38 @@ public class CreatureObject extends TangibleObject { } public String getMoodAnimation() { - return moodAnimation; + return creo6.getMoodAnimation(); } public void setMoodAnimation(String moodAnimation) { - this.moodAnimation = moodAnimation; + creo6.setMoodAnimation(moodAnimation); sendDelta(6, 11, moodAnimation, StringType.ASCII); } public boolean isBeast() { - return beast; + return creo6.isBeast(); } public void setBeast(boolean beast) { - this.beast = beast; + creo6.setBeast(beast); sendDelta(6, 31, beast); } public String getAnimation() { - return animation; + return creo6.getAnimation(); } public void setAnimation(String animation) { - this.animation = animation; + creo6.setAnimation(animation); sendDelta(6, 10, animation, StringType.ASCII); } public WeaponObject getEquippedWeapon() { - return equippedWeapon; + return creo6.getEquippedWeapon(); } public void setEquippedWeapon(WeaponObject weapon) { - this.equippedWeapon = weapon; + creo6.setEquippedWeapon(weapon); sendDelta(6, 12, weapon.getObjectId()); } @@ -564,78 +477,74 @@ public class CreatureObject extends TangibleObject { } public byte getMoodId() { - return moodId; + return creo6.getMoodId(); } public void setMoodId(byte moodId) { - this.moodId = moodId; + creo6.setMoodId(moodId); sendDelta(6, 18, moodId); } public long getLookAtTargetId() { - return lookAtTargetId; + return creo6.getLookAtTargetId(); } public void setLookAtTargetId(long lookAtTargetId) { - this.lookAtTargetId = lookAtTargetId; + creo6.setLookAtTargetId(lookAtTargetId); sendDelta(6, 16, lookAtTargetId); } public long getIntendedTargetId() { - return intendedTargetId; + return creo6.getIntendedTargetId(); } public void setIntendedTargetId(long intendedTargetId) { - this.intendedTargetId = intendedTargetId; + creo6.setIntendedTargetId(intendedTargetId); sendDelta(6, 17, intendedTargetId); } public int getPerformanceCounter() { - return performanceCounter; + return creo6.getPerformanceCounter(); } public void setPerformanceCounter(int performanceCounter) { - this.performanceCounter = performanceCounter; + creo6.setPerformanceCounter(performanceCounter); sendDelta(6, 19, performanceCounter); } public int getPerformanceId() { - return performanceId; + return creo6.getPerformanceId(); } public void setPerformanceId(int performanceId) { - this.performanceId = performanceId; + creo6.setPerformanceId(performanceId); sendDelta(6, 20, performanceId); } public String getCostume() { - return costume; + return creo6.getCostume(); } public void setCostume(String costume) { - this.costume = costume; + creo6.setCostume(costume); sendDelta(6, 24, costume, StringType.ASCII); } public long getGroupId() { - return groupId; + return creo6.getGroupId(); } public void updateGroupInviteData(Player sender, long groupId, String name) { - inviterData.setName(name); - inviterData.setSender(sender); - inviterData.setId(groupId); - inviterData.incrementCounter(); - - sendDelta(6, 14, inviterData); + creo6.updateGroupInviteData(sender, groupId, name); + sendDelta(6, 14, creo6.getInviterData()); } public GroupInviterData getInviterData() { - return inviterData; + return creo6.getInviterData(); } public void setGroupId(long groupId) { - this.groupId = groupId; + creo6.setGroupId(groupId); sendDelta(6, 13, groupId); } @@ -694,73 +603,51 @@ public class CreatureObject extends TangibleObject { } public void adjustSkillmod(String skillModName, int base, int modifier) { - synchronized(skillMods) { - SkillMod skillMod = skillMods.get(skillModName); - - if(skillMod == null) { - // They didn't have this SkillMod already. - // Therefore, we send a full delta. - skillMods.put(skillModName, new SkillMod(base, modifier)); - skillMods.sendDeltaMessage(this); - } else { - // They already had this skillmod. - // All we need to do is adjust the base and the modifier and send an update from the SWGMap - skillMod.adjustBase(base); - skillMod.adjustModifier(modifier); - skillMods.update(skillModName, this); - } - } + creo4.adjustSkillmod(skillModName, base, modifier, this); } public int getSkillModValue(String skillModName) { - synchronized(skillMods) { - SkillMod skillMod = skillMods.get(skillModName); - return skillMod != null ? skillMod.getValue() : 0; - } + return creo4.getSkillModValue(skillModName); } public boolean isVisible() { - return visible; + return creo6.isVisible(); } public void setVisible(boolean visible) { - this.visible = visible; + creo6.setVisible(visible); sendDelta(6, 25, visible); } public boolean isPerforming() { - return performing; + return creo6.isPerforming(); } public void setPerforming(boolean performing) { - this.performing = performing; + creo6.setPerforming(performing); sendDelta(6, 27, performing); } public void setHologramColour(HologramColour hologramColour) { - this.hologramColour = hologramColour; + creo6.setHologramColour(hologramColour); sendDelta(6, 29, hologramColour.getValue()); } public boolean isShownOnRadar() { - return shownOnRadar; + return creo6.isShownOnRadar(); } public void setShownOnRadar(boolean shownOnRadar) { - this.shownOnRadar = shownOnRadar; + creo6.setShownOnRadar(shownOnRadar); sendDelta(6, 30, shownOnRadar); } public int getHealth() { - synchronized (attributes) { - return attributes.get(0); - } + return creo6.getHealth(); } public int getMaxHealth() { - synchronized (maxAttributes) { - return maxAttributes.get(0); - } + return creo6.getMaxHealth(); } public int getBaseHealth() { @@ -770,15 +657,11 @@ public class CreatureObject extends TangibleObject { } public int getAction() { - synchronized (attributes) { - return attributes.get(2); - } + return creo6.getAction(); } public int getMaxAction() { - synchronized (maxAttributes) { - return maxAttributes.get(2); - } + return creo6.getMaxAction(); } public int getBaseAction() { @@ -788,15 +671,11 @@ public class CreatureObject extends TangibleObject { } public int getMind() { - synchronized (attributes) { - return attributes.get(4); - } + return creo6.getMind(); } public int getMaxMind() { - synchronized (maxAttributes) { - return maxAttributes.get(4); - } + return creo6.getMaxMind(); } public int getBaseMind() { @@ -805,19 +684,22 @@ public class CreatureObject extends TangibleObject { } } - public void addAbility(String abilityName){ - synchronized(abilities) { - abilities.put(abilityName, 1); //TODO: Figure out what the integer value should be for each ability - abilities.sendDeltaMessage(this); - } + public void addAbility(String abilityName) { + creo4.addAbility(abilityName, this); + } + + public void removeAbility(String abilityName) { + creo4.removeAbility(abilityName); + } + + public boolean hasAbility(String abilityName) { + return creo4.hasAbility(abilityName); + } + + public Set getAbilityNames() { + return creo4.getAbilityNames(); } - public void removeAbility(String abilityName) { abilities.remove(abilityName); } - - public boolean hasAbility(String abilityName) { return abilities.get(abilityName) != null; } - - public Set getAbilityNames() { return abilities.keySet(); }; - public void setBaseHealth(int baseHealth) { synchronized(baseAttributes) { baseAttributes.set(0, baseHealth); @@ -826,24 +708,15 @@ public class CreatureObject extends TangibleObject { } public void setHealth(int health) { - synchronized(attributes) { - attributes.set(0, health); - attributes.sendDeltaMessage(this); - } + creo6.setHealth(health, this); } public void modifyHealth(int mod) { - synchronized(attributes) { - attributes.set(0, getHealth() + mod); - attributes.sendDeltaMessage(this); - } + creo6.modifyHealth(mod, this); } public void setMaxHealth(int maxHealth) { - synchronized(maxAttributes) { - maxAttributes.set(0, maxHealth); - maxAttributes.sendDeltaMessage(this); - } + creo6.setMaxHealth(maxHealth, this); } public void setBaseAction(int baseAction) { @@ -854,65 +727,27 @@ public class CreatureObject extends TangibleObject { } public void setAction(int action) { - synchronized(attributes) { - attributes.set(2, action); - attributes.sendDeltaMessage(this); - } + creo6.setAction(action, this); } public void modifyAction(int mod) { - synchronized(attributes) { - attributes.set(2, getAction() + mod); - attributes.sendDeltaMessage(this); - } + creo6.modifyAction(mod, this); } public void setMaxAction(int maxAction) { - synchronized(maxAttributes) { - maxAttributes.set(2, maxAction); - maxAttributes.sendDeltaMessage(this); - } + creo6.setMaxAction(maxAction, this); } public void setMind(int mind) { - synchronized(attributes) { - attributes.set(4, mind); - attributes.sendDeltaMessage(this); - } + creo6.setMind(mind, this); } public void modifyMind(int mod) { - synchronized(attributes) { - attributes.set(4, getMind() + mod); - attributes.sendDeltaMessage(this); - } + creo6.modifyMind(mod, this); } public void setMaxMind(int maxMind) { - synchronized(maxAttributes) { - maxAttributes.set(4, maxMind); - maxAttributes.sendDeltaMessage(this); - } - } - - private void initMaxAttributes() { - maxAttributes.add(0, 1000); // Health - maxAttributes.add(1, 0); - maxAttributes.add(2, 300); // Action - maxAttributes.add(3, 0); - maxAttributes.add(4, 300); // Mind - maxAttributes.add(5, 0); - maxAttributes.clearDeltaQueue(); - } - - private void initCurrentAttributes() { - attributes.add(0, 1000); // Health - attributes.add(1, 0); - attributes.add(2, 300); // Action - attributes.add(3, 0); - attributes.add(4, 300); // Mind - attributes.add(5, 0); - attributes.clearDeltaQueue(); + creo6.setMaxMind(maxMind, this); } private void initBaseAttributes() { @@ -1016,59 +851,14 @@ public class CreatureObject extends TangibleObject { super.createBaseline4(target, bb); // 0 variables if (getStringId().toString().equals("@obj_n:unknown_object")) return; - bb.addFloat((float) accelPercent); // 0 - bb.addFloat((float) accelScale); // 1 - bb.addObject(hamEncumbList); // Rename to bonusAttributes? 2 - bb.addObject(skillMods); // 3 - bb.addFloat((float) movementPercent); // 4 - bb.addFloat((float) movementScale); // 5 - bb.addLong(performanceListenTarget); // 6 - bb.addFloat((float) runSpeed); // 7 - bb.addFloat((float) slopeModAngle); // 8 - bb.addFloat((float) slopeModPercent); // 9 - bb.addFloat((float) turnScale); // 10 - bb.addFloat((float) walkSpeed); // 11 - bb.addFloat((float) waterModPercent); // 12 - bb.addObject(missionCriticalObjs); // Group Missions? 13 - bb.addObject(abilities); // 14 - bb.addInt(totalLevelXp); // 15 - - bb.incrementOperandCount(16); + creo4.createBaseline4(target, bb); } public void createBaseline6(Player target, BaselineBuilder bb) { super.createBaseline6(target, bb); // 8 variables - TANO6 (6) + BASE6 (2) if (getStringId().toString().equals("@obj_n:unknown_object")) return; - bb.addShort(level); // 8 - bb.addInt(levelHealthGranted); // 9 - bb.addAscii(animation); // 10 - bb.addAscii(moodAnimation); // 11 - bb.addLong(equippedWeapon == null ? 0 : equippedWeapon.getObjectId()); // 12 - bb.addLong(groupId); // 13 - bb.addObject(inviterData); // TODO: Check structure -- 14 - bb.addInt(guildId); // 15 - bb.addLong(lookAtTargetId); // 16 - bb.addLong(intendedTargetId); // 17 - bb.addByte(moodId); // 18 - bb.addInt(performanceCounter); // 19 - bb.addInt(performanceId); // 20 - bb.addObject(attributes); // 21 - bb.addObject(maxAttributes); // 22 - bb.addObject(equipmentList); // 23 - bb.addAscii(costume); // 24 - bb.addBoolean(visible); // 25 - bb.addObject(buffs); // 26 - bb.addBoolean(performing); // 27 - bb.addByte(difficulty.getDifficulty()); // 28 - bb.addInt((hologramColour == null) ? -1 : hologramColour.getValue()); // Hologram Color -- 29 - bb.addBoolean(shownOnRadar); // 30 - bb.addBoolean(beast); // 31 - bb.addByte(0); // forceShowHam? -- 32 - bb.addObject(appearanceList); // 33 - bb.addLong(0); // decoy? -- 34 - - bb.incrementOperandCount(27); + creo6.createBaseline6(target, bb); } protected void parseBaseline1(NetBuffer buffer) { @@ -1097,62 +887,63 @@ public class CreatureObject extends TangibleObject { super.parseBaseline4(buffer); if (getStringId().toString().equals("@obj_n:unknown_object")) return; - accelPercent = buffer.getFloat(); - accelScale = buffer.getFloat(); - hamEncumbList = buffer.getSwgList(4, 2, Integer.class); - skillMods = buffer.getSwgMap(4, 3, StringType.ASCII, SkillMod.class); - movementPercent = buffer.getFloat(); - movementScale = buffer.getFloat(); - performanceListenTarget = buffer.getLong(); - runSpeed = buffer.getFloat(); - slopeModAngle = buffer.getFloat(); - slopeModPercent = buffer.getFloat(); - turnScale = buffer.getFloat(); - walkSpeed = buffer.getFloat(); - waterModPercent = buffer.getFloat(); - missionCriticalObjs = buffer.getSwgSet(4, 13, StringType.ASCII); - abilities = buffer.getSwgMap(4, 14, StringType.ASCII, Integer.class); - totalLevelXp = buffer.getInt(); + creo4.parseBaseline4(buffer); } protected void parseBaseline6(NetBuffer buffer) { super.parseBaseline6(buffer); if (getStringId().toString().equals("@obj_n:unknown_object")) return; - level = buffer.getShort(); - levelHealthGranted = buffer.getInt(); - animation = buffer.getAscii(); - moodAnimation = buffer.getAscii(); - long weaponId = buffer.getLong(); - groupId = buffer.getLong(); - inviterData = buffer.getEncodable(GroupInviterData.class); - guildId = buffer.getInt(); - lookAtTargetId = buffer.getLong(); - intendedTargetId = buffer.getLong(); - moodId = buffer.getByte(); - performanceCounter = buffer.getInt(); - performanceId = buffer.getInt(); - attributes = buffer.getSwgList(6, 21, Integer.class); - maxAttributes = buffer.getSwgList(6, 22, Integer.class); - equipmentList = buffer.getSwgList(6, 23, Equipment.class); - costume = buffer.getAscii(); - visible = buffer.getBoolean(); - buffs = buffer.getSwgMap(6, 26, CRC.class, Buff.class); - performing = buffer.getBoolean(); - difficulty = CreatureDifficulty.getForDifficulty(buffer.getByte()); - hologramColour = HologramColour.getForValue(buffer.getInt()); - shownOnRadar = buffer.getBoolean(); - beast = buffer.getBoolean(); - buffer.getBoolean(); - appearanceList = buffer.getSwgList(6, 33, Equipment.class); - buffer.getLong(); - equippedWeapon = null; - for (Equipment e : equipmentList) { - if (e.getObjectId() == weaponId && e.getWeapon() instanceof WeaponObject) { - equippedWeapon = (WeaponObject) e.getWeapon(); - break; - } + creo6.parseBaseline6(buffer); + } + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + creo4.save(stream); + creo6.save(stream); + stream.addAscii(posture.name()); + stream.addAscii(race.name()); + stream.addFloat((float) height); + stream.addInt(battleFatigue); + stream.addInt(cashBalance); + stream.addInt(bankBalance); + stream.addLong(reserveBalance); + stream.addLong(ownerId); + stream.addLong(statesBitmask); + stream.addByte(factionRank); + stream.addBoolean(defaultWeapon != null); + if (defaultWeapon != null) + SWGObjectFactory.save(defaultWeapon, stream); + synchronized (skills) { + stream.addList(skills, (s) -> stream.addAscii(s)); + } + synchronized (baseAttributes) { + stream.addList(baseAttributes, (s) -> stream.addInt(s)); } } + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + creo4.read(stream); + creo6.read(stream); + posture = Posture.valueOf(stream.getAscii()); + race = Race.valueOf(stream.getAscii()); + height = stream.getFloat(); + battleFatigue = stream.getInt(); + cashBalance = stream.getInt(); + bankBalance = stream.getInt(); + reserveBalance = stream.getLong(); + ownerId = stream.getLong(); + statesBitmask = stream.getLong(); + factionRank = stream.getByte(); + if (stream.getBoolean()) + defaultWeapon = (WeaponObject) SWGObjectFactory.create(stream); + stream.getList((i) -> skills.add(stream.getAscii())); + stream.getList((i) -> baseAttributes.set(i, stream.getInt())); + } + } diff --git a/src/resources/objects/creature/CreatureObjectClientServerNP.java b/src/resources/objects/creature/CreatureObjectClientServerNP.java new file mode 100644 index 000000000..5c3020b7a --- /dev/null +++ b/src/resources/objects/creature/CreatureObjectClientServerNP.java @@ -0,0 +1,323 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.objects.creature; + +import java.util.HashSet; +import java.util.Set; + +import resources.SkillMod; +import resources.collections.SWGList; +import resources.collections.SWGMap; +import resources.collections.SWGSet; +import resources.network.BaselineBuilder; +import resources.network.NetBuffer; +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import resources.persistable.Persistable; +import resources.player.Player; +import utilities.Encoder.StringType; + +class CreatureObjectClientServerNP implements Persistable { + + private double movementScale = 1; + private double movementPercent = 1; + private double walkSpeed = 1.549; + private double runSpeed = 7.3; + private double accelScale = 1; + private double accelPercent = 1; + private double turnScale = 1; + private double slopeModAngle = 1; + private double slopeModPercent = 1; + private double waterModPercent = 0.75; + private long performanceListenTarget = 0; + private int totalLevelXp = 0; + + private SWGSet missionCriticalObjs = new SWGSet<>(4, 13); + + private SWGList hamEncumbList = new SWGList(4, 2); + + private SWGMap skillMods = new SWGMap<>(4, 3, StringType.ASCII); + private SWGMap abilities = new SWGMap<>(4, 14, StringType.ASCII); + + public CreatureObjectClientServerNP() { + + } + + public void setMovementScale(double movementScale) { + this.movementScale = movementScale; + } + + public void setMovementPercent(double movementPercent) { + this.movementPercent = movementPercent; + } + + public void setWalkSpeed(double walkSpeed) { + this.walkSpeed = walkSpeed; + } + + public void setRunSpeed(double runSpeed) { + this.runSpeed = runSpeed; + } + + public void setAccelScale(double accelScale) { + this.accelScale = accelScale; + } + + public void setAccelPercent(double accelPercent) { + this.accelPercent = accelPercent; + } + + public void setTurnScale(double turnScale) { + this.turnScale = turnScale; + } + + public void setSlopeModAngle(double slopeModAngle) { + this.slopeModAngle = slopeModAngle; + } + + public void setSlopeModPercent(double slopeModPercent) { + this.slopeModPercent = slopeModPercent; + } + + public void setWaterModPercent(double waterModPercent) { + this.waterModPercent = waterModPercent; + } + + public void setPerformanceListenTarget(long performanceListenTarget) { + this.performanceListenTarget = performanceListenTarget; + } + + public void setTotalLevelXp(int totalLevelXp) { + this.totalLevelXp = totalLevelXp; + } + + public double getMovementScale() { + return movementScale; + } + + public double getMovementPercent() { + return movementPercent; + } + + public double getWalkSpeed() { + return walkSpeed; + } + + public double getRunSpeed() { + return runSpeed; + } + + public double getAccelScale() { + return accelScale; + } + + public double getAccelPercent() { + return accelPercent; + } + + public double getTurnScale() { + return turnScale; + } + + public double getSlopeModAngle() { + return slopeModAngle; + } + + public double getSlopeModPercent() { + return slopeModPercent; + } + + public double getWaterModPercent() { + return waterModPercent; + } + + public long getPerformanceListenTarget() { + return performanceListenTarget; + } + + public int getTotalLevelXp() { + return totalLevelXp; + } + + public void adjustSkillmod(String skillModName, int base, int modifier, SWGObject target) { + synchronized (skillMods) { + SkillMod skillMod = skillMods.get(skillModName); + + if (skillMod == null) { + // They didn't have this SkillMod already. + // Therefore, we send a full delta. + skillMods.put(skillModName, new SkillMod(base, modifier)); + skillMods.sendDeltaMessage(target); + } else { + // They already had this skillmod. + // All we need to do is adjust the base and the modifier and send an update from the +// SWGMap + skillMod.adjustBase(base); + skillMod.adjustModifier(modifier); + skillMods.update(skillModName, target); + } + } + } + + public int getSkillModValue(String skillModName) { + synchronized (skillMods) { + SkillMod skillMod = skillMods.get(skillModName); + return skillMod != null ? skillMod.getValue() : 0; + } + } + + public void addAbility(String abilityName, SWGObject target) { + synchronized (abilities) { + if (abilities.containsKey(abilityName)) + abilities.put(abilityName, abilities.get(abilityName) + 1); + else + abilities.put(abilityName, 1); + abilities.sendDeltaMessage(target); + } + } + + public void removeAbility(String abilityName) { + synchronized (abilities) { + Integer i = abilities.remove(abilityName); + if (i != null && i > 1) + abilities.put(abilityName, i-1); + } + } + + public boolean hasAbility(String abilityName) { + synchronized (abilities) { + return abilities.containsKey(abilityName); + } + } + + public Set getAbilityNames() { + synchronized (abilities) { + return new HashSet<>(abilities.keySet()); + } + }; + + public void createBaseline4(Player target, BaselineBuilder bb) { + bb.addFloat((float) accelPercent); // 0 + bb.addFloat((float) accelScale); // 1 + bb.addObject(hamEncumbList); // Rename to bonusAttributes? 2 + bb.addObject(skillMods); // 3 + bb.addFloat((float) movementPercent); // 4 + bb.addFloat((float) movementScale); // 5 + bb.addLong(performanceListenTarget); // 6 + bb.addFloat((float) runSpeed); // 7 + bb.addFloat((float) slopeModAngle); // 8 + bb.addFloat((float) slopeModPercent); // 9 + bb.addFloat((float) turnScale); // 10 + bb.addFloat((float) walkSpeed); // 11 + bb.addFloat((float) waterModPercent); // 12 + bb.addObject(missionCriticalObjs); // Group Missions? 13 + bb.addObject(abilities); // 14 + bb.addInt(totalLevelXp); // 15 + + bb.incrementOperandCount(16); + } + + public void parseBaseline4(NetBuffer buffer) { + accelPercent = buffer.getFloat(); + accelScale = buffer.getFloat(); + hamEncumbList = buffer.getSwgList(4, 2, Integer.class); + skillMods = buffer.getSwgMap(4, 3, StringType.ASCII, SkillMod.class); + movementPercent = buffer.getFloat(); + movementScale = buffer.getFloat(); + performanceListenTarget = buffer.getLong(); + runSpeed = buffer.getFloat(); + slopeModAngle = buffer.getFloat(); + slopeModPercent = buffer.getFloat(); + turnScale = buffer.getFloat(); + walkSpeed = buffer.getFloat(); + waterModPercent = buffer.getFloat(); + missionCriticalObjs = buffer.getSwgSet(4, 13, StringType.ASCII); + abilities = buffer.getSwgMap(4, 14, StringType.ASCII, Integer.class); + totalLevelXp = buffer.getInt(); + } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addFloat((float) accelPercent); + stream.addFloat((float) accelScale); + stream.addFloat((float) movementPercent); + stream.addFloat((float) movementScale); + stream.addFloat((float) runSpeed); + stream.addFloat((float) slopeModAngle); + stream.addFloat((float) slopeModPercent); + stream.addFloat((float) turnScale); + stream.addFloat((float) walkSpeed); + stream.addFloat((float) waterModPercent); + stream.addInt(totalLevelXp); + synchronized (hamEncumbList) { + stream.addList(hamEncumbList, (i) -> stream.addInt(i)); + } + synchronized (skillMods) { + stream.addMap(skillMods, (e) -> { + stream.addAscii(e.getKey()); + e.getValue().save(stream); + }); + } + synchronized (missionCriticalObjs) { + stream.addList(missionCriticalObjs, (s) -> stream.addAscii(s)); + } + synchronized (abilities) { + stream.addMap(abilities, (e) -> { + stream.addAscii(e.getKey()); + stream.addInt(e.getValue()); + }); + } + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + accelPercent = stream.getFloat(); + accelScale = stream.getFloat(); + movementPercent = stream.getFloat(); + movementScale = stream.getFloat(); + runSpeed = stream.getFloat(); + slopeModAngle = stream.getFloat(); + slopeModPercent = stream.getFloat(); + turnScale = stream.getFloat(); + walkSpeed = stream.getFloat(); + waterModPercent = stream.getFloat(); + totalLevelXp = stream.getInt(); + stream.getList((i) -> hamEncumbList.add(stream.getInt())); + stream.getList((i) -> { + SkillMod mod = new SkillMod(); + String key = stream.getAscii(); + mod.read(stream); + skillMods.put(key, mod); + }); + stream.getList((i) -> missionCriticalObjs.add(stream.getAscii())); + stream.getList((i) -> abilities.put(stream.getAscii(), stream.getInt())); + } + +} diff --git a/src/resources/objects/creature/CreatureObjectSharedNP.java b/src/resources/objects/creature/CreatureObjectSharedNP.java new file mode 100644 index 000000000..8b7a59170 --- /dev/null +++ b/src/resources/objects/creature/CreatureObjectSharedNP.java @@ -0,0 +1,528 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.objects.creature; + +import resources.HologramColour; +import resources.collections.SWGList; +import resources.collections.SWGMap; +import resources.common.CRC; +import resources.encodables.player.Equipment; +import resources.network.BaselineBuilder; +import resources.network.NetBuffer; +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import resources.objects.weapon.WeaponObject; +import resources.persistable.Persistable; +import resources.persistable.SWGObjectFactory; +import resources.player.Player; +import services.group.GroupInviterData; + +class CreatureObjectSharedNP implements Persistable { + + private transient GroupInviterData inviterData = new GroupInviterData(0, null, "", 0); + private transient long groupId = 0; + + private short level = 1; + private int levelHealthGranted = 0; + private String animation = ""; + private String moodAnimation = "neutral"; + private WeaponObject equippedWeapon = null; + private int guildId = 0; + private long lookAtTargetId = 0; + private long intendedTargetId = 0; + private byte moodId = 0; + private int performanceCounter = 0; + private int performanceId = 0; + private String costume = ""; + private boolean visible = true; + private boolean performing = false; + private CreatureDifficulty difficulty = CreatureDifficulty.NORMAL; + private HologramColour hologramColour = HologramColour.DEFAULT; + private boolean shownOnRadar = true; + private boolean beast = false; + + private SWGList attributes = new SWGList(6, 21); + private SWGList maxAttributes = new SWGList(6, 22); + private SWGList equipmentList = new SWGList(6, 23); + private SWGList appearanceList = new SWGList(6, 33); + + private SWGMap buffs = new SWGMap<>(6, 26); + + public CreatureObjectSharedNP() { + initCurrentAttributes(); + initMaxAttributes(); + } + + public void addEquipment(SWGObject obj, SWGObject target) { + synchronized (equipmentList) { + if (obj instanceof WeaponObject) + equipmentList.add(new Equipment((WeaponObject) obj)); + else + equipmentList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); + equipmentList.sendDeltaMessage(target); + } + } + + public void removeEquipment(SWGObject obj, SWGObject target) { + synchronized (equipmentList) { + for (Equipment equipment : equipmentList) { + if (equipment.getObjectId() == obj.getObjectId()) { + equipmentList.remove(equipment); + equipmentList.sendDeltaMessage(target); + return; + } + } + } + } + + public void addAppearanceItem(SWGObject obj, SWGObject target) { + synchronized (appearanceList) { + appearanceList.add(new Equipment(obj.getObjectId(), obj.getTemplate())); + appearanceList.sendDeltaMessage(target); + } + } + + public void removeAppearanceItem(SWGObject obj, SWGObject target) { + synchronized (appearanceList) { + for (Equipment equipment : appearanceList) { + if (equipment.getObjectId() == obj.getObjectId()) { + appearanceList.remove(equipment); + appearanceList.sendDeltaMessage(target); + return; + } + } + } + } + + public SWGList getEquipmentList() { + return equipmentList; + } + + public SWGList getAppearanceList() { + return appearanceList; + } + + public void setGuildId(int guildId) { + this.guildId = guildId; + } + + public void setLevel(int level) { + this.level = (short) level; + } + + public void setLevelHealthGranted(int levelHealthGranted) { + this.levelHealthGranted = levelHealthGranted; + } + + public void setDifficulty(CreatureDifficulty difficulty) { + this.difficulty = difficulty; + } + + public void setMoodAnimation(String moodAnimation) { + this.moodAnimation = moodAnimation; + } + + public void setBeast(boolean beast) { + this.beast = beast; + } + + public void setEquippedWeapon(WeaponObject weapon) { + this.equippedWeapon = weapon; + } + + public void setMoodId(byte moodId) { + this.moodId = moodId; + } + + public void setLookAtTargetId(long lookAtTargetId) { + this.lookAtTargetId = lookAtTargetId; + } + + public void setIntendedTargetId(long intendedTargetId) { + this.intendedTargetId = intendedTargetId; + } + + public void setPerformanceCounter(int performanceCounter) { + this.performanceCounter = performanceCounter; + } + + public void setPerformanceId(int performanceId) { + this.performanceId = performanceId; + } + + public int getGuildId() { + return guildId; + } + + public short getLevel() { + return level; + } + + public int getLevelHealthGranted() { + return levelHealthGranted; + } + + public CreatureDifficulty getDifficulty() { + return difficulty; + } + + public String getCostume() { + return costume; + } + + public void setCostume(String costume) { + this.costume = costume; + } + + public void updateGroupInviteData(Player sender, long groupId, String name) { + inviterData.setName(name); + inviterData.setSender(sender); + inviterData.setId(groupId); + inviterData.incrementCounter(); + } + + public long getGroupId() { + return groupId; + } + + public GroupInviterData getInviterData() { + return inviterData; + } + + public void setGroupId(long groupId) { + this.groupId = groupId; + } + + public String getAnimation() { + return animation; + } + + public byte getMoodId() { + return moodId; + } + + public long getLookAtTargetId() { + return lookAtTargetId; + } + + public long getIntendedTargetId() { + return intendedTargetId; + } + + public int getPerformanceCounter() { + return performanceCounter; + } + + public int getPerformanceId() { + return performanceId; + } + + public void setAnimation(String animation) { + this.animation = animation; + } + + public String getMoodAnimation() { + return moodAnimation; + } + + public boolean isBeast() { + return beast; + } + + public WeaponObject getEquippedWeapon() { + return equippedWeapon; + } + + public boolean isVisible() { + return visible; + } + + public void setVisible(boolean visible) { + this.visible = visible; + } + + public boolean isPerforming() { + return performing; + } + + public void setPerforming(boolean performing) { + this.performing = performing; + } + + public void setHologramColour(HologramColour hologramColour) { + this.hologramColour = hologramColour; + } + + public boolean isShownOnRadar() { + return shownOnRadar; + } + + public void setShownOnRadar(boolean shownOnRadar) { + this.shownOnRadar = shownOnRadar; + } + + public int getHealth() { + synchronized (attributes) { + return attributes.get(0); + } + } + + public int getMaxHealth() { + synchronized (maxAttributes) { + return maxAttributes.get(0); + } + } + + public int getAction() { + synchronized (attributes) { + return attributes.get(2); + } + } + + public int getMaxAction() { + synchronized (maxAttributes) { + return maxAttributes.get(2); + } + } + + public int getMind() { + synchronized (attributes) { + return attributes.get(4); + } + } + + public int getMaxMind() { + synchronized (maxAttributes) { + return maxAttributes.get(4); + } + } + + public void setHealth(int health, SWGObject target) { + synchronized(attributes) { + attributes.set(0, health); + attributes.sendDeltaMessage(target); + } + } + + public void modifyHealth(int mod, SWGObject target) { + synchronized(attributes) { + attributes.set(0, getHealth() + mod); + attributes.sendDeltaMessage(target); + } + } + + public void setMaxHealth(int maxHealth, SWGObject target) { + synchronized(maxAttributes) { + maxAttributes.set(0, maxHealth); + maxAttributes.sendDeltaMessage(target); + } + } + + public void setAction(int action, SWGObject target) { + synchronized(attributes) { + attributes.set(2, action); + attributes.sendDeltaMessage(target); + } + } + + public void modifyAction(int mod, SWGObject target) { + synchronized(attributes) { + attributes.set(2, getAction() + mod); + attributes.sendDeltaMessage(target); + } + } + + public void setMaxAction(int maxAction, SWGObject target) { + synchronized(maxAttributes) { + maxAttributes.set(2, maxAction); + maxAttributes.sendDeltaMessage(target); + } + } + + public void setMind(int mind, SWGObject target) { + synchronized(attributes) { + attributes.set(4, mind); + attributes.sendDeltaMessage(target); + } + } + + public void modifyMind(int mod, SWGObject target) { + synchronized(attributes) { + attributes.set(4, getMind() + mod); + attributes.sendDeltaMessage(target); + } + } + + public void setMaxMind(int maxMind, SWGObject target) { + synchronized(maxAttributes) { + maxAttributes.set(4, maxMind); + maxAttributes.sendDeltaMessage(target); + } + } + + private void initMaxAttributes() { + maxAttributes.add(0, 1000); // Health + maxAttributes.add(1, 0); + maxAttributes.add(2, 300); // Action + maxAttributes.add(3, 0); + maxAttributes.add(4, 300); // Mind + maxAttributes.add(5, 0); + maxAttributes.clearDeltaQueue(); + } + + private void initCurrentAttributes() { + attributes.add(0, 1000); // Health + attributes.add(1, 0); + attributes.add(2, 300); // Action + attributes.add(3, 0); + attributes.add(4, 300); // Mind + attributes.add(5, 0); + attributes.clearDeltaQueue(); + } + + public void createBaseline6(Player target, BaselineBuilder bb) { + bb.addShort(level); // 8 + bb.addInt(levelHealthGranted); // 9 + bb.addAscii(animation); // 10 + bb.addAscii(moodAnimation); // 11 + bb.addLong(equippedWeapon == null ? 0 : equippedWeapon.getObjectId()); // 12 + bb.addLong(groupId); // 13 + bb.addObject(inviterData); // 14 + bb.addInt(guildId); // 15 + bb.addLong(lookAtTargetId); // 16 + bb.addLong(intendedTargetId); // 17 + bb.addByte(moodId); // 18 + bb.addInt(performanceCounter); // 19 + bb.addInt(performanceId); // 20 + bb.addObject(attributes); // 21 + bb.addObject(maxAttributes); // 22 + bb.addObject(equipmentList); // 23 + bb.addAscii(costume); // 24 + bb.addBoolean(visible); // 25 + bb.addObject(buffs); // 26 + bb.addBoolean(performing); // 27 + bb.addByte(difficulty.getDifficulty()); // 28 + bb.addInt((hologramColour == null) ? -1 : hologramColour.getValue()); // Hologram Color -- 29 + bb.addBoolean(shownOnRadar); // 30 + bb.addBoolean(beast); // 31 + bb.addByte(0); // forceShowHam? -- 32 + bb.addObject(appearanceList); // 33 + bb.addLong(0); // decoy? -- 34 + + bb.incrementOperandCount(27); + } + + public void parseBaseline6(NetBuffer buffer) { + level = buffer.getShort(); + levelHealthGranted = buffer.getInt(); + animation = buffer.getAscii(); + moodAnimation = buffer.getAscii(); + long weaponId = buffer.getLong(); + groupId = buffer.getLong(); + inviterData = buffer.getEncodable(GroupInviterData.class); + guildId = buffer.getInt(); + lookAtTargetId = buffer.getLong(); + intendedTargetId = buffer.getLong(); + moodId = buffer.getByte(); + performanceCounter = buffer.getInt(); + performanceId = buffer.getInt(); + attributes = buffer.getSwgList(6, 21, Integer.class); + maxAttributes = buffer.getSwgList(6, 22, Integer.class); + equipmentList = buffer.getSwgList(6, 23, Equipment.class); + costume = buffer.getAscii(); + visible = buffer.getBoolean(); + buffs = buffer.getSwgMap(6, 26, CRC.class, Buff.class); + performing = buffer.getBoolean(); + difficulty = CreatureDifficulty.getForDifficulty(buffer.getByte()); + hologramColour = HologramColour.getForValue(buffer.getInt()); + shownOnRadar = buffer.getBoolean(); + beast = buffer.getBoolean(); + buffer.getBoolean(); + appearanceList = buffer.getSwgList(6, 33, Equipment.class); + buffer.getLong(); + equippedWeapon = null; + for (Equipment e : equipmentList) { + if (e.getObjectId() == weaponId && e.getWeapon() instanceof WeaponObject) { + equippedWeapon = (WeaponObject) e.getWeapon(); + break; + } + } + } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addShort(level); + stream.addInt(levelHealthGranted); + stream.addAscii(animation); + stream.addAscii(moodAnimation); + stream.addInt(guildId); + stream.addLong(lookAtTargetId); + stream.addLong(intendedTargetId); + stream.addByte(moodId); + stream.addAscii(costume); + stream.addBoolean(visible); + stream.addBoolean(shownOnRadar); + stream.addBoolean(beast); + stream.addAscii(difficulty.name()); + stream.addAscii(hologramColour.name()); + stream.addBoolean(equippedWeapon != null); + if (equippedWeapon != null) + SWGObjectFactory.save(equippedWeapon, stream); + synchronized (attributes) { + stream.addList(attributes, (i) -> stream.addInt(i)); + } + synchronized (maxAttributes) { + stream.addList(maxAttributes, (i) -> stream.addInt(i)); + } + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + level = stream.getShort(); + levelHealthGranted = stream.getInt(); + animation = stream.getAscii(); + moodAnimation = stream.getAscii(); + guildId = stream.getInt(); + lookAtTargetId = stream.getLong(); + intendedTargetId = stream.getLong(); + moodId = stream.getByte(); + costume = stream.getAscii(); + visible = stream.getBoolean(); + shownOnRadar = stream.getBoolean(); + beast = stream.getBoolean(); + difficulty = CreatureDifficulty.valueOf(stream.getAscii()); + hologramColour = HologramColour.valueOf(stream.getAscii()); + if (stream.getBoolean()) + equippedWeapon = (WeaponObject) SWGObjectFactory.create(stream); + stream.getList((i) -> attributes.set(i, stream.getInt())); + stream.getList((i) -> maxAttributes.set(i, stream.getInt())); + } + +} diff --git a/src/resources/objects/custom/AIObject.java b/src/resources/objects/custom/AIObject.java index e274cf773..35a5770ba 100644 --- a/src/resources/objects/custom/AIObject.java +++ b/src/resources/objects/custom/AIObject.java @@ -35,8 +35,6 @@ import utilities.ScheduledUtilities; public abstract class AIObject extends CreatureObject { - private static final long serialVersionUID = 1L; - private transient ScheduledFuture future; private long initialDelay; private long delay; diff --git a/src/resources/objects/custom/DefaultAIObject.java b/src/resources/objects/custom/DefaultAIObject.java index 3806d541e..d0ea87df0 100644 --- a/src/resources/objects/custom/DefaultAIObject.java +++ b/src/resources/objects/custom/DefaultAIObject.java @@ -36,8 +36,6 @@ import resources.Point3D; public class DefaultAIObject extends AIObject { - private static final long serialVersionUID = 1L; - private Location mainLocation; private AIBehavior behavior; private int updateCounter; diff --git a/src/resources/objects/factory/FactoryObject.java b/src/resources/objects/factory/FactoryObject.java index 9116f64d0..0d730c9b2 100644 --- a/src/resources/objects/factory/FactoryObject.java +++ b/src/resources/objects/factory/FactoryObject.java @@ -28,14 +28,25 @@ package resources.objects.factory; import network.packets.swg.zone.baselines.Baseline.BaselineType; +import resources.network.NetBufferStream; import resources.objects.tangible.TangibleObject; public class FactoryObject extends TangibleObject { - private static final long serialVersionUID = 1L; - public FactoryObject(long objectId) { super(objectId, BaselineType.FCYT); } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + } + } diff --git a/src/resources/objects/group/GroupObject.java b/src/resources/objects/group/GroupObject.java index 57ba9a66d..79475dcdd 100644 --- a/src/resources/objects/group/GroupObject.java +++ b/src/resources/objects/group/GroupObject.java @@ -45,8 +45,7 @@ import java.util.HashMap; import java.util.Map; public class GroupObject extends SWGObject { // Extends INTO or TANO? - private static final long serialVersionUID = 200L; - + private final SWGList groupMembers = new SWGList<>(6, 2, Encoder.StringType.ASCII); private long leader; private short level; diff --git a/src/resources/objects/guild/GuildObject.java b/src/resources/objects/guild/GuildObject.java index 755a77ffb..618db8850 100644 --- a/src/resources/objects/guild/GuildObject.java +++ b/src/resources/objects/guild/GuildObject.java @@ -41,8 +41,6 @@ import utilities.Encoder.StringType; public class GuildObject extends SWGObject { - private static final long serialVersionUID = 1L; - private SWGSet abbreviations = new SWGSet(3, 4, StringType.ASCII); private SWGMap gcwImperialScorePercentileThisGalaxy = new SWGMap<>(6, 2); private SWGMap gcwGroupImperialScorePercentileThisGalaxy = new SWGMap<>(6, 3); diff --git a/src/resources/objects/installation/InstallationObject.java b/src/resources/objects/installation/InstallationObject.java index 3a2589b7d..bb9f4dac2 100644 --- a/src/resources/objects/installation/InstallationObject.java +++ b/src/resources/objects/installation/InstallationObject.java @@ -30,13 +30,12 @@ package resources.objects.installation; import network.packets.swg.zone.baselines.Baseline.BaselineType; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.tangible.TangibleObject; import resources.player.Player; public class InstallationObject extends TangibleObject { - private static final long serialVersionUID = 1L; - private boolean activated = false; private double power = 0; private double powerRate = 0; @@ -105,4 +104,22 @@ public class InstallationObject extends TangibleObject { return hash; } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addBoolean(activated); + stream.addFloat((float) power); + stream.addFloat((float) powerRate); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + activated = stream.getBoolean(); + power = stream.getFloat(); + powerRate = stream.getFloat(); + } + } diff --git a/src/resources/objects/intangible/IntangibleObject.java b/src/resources/objects/intangible/IntangibleObject.java index 6108518c1..a237ef4cb 100644 --- a/src/resources/objects/intangible/IntangibleObject.java +++ b/src/resources/objects/intangible/IntangibleObject.java @@ -30,13 +30,12 @@ package resources.objects.intangible; import network.packets.swg.zone.baselines.Baseline.BaselineType; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.SWGObject; import resources.player.Player; public class IntangibleObject extends SWGObject { - private static final long serialVersionUID = 1L; - private int count = 0; public IntangibleObject(long objectId) { @@ -76,4 +75,18 @@ public class IntangibleObject extends SWGObject { public int hashCode() { return super.hashCode(); } + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addInt(count); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + count = stream.getInt(); + } } diff --git a/src/resources/objects/manufacture/ManufactureSchematicObject.java b/src/resources/objects/manufacture/ManufactureSchematicObject.java index cee7a9905..be3258171 100644 --- a/src/resources/objects/manufacture/ManufactureSchematicObject.java +++ b/src/resources/objects/manufacture/ManufactureSchematicObject.java @@ -27,20 +27,21 @@ ***********************************************************************************/ package resources.objects.manufacture; +import java.util.Map.Entry; + import network.packets.swg.zone.baselines.Baseline.BaselineType; import resources.collections.SWGMap; import resources.common.CRC; import resources.encodables.StringId; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.intangible.IntangibleObject; import resources.player.Player; import resources.server_info.CrcDatabase; public class ManufactureSchematicObject extends IntangibleObject { - private static final long serialVersionUID = 1L; - private SWGMap attributes = new SWGMap<>(3, 5); private int itemsPerContainer = 0; private float manufactureTime = 0; @@ -158,4 +159,42 @@ public class ManufactureSchematicObject extends IntangibleObject { schematicChangedSignal = buffer.getByte(); } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addInt(itemsPerContainer); + stream.addFloat(manufactureTime); + stream.addArray(appearanceData); + stream.addArray(customAppearance); + stream.addAscii(draftSchematicTemplate); + stream.addBoolean(crafting); + stream.addByte(schematicChangedSignal); + synchronized (attributes) { + stream.addInt(attributes.size()); + for (Entry e : attributes.entrySet()) { + e.getKey().save(stream); + stream.addFloat(e.getValue()); + } + } + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + itemsPerContainer = stream.getInt(); + manufactureTime = stream.getFloat(); + appearanceData = stream.getArray(); + customAppearance = stream.getArray(); + draftSchematicTemplate = stream.getAscii(); + crafting = stream.getBoolean(); + schematicChangedSignal = stream.getByte(); + for (int i = 0; i < stream.getInt(); i++) { + StringId id = new StringId(); + id.read(stream); + attributes.put(id, stream.getFloat()); + } + } + } diff --git a/src/resources/objects/mission/MissionObject.java b/src/resources/objects/mission/MissionObject.java index 03325c7a0..96687807e 100644 --- a/src/resources/objects/mission/MissionObject.java +++ b/src/resources/objects/mission/MissionObject.java @@ -37,14 +37,14 @@ import resources.encodables.Encodable; import resources.encodables.StringId; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.intangible.IntangibleObject; import resources.objects.waypoint.WaypointObject; +import resources.persistable.Persistable; import resources.player.Player; public class MissionObject extends IntangibleObject { - private static final long serialVersionUID = 1L; - private int difficulty = 0; private MissionLocation location = new MissionLocation(); private String missionCreator = ""; @@ -109,7 +109,43 @@ public class MissionObject extends IntangibleObject { buffer.getInt(); } - public static class MissionLocation implements Encodable { + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addInt(difficulty); + stream.addInt(reward); + stream.addInt(status); + stream.addUnicode(missionCreator); + stream.addUnicode(targetName); + title.save(stream); + description.save(stream); + targetAppearance.save(stream); + missionType.save(stream); + waypoint.save(stream); + startLocation.save(stream); + location.save(stream); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + difficulty = stream.getInt(); + reward = stream.getInt(); + status = stream.getInt(); + missionCreator = stream.getUnicode(); + targetName = stream.getUnicode(); + title.read(stream); + description.read(stream); + targetAppearance.read(stream); + missionType.read(stream); + waypoint.read(stream); + startLocation.read(stream); + location.read(stream); + } + + public static class MissionLocation implements Encodable, Persistable { private Point3D location; private long objectId; @@ -138,6 +174,22 @@ public class MissionObject extends IntangibleObject { terrain = Terrain.getTerrainFromCrc(data.getInt()); } + @Override + public void save(NetBufferStream stream) { + stream.addInt(0); + stream.addLong(objectId); + location.save(stream); + stream.addAscii(terrain.name()); + } + + @Override + public void read(NetBufferStream stream) { + stream.getInt(); + objectId = stream.getLong(); + location.read(stream); + terrain = Terrain.valueOf(stream.getAscii()); + } + } } diff --git a/src/resources/objects/mobile/MobileObject.java b/src/resources/objects/mobile/MobileObject.java index df604894d..f3ca8f0e9 100644 --- a/src/resources/objects/mobile/MobileObject.java +++ b/src/resources/objects/mobile/MobileObject.java @@ -31,8 +31,6 @@ import resources.objects.creature.CreatureObject; public class MobileObject extends CreatureObject { - private static final long serialVersionUID = 1L; - public MobileObject(long objectId) { super(objectId); } diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index 499461116..daaa14374 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -29,12 +29,9 @@ package resources.objects.player; import network.packets.swg.zone.UpdatePostureMessage; import network.packets.swg.zone.baselines.Baseline.BaselineType; -import network.packets.swg.zone.chat.ChatSystemMessage; -import resources.collections.SWGFlag; -import resources.collections.SWGBitSet; -import resources.collections.SWGList; import resources.collections.SWGMap; import resources.network.BaselineBuilder; +import resources.network.NetBufferStream; import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; import resources.objects.intangible.IntangibleObject; @@ -42,68 +39,22 @@ import resources.objects.waypoint.WaypointObject; import resources.player.AccessLevel; import resources.player.Player; import resources.player.PlayerFlags; -import utilities.MathUtils; import utilities.Encoder.StringType; import java.util.ArrayList; -import java.util.BitSet; import java.util.Collections; import java.util.List; public class PlayerObject extends IntangibleObject { - private static final long serialVersionUID = 1L; + private PlayerObjectShared play3 = new PlayerObjectShared(); + private PlayerObjectSharedNP play6 = new PlayerObjectSharedNP(); + private PlayerObjectPrivate play8 = new PlayerObjectPrivate(); + private PlayerObjectPrivateNP play9 = new PlayerObjectPrivateNP(); - private String biography = ""; - private List joinedChannels = new ArrayList<>(); - - // PLAY 03 - private SWGFlag flagsList = new SWGFlag(3, 5); - private SWGFlag profileFlags = new SWGFlag(3, 6); - private String title = ""; - private int bornDate = 0; - private int playTime = 0; - private int professionIcon = 0; - private String profession = ""; - private int gcwPoints = 0; - private int pvpKills = 0; - private long lifetimeGcwPoints = 0; - private int lifetimePvpKills = 0; - private SWGBitSet collectionBadges = new SWGBitSet(3, 16); - private SWGBitSet collectionBadges2 = new SWGBitSet(3, 17); - private boolean showHelmet = true; - private boolean showBackpack = true; - // PLAY 06 - private int adminTag = 0; - private int currentRank = 0; - private float rankProgress = 0; - private int highestRebelRank = 0; - private int highestImperialRank = 0; - private int gcwNextUpdate = 0; - private String home = ""; - // PLAY 08 - private SWGMap experience = new SWGMap<>(8, 0, StringType.ASCII); - private SWGMap waypoints = new SWGMap<>(8, 1); - private boolean citizen = false; - private int guildRankTitle = 0; - private int activeQuest = 0; - private SWGMap quests = new SWGMap<>(8, 7); - private String profWheelPosition = ""; - // PLAY 09 - private int experimentFlag = 0; - private int craftingStage = 0; - private long nearbyCraftStation = 0; - private SWGList draftSchemList = new SWGList<>(9, 3, StringType.ASCII); - private int experimentPoints = 0; - private SWGList friendsList = new SWGList<>(9, 7, StringType.ASCII); - private SWGList ignoreList = new SWGList<>(9, 8, StringType.ASCII); - private int languageId = 0; - private SWGList defenders = new SWGList<>(9, 17); // TODO: Change to set - private int killMeter = 0; - private long petId = 0; - private SWGList petAbilities = new SWGList<>(9, 21); - private SWGList activePetAbilities = new SWGList<>(9, 22); - private int startPlayTime; + private int startPlayTime = 0; + private String biography = ""; + private List joinedChannels = new ArrayList<>(); public PlayerObject(long objectId) { super(objectId, BaselineType.PLAY); @@ -111,129 +62,110 @@ public class PlayerObject extends IntangibleObject { } public void addWaypoint(WaypointObject waypoint) { - synchronized(waypoints) { - if (waypoints.size() < 250) { - waypoints.put(waypoint.getObjectId(), waypoint); - waypoints.sendDeltaMessage(this); - } - else { - sendSelf(new ChatSystemMessage(ChatSystemMessage.SystemChatType.SCREEN_AND_CHAT, "@base_player:too_many_waypoints")); - } - } + play8.addWaypoint(waypoint, this); } public WaypointObject getWaypoint(long objId) { - synchronized(waypoints) { - return waypoints.get(objId); - } + return play8.getWaypoint(objId); } public SWGMap getWaypoints() { - synchronized(waypoints) { - return waypoints; - } + return play8.getWaypoints(); } public void updateWaypoint(WaypointObject obj) { - synchronized(waypoints) { - waypoints.update(obj.getObjectId(), this); - } + play8.updateWaypoint(obj, this); } public void removeWaypoint(long objId) { - synchronized(waypoints) { - waypoints.remove(objId); - waypoints.sendDeltaMessage(this); - } + play8.removeWaypoint(objId, this); } public String getTitle() { - return title; + return play3.getTitle(); } public void setTitle(String title) { - this.title = title; + play3.setTitle(title); sendDelta(3, 7, title, StringType.ASCII); } public int getPlayTime() { - return playTime; + return play3.getPlayTime(); } public void setPlayTime(int playTime) { - this.playTime = playTime; + play3.setPlayTime(playTime); sendDelta(3, 9, playTime); } public int getGcwPoints() { - return gcwPoints; + return play3.getGcwPoints(); } public void setGcwPoints(int gcwPoints) { - this.gcwPoints = gcwPoints; + play3.setGcwPoints(gcwPoints); sendDelta(3, 12, gcwPoints); } public int getPvpKills() { - return pvpKills; + return play3.getPvpKills(); } public void setPvpKills(int pvpKills) { - this.pvpKills = pvpKills; + play3.setPvpKills(pvpKills); sendDelta(3, 13, pvpKills); } public long getLifetimeGcwPoints() { - return lifetimeGcwPoints; + return play3.getLifetimeGcwPoints(); } public void setLifetimeGcwPoints(long lifetimeGcwPoints) { - this.lifetimeGcwPoints = lifetimeGcwPoints; + play3.setLifetimeGcwPoints(lifetimeGcwPoints); sendDelta(3, 14, lifetimeGcwPoints); } public int getLifetimePvpKills() { - return lifetimePvpKills; + return play3.getLifetimePvpKills(); } public void setLifetimePvpKills(int lifetimePvpKills) { - this.lifetimePvpKills = lifetimePvpKills; + play3.setLifetimePvpKills(lifetimePvpKills); sendDelta(3, 15, lifetimePvpKills); } public byte[] getCollectionBadges() { - return collectionBadges.toByteArray(); + return play3.getCollectionBadges(); } public void setCollectionBadges(byte[] collection) { - this.collectionBadges.clear(); - this.collectionBadges.or(BitSet.valueOf(collection)); - sendDelta(3, 16, collectionBadges); + play3.setCollectionBadges(collection, this); } public boolean isShowHelmet() { - return showHelmet; + return play3.isShowHelmet(); } public void setShowHelmet(boolean showHelmet) { - this.showHelmet = showHelmet; + play3.setShowHelmet(showHelmet); sendDelta(3, 19, showHelmet); } public boolean isShowBackpack() { - return showBackpack; + return play3.isShowBackpack(); } public void setShowBackpack(boolean showBackpack) { - this.showBackpack = showBackpack; + play3.setShowBackpack(showBackpack); sendDelta(3, 18, showBackpack); } public String getProfession() { - return profession; + return play3.getProfession(); } public void setProfession(String profession) { - this.profession = profession; + play3.setProfession(profession); sendDelta(3, 11, profession, StringType.ASCII); } @@ -246,183 +178,150 @@ public class PlayerObject extends IntangibleObject { } public void setBornDate(int year, int month, int day) { - this.bornDate = MathUtils.numberDaysSince(year, month, day, 2000, 12, 31); + play3.setBornDate(year, month, day); } public int getBornDate() { - return bornDate; + return play3.getBornDate(); + } + + public int getAdminTag() { + return play6.getAdminTag(); } public void setAdminTag(AccessLevel access) { - switch(access) { - case PLAYER: break; - case CSR: adminTag = 1; break; - case DEV: adminTag = 2; break; - case WARDEN: adminTag = 3; break; - case QA: adminTag = 4; break; - } - sendDelta(6, 2, adminTag); - } - - public void setAdminTag(int tag) { - this.adminTag = tag; - sendDelta(6, 2, tag); + play6.setAdminTag(access); + sendDelta(6, 2, play6.getAdminTag()); } public int getCurrentRank() { - return currentRank; + return play6.getCurrentRank(); } public void setCurrentRank(int currentRank) { - this.currentRank = currentRank; + play6.setCurrentRank(currentRank); sendDelta(6, 3, currentRank); } public float getRankProgress() { - return rankProgress; + return play6.getRankProgress(); } public void setRankProgress(float rankProgress) { - this.rankProgress = rankProgress; + play6.setRankProgress(rankProgress); sendDelta(6, 4, rankProgress); } public int getHighestRebelRank() { - return highestRebelRank; + return play6.getHighestRebelRank(); } public void setHighestRebelRank(int highestRebelRank) { - this.highestRebelRank = highestRebelRank; + play6.setHighestRebelRank(highestRebelRank); sendDelta(6, 5, highestRebelRank); } public int getHighestImperialRank() { - return highestImperialRank; + return play6.getHighestImperialRank(); } public void setHighestImperialRank(int highestImperialRank) { - this.highestImperialRank = highestImperialRank; + play6.setHighestImperialRank(highestImperialRank); sendDelta(6, 6, highestImperialRank); } public int getGcwNextUpdate() { - return gcwNextUpdate; + return play6.getGcwNextUpdate(); } public void setGcwNextUpdate(int gcwNextUpdate) { - this.gcwNextUpdate = gcwNextUpdate; + play6.setGcwNextUpdate(gcwNextUpdate); sendDelta(6, 7, gcwNextUpdate); } public String getHome() { - return home; + return play6.getHome(); } public void setHome(String home) { - this.home = home; + play6.setHome(home); sendDelta(6, 8, home, StringType.ASCII); } - + public boolean isCitizen() { - return citizen; + return play6.isCitizen(); } - + public void setCitizen(boolean citizen) { - this.citizen = citizen; + play6.setCitizen(citizen); sendDelta(6, 9, citizen); } public int getGuildRankTitle() { - return guildRankTitle; + return play8.getGuildRankTitle(); } public void setGuildRankTitle(int guildRankTitle) { - this.guildRankTitle = guildRankTitle; + play8.setGuildRankTitle(guildRankTitle); sendDelta(6, 13, guildRankTitle); } public int getActiveQuest() { - return activeQuest; + return play8.getActiveQuest(); } public void setActiveQuest(int activeQuest) { - this.activeQuest = activeQuest; + play8.setActiveQuest(activeQuest); sendDelta(8, 6, activeQuest); } public void removeFriend(String friend) { - synchronized (friendsList) { - friendsList.remove(friend); - } - friendsList.sendDeltaMessage(this); + play9.removeFriend(friend, this); } public void addFriend(String friend) { - synchronized (friendsList) { - friendsList.add(friend); - } - friendsList.sendDeltaMessage(this); + play9.addFriend(friend, this); } public List getFriendsList() { - return friendsList; + return play9.getFriendsList(); } public void addIgnored(String ignored) { - synchronized (ignoreList) { - ignoreList.add(ignored); - } - ignoreList.sendDeltaMessage(this); + play9.addIgnored(ignored, this); } public void removeIgnored(String ignored) { - synchronized (ignoreList) { - ignoreList.remove(ignored); - } - ignoreList.sendDeltaMessage(this); + play9.removeIgnored(ignored, this); } public boolean isIgnored(String target) { - return ignoreList.contains(target); + return play9.isIgnored(target); } public List getIgnoreList() { - return ignoreList; + return play9.getIgnoreList(); } public String getProfWheelPosition() { - return profWheelPosition; + return play8.getProfWheelPosition(); } public void setProfWheelPosition(String profWheelPosition) { - this.profWheelPosition = profWheelPosition; + play8.setProfWheelPosition(profWheelPosition); sendDelta(8, 8, profWheelPosition, StringType.ASCII); } public void setFlagBitmask(PlayerFlags ... flags) { - boolean changed = false; - for (PlayerFlags flag : flags) { - changed |= !flagsList.get(flag.getFlag()); - flagsList.set(flag.getFlag()); - } - if (changed) - flagsList.sendDeltaMessage(this); + play3.setFlagBitmask(this, flags); } public void clearFlagBitmask(PlayerFlags ... flags) { - boolean changed = false; - for (PlayerFlags flag : flags) { - changed |= flagsList.get(flag.getFlag()); - flagsList.clear(flag.getFlag()); - } - if (changed) - flagsList.sendDeltaMessage(this); + play3.clearFlagBitmask(this, flags); } public void toggleFlag(PlayerFlags ... flags) { - for (PlayerFlags flag : flags) - flagsList.flip(flag.getFlag()); - flagsList.sendDeltaMessage(this); + play3.toggleFlag(this, flags); } public List getJoinedChannels() { @@ -448,26 +347,36 @@ public class PlayerObject extends IntangibleObject { } public void setProfessionIcon(int professionIcon) { - this.professionIcon = professionIcon; + play3.setProfessionIcon(professionIcon); sendDelta(3, 10, professionIcon); } public int getProfessionIcon() { - return professionIcon; + return play3.getProfessionIcon(); } public void addDraftSchematic(String schematic) { - draftSchemList.add(schematic); - draftSchemList.sendDeltaMessage(this); + play9.addDraftSchematic(schematic, this); } - public Integer getExperiencePoints(String xpType) { - return experience.get(xpType); + public int getExperiencePoints(String xpType) { + return play8.getExperiencePoints(xpType); } public void setExperiencePoints(String xpType, int experiencePoints) { - experience.put(xpType, experiencePoints); - experience.sendDeltaMessage(this); + play8.setExperiencePoints(xpType, experiencePoints, this); + } + + public void addExperiencePoints(String xpType, int experiencePoints) { + play8.addExperiencePoints(xpType, experiencePoints, this); + } + + public int getStartPlayTime() { + return startPlayTime; + } + + public void setStartPlayTime(int startPlayTime) { + this.startPlayTime = startPlayTime; } public void createChildrenObjects(Player target) { @@ -479,113 +388,45 @@ public class PlayerObject extends IntangibleObject { public void createBaseline3(Player target, BaselineBuilder bb) { super.createBaseline3(target, bb); // 5 variables - bb.addObject(flagsList); // 4 flags -- 5 - bb.addObject(profileFlags); // 4 flags -- 6 - bb.addAscii(title); // 7 - bb.addInt(bornDate); // Born Date -- 4001 = 12/15/2011 || Number of days after 12/31/2000 -- 8 - bb.addInt(playTime); // 9 - bb.addInt(professionIcon); // 10 - bb.addAscii(profession); // 11 - bb.addInt(gcwPoints); // 12 - bb.addInt(pvpKills); // 13 - bb.addLong(lifetimeGcwPoints); // 14 - bb.addInt(lifetimePvpKills); // 15 - bb.addObject(collectionBadges); // 16 - bb.addObject(collectionBadges2); // 17 - bb.addBoolean(showBackpack); // 18 - bb.addBoolean(showHelmet); // 19 - for (int i = 0; i < 64; i++) - bb.addByte(0); - - bb.incrementOperandCount(15); + play3.createBaseline3(target, bb); } public void createBaseline6(Player target, BaselineBuilder bb) { super.createBaseline6(target, bb); // 2 variables - bb.addByte(adminTag); // Admin Tag (0 = none, 1 = CSR, 2 = Developer, 3 = Warden, 4 = QA) -- 2 - bb.addInt(currentRank); // 3 - bb.addFloat(rankProgress); // 4 - bb.addInt(highestImperialRank); // 5 - bb.addInt(highestRebelRank); // 6 - bb.addInt(gcwNextUpdate); // 7 - bb.addAscii(home); // 8 - bb.addBoolean(citizen); // 9 - bb.addAscii(""); // City Region Defender 'region' -- 10 - bb.addBoolean(false); // City Region Defender byte #1 - bb.addBoolean(false); // City Region Defender byte #2 - bb.addAscii(""); // Guild Region Defender 'region' -- 11 - bb.addBoolean(false); // Guild Region Defender byte #1 - bb.addBoolean(false); // Guild Region Defender byte #2 - bb.addLong(0); // General? -- 12 - bb.addAscii(""); // 13 - bb.addInt(0); // Citizen Rank Title? 6 bytes -- 14 - bb.addInt(0); // Environment Flags Override -- 15 - bb.addAscii(""); // Vehicle Attack Command -- 16 - - bb.incrementOperandCount(15); + play6.createBaseline6(target, bb); } public void createBaseline8(Player target, BaselineBuilder bb) { super.createBaseline8(target, bb); // 0 variables - bb.addObject(experience); // 0 - bb.addObject(waypoints); // 1 - bb.addInt(100); // Current Force Power -- 2 - bb.addInt(100); // Max Force Power -- 3 - bb.addInt(0); // Completed Quests (List) -- 4 - bb.addInt(0); - bb.addInt(0); // Active Quests (List) -- 5 - bb.addInt(0); - bb.addInt(activeQuest); // Current Quest -- 6 - bb.addObject(quests); // 7 - bb.addAscii(profWheelPosition); // 8 - - bb.incrementOperandCount(9); + play8.createBaseline8(target, bb); } public void createBaseline9(Player target, BaselineBuilder bb) { super.createBaseline9(target, bb); // 0 variables - bb.addInt(experimentFlag); // 0 - bb.addInt(craftingStage); // 1 - bb.addLong(nearbyCraftStation); // 2 - bb.addObject(draftSchemList); // 3 - bb.addInt(0); // Might or might not be a list, two ints that are part of the same delta -- 4 - bb.addInt(0); - bb.addInt(experimentPoints); // 5 - bb.addInt(0); // Accomplishment Counter - Pre-NGE? -- 6 - bb.addObject(friendsList); // 7 - bb.addObject(ignoreList); // 8 - bb.addInt(languageId); // 9 - bb.addInt(0); // Current Stomach -- 10 - bb.addInt(100); // Max Stomach -- 11 - bb.addInt(0); // Current Drink -- 12 - bb.addInt(100); // Max Drink -- 13 - bb.addInt(0); // Current Consumable -- 14 - bb.addInt(100); // Max Consumable -- 15 - bb.addInt(0); // Group Waypoints -- 16 - bb.addInt(0); - bb.addObject(defenders); // 17 - bb.addInt(killMeter); // 18 - bb.addInt(0); // Unk -- 19 - bb.addLong(petId); // 20 - bb.addObject(petAbilities); // 21 - bb.addObject(activePetAbilities); // 22 - bb.addByte(0); // Unk sometimes 0x01 or 0x02 -- 23 - bb.addInt(0); // Unk sometimes 4 -- 24 - bb.addLong(0); // Unk Bitmask starts with 0x20 ends with 0x40 -- 25 - bb.addLong(0); // Unk Changes from 6 bytes to 9 -- 26 - bb.addByte(0); // Unk Changes from 6 bytes to 9 -- 27 - bb.addLong(0); // Unk sometimes 856 -- 28 - bb.addLong(0); // Unk sometimes 8559 -- 29 - bb.addInt(0); // Residence Time? Seen as Saturday 28th May 2011 -- 30 - - bb.incrementOperandCount(31); + play9.createBaseline9(target, bb); } - public int getStartPlayTime() { - return startPlayTime; + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + play3.save(stream); + play6.save(stream); + play8.save(stream); + play9.save(stream); + stream.addInt(startPlayTime); + stream.addUnicode(biography); } - - public void setStartPlayTime(int startPlayTime) { - this.startPlayTime = startPlayTime; + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + play3.read(stream); + play6.read(stream); + play8.read(stream); + play9.read(stream); + startPlayTime = stream.getInt(); + biography = stream.getUnicode(); } } diff --git a/src/resources/objects/player/PlayerObjectPrivate.java b/src/resources/objects/player/PlayerObjectPrivate.java new file mode 100644 index 000000000..221c2101f --- /dev/null +++ b/src/resources/objects/player/PlayerObjectPrivate.java @@ -0,0 +1,190 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.objects.player; + +import network.packets.swg.zone.chat.ChatSystemMessage; +import resources.collections.SWGMap; +import resources.network.BaselineBuilder; +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import resources.objects.waypoint.WaypointObject; +import resources.persistable.Persistable; +import resources.persistable.SWGObjectFactory; +import resources.player.Player; +import utilities.Encoder.StringType; + +class PlayerObjectPrivate implements Persistable { + + private SWGMap experience = new SWGMap<>(8, 0, StringType.ASCII); + private SWGMap waypoints = new SWGMap<>(8, 1); + private int guildRankTitle = 0; + private int activeQuest = 0; + private SWGMap quests = new SWGMap<>(8, 7); + private String profWheelPosition = ""; + + public PlayerObjectPrivate() { + + } + + public void addWaypoint(WaypointObject waypoint, SWGObject target) { + synchronized(waypoints) { + if (waypoints.size() < 250) { + waypoints.put(waypoint.getObjectId(), waypoint); + waypoints.sendDeltaMessage(target); + } else { + target.sendSelf(new ChatSystemMessage(ChatSystemMessage.SystemChatType.SCREEN_AND_CHAT, "@base_player:too_many_waypoints")); + } + } + } + + public WaypointObject getWaypoint(long objId) { + synchronized (waypoints) { + return waypoints.get(objId); + } + } + + public SWGMap getWaypoints() { + synchronized (waypoints) { + return waypoints; + } + } + + public void updateWaypoint(WaypointObject obj, SWGObject target) { + synchronized (waypoints) { + waypoints.update(obj.getObjectId(), target); + } + } + + public void removeWaypoint(long objId, SWGObject target) { + synchronized (waypoints) { + waypoints.remove(objId); + waypoints.sendDeltaMessage(target); + } + } + + public int getGuildRankTitle() { + return guildRankTitle; + } + + public int getActiveQuest() { + return activeQuest; + } + + public String getProfWheelPosition() { + return profWheelPosition; + } + + public void setGuildRankTitle(int guildRankTitle) { + this.guildRankTitle = guildRankTitle; + } + + public void setActiveQuest(int activeQuest) { + this.activeQuest = activeQuest; + } + + public void setProfWheelPosition(String profWheelPosition) { + this.profWheelPosition = profWheelPosition; + } + + public int getExperiencePoints(String xpType) { + synchronized (experience) { + Integer i = experience.get(xpType); + if (i == null) + return 0; + return i; + } + } + + public void setExperiencePoints(String xpType, int experiencePoints, SWGObject target) { + synchronized (experience) { + experience.put(xpType, experiencePoints); + experience.sendDeltaMessage(target); + } + } + + public void addExperiencePoints(String xpType, int experiencePoints, SWGObject target) { + synchronized (experience) { + experience.put(xpType, getExperiencePoints(xpType) + experiencePoints); + experience.sendDeltaMessage(target); + } + } + + public void createBaseline8(Player target, BaselineBuilder bb) { + bb.addObject(experience); // 0 + bb.addObject(waypoints); // 1 + bb.addInt(100); // Current Force Power -- 2 + bb.addInt(100); // Max Force Power -- 3 + bb.addInt(0); // Completed Quests (List) -- 4 + bb.addInt(0); + bb.addInt(0); // Active Quests (List) -- 5 + bb.addInt(0); + bb.addInt(activeQuest); // Current Quest -- 6 + bb.addObject(quests); // 7 + bb.addAscii(profWheelPosition); // 8 + + bb.incrementOperandCount(9); + } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addAscii(profWheelPosition); + stream.addInt(guildRankTitle); + stream.addInt(activeQuest); + synchronized (experience) { + stream.addMap(experience, (e) -> { + stream.addAscii(e.getKey()); + stream.addInt(e.getValue()); + }); + } + synchronized (quests) { + stream.addMap(quests, (e) -> { + stream.addInt(e.getKey()); + stream.addInt(e.getValue()); + }); + } + synchronized (waypoints) { + stream.addMap(waypoints, (e) -> { + stream.addLong(e.getKey()); + SWGObjectFactory.save(e.getValue(), stream); + }); + } + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + profWheelPosition = stream.getAscii(); + guildRankTitle = stream.getInt(); + activeQuest = stream.getInt(); + stream.getList((i) -> experience.put(stream.getAscii(), stream.getInt())); + stream.getList((i) -> quests.put(stream.getInt(), stream.getInt())); + stream.getList((i) -> waypoints.put(stream.getLong(), (WaypointObject) SWGObjectFactory.create(stream))); + } + +} diff --git a/src/resources/objects/player/PlayerObjectPrivateNP.java b/src/resources/objects/player/PlayerObjectPrivateNP.java new file mode 100644 index 000000000..b79579968 --- /dev/null +++ b/src/resources/objects/player/PlayerObjectPrivateNP.java @@ -0,0 +1,170 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.objects.player; + +import java.util.List; + +import resources.collections.SWGList; +import resources.collections.SWGSet; +import resources.network.BaselineBuilder; +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import resources.persistable.Persistable; +import resources.player.Player; +import utilities.Encoder.StringType; + +class PlayerObjectPrivateNP implements Persistable { + + private int experimentFlag = 0; + private int craftingStage = 0; + private long nearbyCraftStation = 0; + private SWGList draftSchemList = new SWGList<>(9, 3, StringType.ASCII); + private int experimentPoints = 0; + private SWGList friendsList = new SWGList<>(9, 7, StringType.ASCII); + private SWGList ignoreList = new SWGList<>(9, 8, StringType.ASCII); + private int languageId = 0; + private SWGSet defenders = new SWGSet<>(9, 17); + private int killMeter = 0; + private long petId = 0; + private SWGList petAbilities = new SWGList<>(9, 21); + private SWGList activePetAbilities = new SWGList<>(9, 22); + + public PlayerObjectPrivateNP() { + + } + + public void removeFriend(String friend, SWGObject target) { + synchronized (friendsList) { + friendsList.remove(friend); + } + friendsList.sendDeltaMessage(target); + } + + public void addFriend(String friend, SWGObject target) { + synchronized (friendsList) { + friendsList.add(friend); + } + friendsList.sendDeltaMessage(target); + } + + public List getFriendsList() { + return friendsList; + } + + public void addIgnored(String ignored, SWGObject target) { + synchronized (ignoreList) { + ignoreList.add(ignored); + } + ignoreList.sendDeltaMessage(target); + } + + public void removeIgnored(String ignored, SWGObject target) { + synchronized (ignoreList) { + ignoreList.remove(ignored); + } + ignoreList.sendDeltaMessage(target); + } + + public boolean isIgnored(String target) { + return ignoreList.contains(target); + } + + public List getIgnoreList() { + return ignoreList; + } + + public void addDraftSchematic(String schematic, SWGObject target) { + draftSchemList.add(schematic); + draftSchemList.sendDeltaMessage(target); + } + + public void createBaseline9(Player target, BaselineBuilder bb) { + bb.addInt(experimentFlag); // 0 + bb.addInt(craftingStage); // 1 + bb.addLong(nearbyCraftStation); // 2 + bb.addObject(draftSchemList); // 3 + bb.addInt(0); // Might or might not be a list, two ints that are part of the same delta -- 4 + bb.addInt(0); + bb.addInt(experimentPoints); // 5 + bb.addInt(0); // Accomplishment Counter - Pre-NGE? -- 6 + bb.addObject(friendsList); // 7 + bb.addObject(ignoreList); // 8 + bb.addInt(languageId); // 9 + bb.addInt(0); // Current Stomach -- 10 + bb.addInt(100); // Max Stomach -- 11 + bb.addInt(0); // Current Drink -- 12 + bb.addInt(100); // Max Drink -- 13 + bb.addInt(0); // Current Consumable -- 14 + bb.addInt(100); // Max Consumable -- 15 + bb.addInt(0); // Group Waypoints -- 16 + bb.addInt(0); + bb.addObject(defenders); // 17 + bb.addInt(killMeter); // 18 + bb.addInt(0); // Unk -- 19 + bb.addLong(petId); // 20 + bb.addObject(petAbilities); // 21 + bb.addObject(activePetAbilities); // 22 + bb.addByte(0); // Unk sometimes 0x01 or 0x02 -- 23 + bb.addInt(0); // Unk sometimes 4 -- 24 + bb.addLong(0); // Unk Bitmask starts with 0x20 ends with 0x40 -- 25 + bb.addLong(0); // Unk Changes from 6 bytes to 9 -- 26 + bb.addByte(0); // Unk Changes from 6 bytes to 9 -- 27 + bb.addLong(0); // Unk sometimes 856 -- 28 + bb.addLong(0); // Unk sometimes 8559 -- 29 + bb.addInt(0); // Residence Time? Seen as Saturday 28th May 2011 -- 30 + + bb.incrementOperandCount(31); + } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addInt(languageId); + stream.addInt(killMeter); + stream.addLong(petId); + stream.addList(draftSchemList, (s) -> stream.addAscii(s)); + stream.addList(friendsList, (s) -> stream.addAscii(s)); + stream.addList(ignoreList, (s) -> stream.addAscii(s)); + stream.addList(petAbilities, (s) -> stream.addAscii(s)); + stream.addList(activePetAbilities, (s) -> stream.addAscii(s)); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + languageId = stream.getInt(); + killMeter = stream.getInt(); + petId = stream.getLong(); + stream.getList((i) -> draftSchemList.add(stream.getAscii())); + stream.getList((i) -> friendsList.add(stream.getAscii())); + stream.getList((i) -> ignoreList.add(stream.getAscii())); + stream.getList((i) -> petAbilities.add(stream.getAscii())); + stream.getList((i) -> activePetAbilities.add(stream.getAscii())); + } + +} diff --git a/src/resources/objects/player/PlayerObjectShared.java b/src/resources/objects/player/PlayerObjectShared.java new file mode 100644 index 000000000..9a7609548 --- /dev/null +++ b/src/resources/objects/player/PlayerObjectShared.java @@ -0,0 +1,266 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.objects.player; + +import java.util.BitSet; + +import resources.collections.SWGBitSet; +import resources.collections.SWGFlag; +import resources.network.BaselineBuilder; +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import resources.persistable.Persistable; +import resources.player.Player; +import resources.player.PlayerFlags; +import utilities.MathUtils; + +class PlayerObjectShared implements Persistable { + + private SWGFlag flagsList = new SWGFlag(3, 5); + private SWGFlag profileFlags = new SWGFlag(3, 6); + private String title = ""; + private int bornDate = 0; + private int playTime = 0; + private int professionIcon = 0; + private String profession = ""; + private int gcwPoints = 0; + private int pvpKills = 0; + private long lifetimeGcwPoints = 0; + private int lifetimePvpKills = 0; + private SWGBitSet collectionBadges = new SWGBitSet(3, 16); + private SWGBitSet collectionBadges2 = new SWGBitSet(3, 17); + private boolean showHelmet = true; + private boolean showBackpack = true; + + public PlayerObjectShared() { + + } + + public SWGFlag getFlagsList() { + return flagsList; + } + + public SWGFlag getProfileFlags() { + return profileFlags; + } + + public String getTitle() { + return title; + } + + public int getBornDate() { + return bornDate; + } + + public int getPlayTime() { + return playTime; + } + + public int getProfessionIcon() { + return professionIcon; + } + + public String getProfession() { + return profession; + } + + public int getGcwPoints() { + return gcwPoints; + } + + public int getPvpKills() { + return pvpKills; + } + + public long getLifetimeGcwPoints() { + return lifetimeGcwPoints; + } + + public int getLifetimePvpKills() { + return lifetimePvpKills; + } + + public byte[] getCollectionBadges() { + return collectionBadges.toByteArray(); + } + + public boolean isShowHelmet() { + return showHelmet; + } + + public boolean isShowBackpack() { + return showBackpack; + } + + public void setFlagsList(SWGFlag flagsList) { + this.flagsList = flagsList; + } + + public void setProfileFlags(SWGFlag profileFlags) { + this.profileFlags = profileFlags; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setBornDate(int bornDate) { + this.bornDate = bornDate; + } + + public void setPlayTime(int playTime) { + this.playTime = playTime; + } + + public void setProfessionIcon(int professionIcon) { + this.professionIcon = professionIcon; + } + + public void setProfession(String profession) { + this.profession = profession; + } + + public void setBornDate(int year, int month, int day) { + this.bornDate = MathUtils.numberDaysSince(year, month, day, 2000, 12, 31); + } + + public void setGcwPoints(int gcwPoints) { + this.gcwPoints = gcwPoints; + } + + public void setPvpKills(int pvpKills) { + this.pvpKills = pvpKills; + } + + public void setLifetimeGcwPoints(long lifetimeGcwPoints) { + this.lifetimeGcwPoints = lifetimeGcwPoints; + } + + public void setLifetimePvpKills(int lifetimePvpKills) { + this.lifetimePvpKills = lifetimePvpKills; + } + + public void setCollectionBadges(byte [] collection, SWGObject target) { + this.collectionBadges.clear(); + this.collectionBadges.or(BitSet.valueOf(collection)); + collectionBadges.sendDeltaMessage(target); + } + + public void setShowHelmet(boolean showHelmet) { + this.showHelmet = showHelmet; + } + + public void setShowBackpack(boolean showBackpack) { + this.showBackpack = showBackpack; + } + + public void setFlagBitmask(SWGObject target, PlayerFlags ... flags) { + boolean changed = false; + for (PlayerFlags flag : flags) { + changed |= !flagsList.get(flag.getFlag()); + flagsList.set(flag.getFlag()); + } + if (changed) + flagsList.sendDeltaMessage(target); + } + + public void clearFlagBitmask(SWGObject target, PlayerFlags ... flags) { + boolean changed = false; + for (PlayerFlags flag : flags) { + changed |= flagsList.get(flag.getFlag()); + flagsList.clear(flag.getFlag()); + } + if (changed) + flagsList.sendDeltaMessage(target); + } + + public void toggleFlag(SWGObject target, PlayerFlags ... flags) { + for (PlayerFlags flag : flags) + flagsList.flip(flag.getFlag()); + flagsList.sendDeltaMessage(target); + } + + public void createBaseline3(Player target, BaselineBuilder bb) { + bb.addObject(flagsList); // 4 flags -- 5 + bb.addObject(profileFlags); // 4 flags -- 6 + bb.addAscii(title); // 7 + bb.addInt(bornDate); // Born Date -- 4001 = 12/15/2011 || Number of days after 12/31/2000 -- 8 + bb.addInt(playTime); // 9 + bb.addInt(professionIcon); // 10 + bb.addAscii(profession); // 11 + bb.addInt(gcwPoints); // 12 + bb.addInt(pvpKills); // 13 + bb.addLong(lifetimeGcwPoints); // 14 + bb.addInt(lifetimePvpKills); // 15 + bb.addObject(collectionBadges); // 16 + bb.addObject(collectionBadges2); // 17 + bb.addBoolean(showBackpack); // 18 + bb.addBoolean(showHelmet); // 19 + + bb.incrementOperandCount(15); + } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + flagsList.save(stream); + profileFlags.save(stream); + collectionBadges.save(stream); + stream.addAscii(title); + stream.addAscii(profession); + stream.addInt(bornDate); + stream.addInt(playTime); + stream.addInt(professionIcon); + stream.addInt(gcwPoints); + stream.addInt(pvpKills); + stream.addInt(lifetimePvpKills); + stream.addLong(lifetimeGcwPoints); + stream.addBoolean(showBackpack); + stream.addBoolean(showHelmet); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + flagsList.read(stream); + profileFlags.read(stream); + collectionBadges.read(stream); + title = stream.getAscii(); + profession = stream.getAscii(); + bornDate = stream.getInt(); + playTime = stream.getInt(); + professionIcon = stream.getInt(); + gcwPoints = stream.getInt(); + pvpKills = stream.getInt(); + lifetimePvpKills = stream.getInt(); + lifetimeGcwPoints = stream.getLong(); + showBackpack = stream.getBoolean(); + showHelmet = stream.getBoolean(); + } + +} diff --git a/src/resources/objects/player/PlayerObjectSharedNP.java b/src/resources/objects/player/PlayerObjectSharedNP.java new file mode 100644 index 000000000..b48f0ccfc --- /dev/null +++ b/src/resources/objects/player/PlayerObjectSharedNP.java @@ -0,0 +1,175 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.objects.player; + +import resources.network.BaselineBuilder; +import resources.network.NetBufferStream; +import resources.persistable.Persistable; +import resources.player.AccessLevel; +import resources.player.Player; + +class PlayerObjectSharedNP implements Persistable { + + private int adminTag = 0; + private int currentRank = 0; + private float rankProgress = 0; + private int highestRebelRank = 0; + private int highestImperialRank = 0; + private int gcwNextUpdate = 0; + private String home = ""; + private boolean citizen = false; + + public PlayerObjectSharedNP() { + + } + + public int getAdminTag() { + return adminTag; + } + + public void setAdminTag(AccessLevel access) { + switch (access) { + case PLAYER: adminTag = 0; break; + case CSR: adminTag = 1; break; + case DEV: adminTag = 2; break; + case WARDEN: adminTag = 3; break; + case QA: adminTag = 4; break; + } + } + + public void setAdminTag(int tag) { + this.adminTag = tag; + } + + public int getCurrentRank() { + return currentRank; + } + + public void setCurrentRank(int currentRank) { + this.currentRank = currentRank; + } + + public float getRankProgress() { + return rankProgress; + } + + public void setRankProgress(float rankProgress) { + this.rankProgress = rankProgress; + } + + public int getHighestRebelRank() { + return highestRebelRank; + } + + public void setHighestRebelRank(int highestRebelRank) { + this.highestRebelRank = highestRebelRank; + } + + public int getHighestImperialRank() { + return highestImperialRank; + } + + public void setHighestImperialRank(int highestImperialRank) { + this.highestImperialRank = highestImperialRank; + } + + public int getGcwNextUpdate() { + return gcwNextUpdate; + } + + public void setGcwNextUpdate(int gcwNextUpdate) { + this.gcwNextUpdate = gcwNextUpdate; + } + + public String getHome() { + return home; + } + + public void setHome(String home) { + this.home = home; + } + + public boolean isCitizen() { + return citizen; + } + + public void setCitizen(boolean citizen) { + this.citizen = citizen; + } + + public void createBaseline6(Player target, BaselineBuilder bb) { + bb.addByte(adminTag); // Admin Tag (0 = none, 1 = CSR, 2 = Developer, 3 = Warden, 4 = QA) -- 2 + bb.addInt(currentRank); // 3 + bb.addFloat(rankProgress); // 4 + bb.addInt(highestImperialRank); // 5 + bb.addInt(highestRebelRank); // 6 + bb.addInt(gcwNextUpdate); // 7 + bb.addAscii(home); // 8 + bb.addBoolean(citizen); // 9 + bb.addAscii(""); // City Region Defender 'region' -- 10 + bb.addBoolean(false); // City Region Defender byte #1 + bb.addBoolean(false); // City Region Defender byte #2 + bb.addAscii(""); // Guild Region Defender 'region' -- 11 + bb.addBoolean(false); // Guild Region Defender byte #1 + bb.addBoolean(false); // Guild Region Defender byte #2 + bb.addLong(0); // General? -- 12 + bb.addAscii(""); // 13 + bb.addInt(0); // Citizen Rank Title? 6 bytes -- 14 + bb.addInt(0); // Environment Flags Override -- 15 + bb.addAscii(""); // Vehicle Attack Command -- 16 + + bb.incrementOperandCount(15); + } + + @Override + public void save(NetBufferStream stream) { + stream.addByte(0); + stream.addInt(adminTag); + stream.addInt(currentRank); + stream.addFloat(rankProgress); + stream.addInt(highestRebelRank); + stream.addInt(highestImperialRank); + stream.addInt(gcwNextUpdate); + stream.addAscii(home); + stream.addBoolean(citizen); + } + + @Override + public void read(NetBufferStream stream) { + stream.getByte(); + adminTag = stream.getInt(); + currentRank = stream.getInt(); + rankProgress = stream.getFloat(); + highestRebelRank = stream.getInt(); + highestImperialRank = stream.getInt(); + gcwNextUpdate = stream.getInt(); + home = stream.getAscii(); + citizen = stream.getBoolean(); + } + +} diff --git a/src/resources/objects/resource/ResourceContainerObject.java b/src/resources/objects/resource/ResourceContainerObject.java index aad4b1155..c16475891 100644 --- a/src/resources/objects/resource/ResourceContainerObject.java +++ b/src/resources/objects/resource/ResourceContainerObject.java @@ -29,13 +29,12 @@ package resources.objects.resource; import network.packets.swg.zone.baselines.Baseline.BaselineType; import resources.network.BaselineBuilder; +import resources.network.NetBufferStream; import resources.objects.tangible.TangibleObject; import resources.player.Player; public class ResourceContainerObject extends TangibleObject { - private static final long serialVersionUID = 1L; - private long resourceType = 0; private String resourceName = ""; private int quantity = 0; @@ -132,4 +131,37 @@ public class ResourceContainerObject extends TangibleObject { return hash; } + /* + private long resourceType = 0; + private String resourceName = ""; + private int quantity = 0; + private int maxQuantity = 0; + private String parentName = ""; + private String displayName = ""; + */ + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addInt(quantity); + stream.addInt(maxQuantity); + stream.addLong(resourceType); + stream.addAscii(parentName); + stream.addUnicode(resourceName); + stream.addUnicode(displayName); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + quantity = stream.getInt(); + maxQuantity = stream.getInt(); + resourceType = stream.getLong(); + parentName = stream.getAscii(); + resourceName = stream.getUnicode(); + displayName = stream.getUnicode(); + } + } diff --git a/src/resources/objects/ship/ShipObject.java b/src/resources/objects/ship/ShipObject.java index 48f96db92..f8e3c04e7 100644 --- a/src/resources/objects/ship/ShipObject.java +++ b/src/resources/objects/ship/ShipObject.java @@ -28,14 +28,25 @@ package resources.objects.ship; import network.packets.swg.zone.baselines.Baseline.BaselineType; +import resources.network.NetBufferStream; import resources.objects.tangible.TangibleObject; public class ShipObject extends TangibleObject { - private static final long serialVersionUID = 1L; - public ShipObject(long objectId) { super(objectId, BaselineType.SHIP); } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + } + } diff --git a/src/resources/objects/sound/SoundObject.java b/src/resources/objects/sound/SoundObject.java index 6569a615d..da7ddfc1f 100644 --- a/src/resources/objects/sound/SoundObject.java +++ b/src/resources/objects/sound/SoundObject.java @@ -27,14 +27,25 @@ ***********************************************************************************/ package resources.objects.sound; +import resources.network.NetBufferStream; import resources.objects.staticobject.StaticObject; public class SoundObject extends StaticObject { - private static final long serialVersionUID = 1L; - public SoundObject(long objectId) { super(objectId); } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + } + } diff --git a/src/resources/objects/staticobject/StaticObject.java b/src/resources/objects/staticobject/StaticObject.java index a577bc8ca..aac473fba 100644 --- a/src/resources/objects/staticobject/StaticObject.java +++ b/src/resources/objects/staticobject/StaticObject.java @@ -27,14 +27,25 @@ ***********************************************************************************/ package resources.objects.staticobject; +import resources.network.NetBufferStream; import resources.objects.creature.CreatureObject; public class StaticObject extends CreatureObject { - private static final long serialVersionUID = 1L; - public StaticObject(long objectId) { super(objectId); } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + } + } diff --git a/src/resources/objects/tangible/TangibleObject.java b/src/resources/objects/tangible/TangibleObject.java index a663cd214..764e2cc2f 100644 --- a/src/resources/objects/tangible/TangibleObject.java +++ b/src/resources/objects/tangible/TangibleObject.java @@ -41,6 +41,7 @@ import resources.collections.SWGMap; import resources.collections.SWGSet; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; import resources.player.Player; @@ -48,8 +49,6 @@ import utilities.Encoder.StringType; public class TangibleObject extends SWGObject { - private static final long serialVersionUID = 1L; - private byte [] appearanceData = new byte[0]; private int maxHitPoints = 1000; private int components = 0; @@ -315,5 +314,44 @@ public class TangibleObject extends SWGObject { new FactionIntent(this, FactionIntentType.FLAGUPDATE).broadcast(); } + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addArray(appearanceData); + stream.addInt(maxHitPoints); + stream.addInt(components); + stream.addBoolean(inCombat); + stream.addInt(condition); + stream.addInt(pvpFlags); + stream.addAscii(pvpStatus.name()); + stream.addAscii(pvpFaction.name()); + stream.addBoolean(visibleGmOnly); + stream.addArray(objectEffects); + stream.addInt(optionFlags); + stream.addMap(effectsMap, (e) -> { + stream.addAscii(e.getKey()); + stream.addAscii(e.getValue()); + }); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + appearanceData = stream.getArray(); + maxHitPoints = stream.getInt(); + components = stream.getInt(); + inCombat = stream.getBoolean(); + condition = stream.getInt(); + pvpFlags = stream.getInt(); + pvpStatus = PvpStatus.valueOf(stream.getAscii()); + pvpFaction = PvpFaction.valueOf(stream.getAscii()); + visibleGmOnly = stream.getBoolean(); + objectEffects = stream.getArray(); + optionFlags = stream.getInt(); + stream.getList((i) -> effectsMap.put(stream.getAscii(), stream.getAscii())); + } } \ No newline at end of file diff --git a/src/resources/objects/waypoint/WaypointObject.java b/src/resources/objects/waypoint/WaypointObject.java index 292d7a9c7..9fee6f3f7 100644 --- a/src/resources/objects/waypoint/WaypointObject.java +++ b/src/resources/objects/waypoint/WaypointObject.java @@ -33,14 +33,13 @@ import resources.Location; import resources.Terrain; import resources.encodables.OutOfBandData; import resources.encodables.OutOfBandPackage; +import resources.network.NetBufferStream; import resources.objects.intangible.IntangibleObject; import resources.player.Player; import java.nio.ByteBuffer; public class WaypointObject extends IntangibleObject implements OutOfBandData { - - private static final long serialVersionUID = 1L; private long cellId; private String name = "New Waypoint"; @@ -116,6 +115,26 @@ public class WaypointObject extends IntangibleObject implements OutOfBandData { active = Packet.getBoolean(data); setLocation(loc); } + + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addBoolean(active); + stream.addLong(cellId); + stream.addAscii(name); + stream.addAscii(color.name()); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + active = stream.getBoolean(); + cellId = stream.getLong(); + name = stream.getAscii(); + color = WaypointColor.valueOf(stream.getAscii()); + } @Override public OutOfBandPackage.Type getOobType() { diff --git a/src/resources/objects/weapon/WeaponObject.java b/src/resources/objects/weapon/WeaponObject.java index bc3c81474..6859790f7 100644 --- a/src/resources/objects/weapon/WeaponObject.java +++ b/src/resources/objects/weapon/WeaponObject.java @@ -30,13 +30,12 @@ package resources.objects.weapon; import network.packets.swg.zone.baselines.Baseline.BaselineType; import resources.network.BaselineBuilder; import resources.network.NetBuffer; +import resources.network.NetBufferStream; import resources.objects.tangible.TangibleObject; import resources.player.Player; public class WeaponObject extends TangibleObject { - private static final long serialVersionUID = 1L; - private float attackSpeed = 0.5f; private float maxRange = 5f; private WeaponType type = WeaponType.UNARMED; @@ -124,4 +123,22 @@ public class WeaponObject extends TangibleObject { type = WeaponType.getWeaponType(buffer.getInt()); } + @Override + public void save(NetBufferStream stream) { + super.save(stream); + stream.addByte(0); + stream.addFloat(attackSpeed); + stream.addFloat(maxRange); + stream.addAscii(type.name()); + } + + @Override + public void read(NetBufferStream stream) { + super.read(stream); + stream.getByte(); + attackSpeed = stream.getFloat(); + maxRange = stream.getFloat(); + type = WeaponType.valueOf(stream.getAscii()); + } + } diff --git a/src/resources/persistable/InputPersistenceStream.java b/src/resources/persistable/InputPersistenceStream.java new file mode 100644 index 000000000..ef37b6f1b --- /dev/null +++ b/src/resources/persistable/InputPersistenceStream.java @@ -0,0 +1,111 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import java.io.IOException; +import java.io.InputStream; + +import resources.network.NetBufferStream; + +public class InputPersistenceStream extends InputStream { + + private final InputStream is; + + public InputPersistenceStream(InputStream is) { + this.is = is; + } + + public int read() { + throw new UnsupportedOperationException("Unable to read raw data"); + } + + public int read(byte[] b) { + throw new UnsupportedOperationException("Unable to read raw data"); + } + + public int read(byte[] b, int off, int len) { + throw new UnsupportedOperationException("Unable to read raw data"); + } + + public T read(PersistableCreator creator) throws IOException { + int size = readInt(); + try (NetBufferStream stream = new NetBufferStream(size)) { + byte [] buffer = new byte[Math.min(size, 2048)]; + int pos = 0; + while (pos < size) { + int n = is.read(buffer, 0, Math.min(size-pos, buffer.length)); + if (n == -1) + break; + stream.write(buffer, 0, n); + pos += n; + } + stream.position(0); + return creator.create(stream); + } + } + + public long skip(long n) throws IOException { + return is.skip(n); + } + + public int available() throws IOException { + return is.available(); + } + + public void close() throws IOException { + is.close(); + } + + public void mark(int readlimit) { + is.mark(readlimit); + } + + public void reset() throws IOException { + is.reset(); + } + + public boolean markSupported() { + return is.markSupported(); + } + + private int readInt() throws IOException { + int ret = 0; + int b; + for (int i = 0; i < 4; i++) { + b = is.read(); + if (b != -1) + ret |= b << (i * 8); + } + return ret; + } + + public static interface PersistableCreator { + T create(NetBufferStream stream); + } + +} diff --git a/src/resources/persistable/OutputPersistenceStream.java b/src/resources/persistable/OutputPersistenceStream.java new file mode 100644 index 000000000..60ad7d1f6 --- /dev/null +++ b/src/resources/persistable/OutputPersistenceStream.java @@ -0,0 +1,98 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import java.io.Closeable; +import java.io.IOException; +import java.io.OutputStream; + +import resources.network.NetBufferStream; + +public class OutputPersistenceStream extends OutputStream implements Closeable { + + private final OutputStream os; + + public OutputPersistenceStream(OutputStream os) { + this.os = os; + } + + @Override + public void write(int b) { + throw new UnsupportedOperationException("Unable to write raw data"); + } + + @Override + public void write(byte[] b) { + throw new UnsupportedOperationException("Unable to write raw data"); + } + + @Override + public void write(byte[] b, int off, int len) { + throw new UnsupportedOperationException("Unable to write raw data"); + } + + public void write(Persistable p) throws IOException { + NetBufferStream buffer = new NetBufferStream(); + p.save(buffer); + writeInt(buffer.size()); + os.write(buffer.array(), 0, buffer.size()); + flush(); + buffer.close(); + } + + public void write(T obj, PersistableSaver saver) throws IOException { + NetBufferStream buffer = new NetBufferStream(); + saver.save(obj, buffer); + writeInt(buffer.size()); + os.write(buffer.array(), 0, buffer.size()); + flush(); + buffer.close(); + } + + @Override + public void flush() throws IOException { + os.flush(); + } + + @Override + public void close() throws IOException { + os.close(); + } + + private void writeInt(int i) throws IOException { + os.write(i >>> 0); + os.write(i >>> 8); + os.write(i >>> 16); + os.write(i >>> 24); + } + + public static interface PersistableSaver { + void save(T obj, NetBufferStream stream); + } + +} diff --git a/src/resources/persistable/Persistable.java b/src/resources/persistable/Persistable.java new file mode 100644 index 000000000..c4836d0bd --- /dev/null +++ b/src/resources/persistable/Persistable.java @@ -0,0 +1,35 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import resources.network.NetBufferStream; + +public interface Persistable { + void save(NetBufferStream stream); + void read(NetBufferStream stream); +} diff --git a/src/resources/persistable/SWGObjectFactory.java b/src/resources/persistable/SWGObjectFactory.java new file mode 100644 index 000000000..7dabdf502 --- /dev/null +++ b/src/resources/persistable/SWGObjectFactory.java @@ -0,0 +1,50 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import resources.network.NetBufferStream; +import resources.objects.SWGObject; +import services.objects.ObjectCreator; + +public class SWGObjectFactory { + + public static void save(SWGObject obj, NetBufferStream stream) { + stream.addLong(obj.getObjectId()); + stream.addAscii(obj.getTemplate()); + obj.save(stream); + } + + public static SWGObject create(NetBufferStream stream) { + long objectId = stream.getLong(); + String template = stream.getAscii(); + SWGObject obj = ObjectCreator.createObjectFromTemplate(objectId, template); + obj.read(stream); + return obj; + } + +} diff --git a/src/resources/server_info/CachedObjectDatabase.java b/src/resources/server_info/CachedObjectDatabase.java index cf1ddb57f..34c743969 100644 --- a/src/resources/server_info/CachedObjectDatabase.java +++ b/src/resources/server_info/CachedObjectDatabase.java @@ -27,55 +27,42 @@ ***********************************************************************************/ package resources.server_info; -import java.io.EOFException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; +import java.util.HashSet; +import java.util.Set; -public class CachedObjectDatabase extends ObjectDatabase { +import resources.persistable.InputPersistenceStream; +import resources.persistable.InputPersistenceStream.PersistableCreator; +import resources.persistable.OutputPersistenceStream; +import resources.persistable.OutputPersistenceStream.PersistableSaver; +import resources.persistable.Persistable; + +public class CachedObjectDatabase extends ObjectDatabase { - private final Map objects; + private final PersistableCreator creator; + private final PersistableSaver saver; + private final Set objects; private boolean loaded; - public CachedObjectDatabase(String filename) { + public CachedObjectDatabase(String filename, PersistableCreator creator, PersistableSaver saver) { super(filename); - objects = new HashMap(); + this.creator = creator; + this.saver = saver; + objects = new HashSet<>(); loaded = false; } - public synchronized V put(String key, V value) { - return put(hash(key), value); - } - - public synchronized V put(long key, V value) { + public synchronized boolean add(V value) { synchronized (objects) { - return objects.put(key, value); + return objects.add(value); } } - public synchronized V get(String key) { - return get(hash(key)); - } - - public synchronized V get(long key) { + public synchronized boolean remove(V obj) { synchronized (objects) { - return objects.get(key); - } - } - - public synchronized V remove(String key) { - return get(hash(key)); - } - - public synchronized V remove(long key) { - synchronized (objects) { - return objects.remove(key); + return objects.remove(obj); } } @@ -85,105 +72,70 @@ public class CachedObjectDatabase extends ObjectDatabase } } - public synchronized boolean contains(long key) { + public synchronized boolean contains(V obj) { synchronized (objects) { - return objects.containsKey(key); + return objects.contains(obj); } } - public synchronized boolean contains(String key) { - return contains(hash(key)); - } - public synchronized boolean save() { if (!loaded) { Log.e("CachedObjectDatabase", "Not saving '" + getFile() + "', file not loaded yet!"); return false; } - ObjectOutputStream oos = null; - try { - oos = new ObjectOutputStream(new FileOutputStream(getFile())); + try (OutputPersistenceStream os = new OutputPersistenceStream(new FileOutputStream(getFile()))) { synchronized (objects) { - for (Entry e : objects.entrySet()) { - oos.writeLong(e.getKey()); - oos.writeObject(e.getValue()); - } + for (V obj : objects) + os.write(obj, saver); } - oos.close(); } catch (IOException e) { Log.e("CachedObjectDatabase", "Error while saving file. IOException: " + e.getMessage()); - e.printStackTrace(); + Log.e("CachedObjectDatabase", e); return false; - } finally { - if (oos != null) { - try { - oos.close(); - } catch (Exception e) { - Log.e("CachedObjectDatabase", "Failed to close stream while saving! " + e.getMessage()); - e.printStackTrace(); - } - } } return true; } - public synchronized void clearCache() { - synchronized (objects) { - objects.clear(); - loaded = false; - } - } - public synchronized boolean load() { if (!fileExists()) { Log.e("CachedObjectDatabase", "load() - file '%s' does not exist!", getFile()); + loaded = true; return false; } - ObjectInputStream ois = null; - try { - ois = new ObjectInputStream(new FileInputStream(getFile())); + try (InputPersistenceStream is = new InputPersistenceStream(new FileInputStream(getFile()))) { synchronized (objects) { - while (ois.available() >= 8) { - long key = ois.readLong(); - @SuppressWarnings("unchecked") - V val = (V) ois.readObject(); - objects.put(key, val); - } + while (is.available() > 0) + objects.add(is.read(creator)); + loaded = true; } - loaded = true; - } catch (EOFException e) { - loaded = true; - } catch (IOException | ClassNotFoundException | ClassCastException e) { - Log.e("CachedObjectDatabase", "load() - unable to load with error: %s - %s", e.getClass().getSimpleName(), e.getMessage()); + } catch (IOException e) { + Log.e("CachedObjectDatabase", "Error while loading file. IOException: " + e.getMessage()); + Log.e("CachedObjectDatabase", e); return false; - } finally { - if (ois != null) { - try { - ois.close(); - } catch (Exception e) { - Log.e("CachedObjectDatabase", "Failed to close stream when loading! " + e.getMessage()); - Log.e("CachedObjectDatabase", e); - } - } } return true; } + public synchronized void clearObjects() { + synchronized (objects) { + objects.clear(); + } + } + public synchronized void traverse(Traverser traverser) { synchronized (objects) { - for (V obj : objects.values()) + for (V obj : objects) traverser.process(obj); } } - private static final long hash(String string) { - long h = 1125899906842597L; - int len = string.length(); - - for (int i = 0; i < len; i++) { - h = 31*h + string.charAt(i); + public synchronized void traverseInterruptable(InterruptableTraverser traverser) { + synchronized (objects) { + for (V obj : objects) { + if (!traverser.process(obj)) + return; + } } - return h; } } diff --git a/src/resources/server_info/ObjectDatabase.java b/src/resources/server_info/ObjectDatabase.java index 6166de8b8..db336fb46 100644 --- a/src/resources/server_info/ObjectDatabase.java +++ b/src/resources/server_info/ObjectDatabase.java @@ -29,14 +29,14 @@ package resources.server_info; import java.io.File; import java.io.IOException; -import java.io.Serializable; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import resources.persistable.Persistable; import utilities.ThreadUtilities; -public abstract class ObjectDatabase { +public abstract class ObjectDatabase { private final File file; private final ScheduledExecutorService autosaveService; @@ -103,21 +103,21 @@ public abstract class ObjectDatabase { return file.isFile(); } - public abstract V put(String key, V value); - public abstract V put(long key, V value); - public abstract V get(String key); - public abstract V get(long key); - public abstract V remove(String key); - public abstract V remove(long key); + public abstract boolean add(V obj); + public abstract boolean remove(V obj); public abstract int size(); - public abstract boolean contains(long key); - public abstract boolean contains(String key); + public abstract boolean contains(V obj); public abstract boolean load(); public abstract boolean save(); public abstract void traverse(Traverser traverser); + public abstract void traverseInterruptable(InterruptableTraverser traverser); public interface Traverser { public void process(V element); } + public interface InterruptableTraverser { + public boolean process(V element); + } + } diff --git a/src/resources/server_info/UncachedObjectDatabase.java b/src/resources/server_info/UncachedObjectDatabase.java deleted file mode 100644 index 1ca1554be..000000000 --- a/src/resources/server_info/UncachedObjectDatabase.java +++ /dev/null @@ -1,390 +0,0 @@ -/*********************************************************************************** -* Copyright (c) 2015 /// 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 . * -* * -***********************************************************************************/ -package resources.server_info; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.EOFException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -public class UncachedObjectDatabase extends ObjectDatabase { - - private final Map objectIndex; - private final Map objects; - private boolean loaded; - - public UncachedObjectDatabase(String filename) { - super(filename); - objectIndex = new HashMap(); - objects = new HashMap(); - loaded = false; - loadPointers(); - } - - public synchronized V put(String key, V value) { - return put(hash(key), value); - } - - public synchronized V put(long key, V value) { - synchronized (objects) { - return objects.put(key, value); - } - } - - public synchronized V get(String key) { - return get(hash(key)); - } - - public synchronized V get(long key) { - V val = null; - synchronized (objects) { - val = objects.get(key); - } - if (val == null) - return getFromDB(key); - return val; - } - - public synchronized V remove(String key) { - return get(hash(key)); - } - - public synchronized V remove(long key) { - synchronized (objects) { - return objects.remove(key); - } - } - - public synchronized int size() { - synchronized (objectIndex) { - return objectIndex.size(); - } - } - - public synchronized boolean contains(long key) { - synchronized (objectIndex) { - return objectIndex.containsKey(key); - } - } - - public synchronized boolean contains(String key) { - return contains(hash(key)); - } - - public synchronized boolean save() { - if (!loaded) { - Log.e("UncachedObjectDatabase", "Not saving '" + getFile() + "', file not loaded yet!"); - return false; - } - DataOutputStream dos = null; - try { - File file = getFile(); - dos = new DataOutputStream(new FileOutputStream(file + ".tmp")); - loadCachedAndSave(dos, loadUncachedAndSave(dos, 0)); - moveFile(file+".tmp", file.getAbsolutePath()); - } catch (IOException e) { - Log.e("UncachedObjectDatabase", "Error while saving file. IOException: " + e.getMessage()); - e.printStackTrace(); - return false; - } finally { - safeClose(dos); - } - return true; - } - - public synchronized void clearCache() { - synchronized (objects) { - objects.clear(); - } - } - - public synchronized boolean load() { - return loadToCache(); - } - - public synchronized boolean loadToCache() { - if (!fileExists()) - return false; - DataInputStream dis = null; - try { - dis = new DataInputStream(new FileInputStream(getFile())); - synchronized (objects) { - while (dis.available() >= 12) { - long key = dis.readLong(); - int length = dis.readInt(); - if (!objects.containsKey(key)) { - objects.put(key, readObject(dis)); - } else { - if (dis.skip(length) != length) - throw new IOException("Failed to skip " + length + " bytes"); - } - } - } - dis.close(); - } catch (IOException | ClassNotFoundException | ClassCastException e) { - Log.e("UncachedObjectDatabase", "Unable to load cache with error: %s - %s", e.getClass().getSimpleName(), e.getMessage()); - return false; - } finally { - safeClose(dis); - } - return true; - } - - public synchronized void traverse(Traverser traverser) { - DataInputStream dis = null; - try { - save(); - dis = new DataInputStream(new FileInputStream(getFile())); - synchronized (objects) { - while (dis.available() >= 12) { - V v = objects.get(dis.readLong()); - int length = dis.readInt(); - if (v != null) { - if (dis.skip(length) != length) - throw new IOException("Failed to skip " + length + " bytes"); - } else - v = readObject(dis); - traverser.process(v); - } - } - } catch (IOException | ClassNotFoundException e) { - Log.e("UncachedObjectDatabase", "Unable to traverse with error: %s - %s", e.getClass().getSimpleName(), e.getMessage()); - } - safeClose(dis); - } - - public synchronized void traverseCache(Traverser traverser) { - synchronized (objects) { - for (V obj : objects.values()) - traverser.process(obj); - } - } - - private void moveFile(String source, String destination) throws IOException { - moveFile(source, destination, 4096); - } - - private void moveFile(String source, String destination, int bufferSize) throws IOException { - File sFile = new File(source); - File dFile = new File(destination); - - InputStream inStream = null; - OutputStream outStream = null; - try { - inStream = new FileInputStream(sFile); - outStream = new FileOutputStream(dFile); - - byte [] buffer = new byte[bufferSize]; - int length = 0; - while ((length = inStream.read(buffer)) > 0){ - outStream.write(buffer, 0, length); - } - } finally { - safeClose(inStream); - safeClose(outStream); - } - if (!sFile.delete()) - Log.e("UncachedObjectDatabase", "Failed to delete source file when moving %s -> %s", sFile, dFile); - } - - private V getFromDB(long key) { - long index = getObjectIndex(key); - if (index == -1) - return null; - V val = readObject(index); - synchronized (objects) { - objects.put(key, val); - } - return val; - } - - private long getObjectIndex(long key) { - synchronized (objectIndex) { - Long index = objectIndex.get(key); - if (index == null) - return -1; - return index; - } - } - - private V readObject(long index) { - FileInputStream fis = null; - V val = null; - try { - fis = new FileInputStream(getFile()); - if (fis.skip(index+12) != index+12) - throw new IOException("Failed to skip " + (index+12) + " bytes"); - val = readObject(fis); - } catch (IOException | ClassNotFoundException e) { - val = null; - } finally { - safeClose(fis); - } - return val; - } - - @SuppressWarnings("unchecked") - private V readObject(InputStream is) throws ClassNotFoundException, IOException { - return (V) new ObjectInputStream(is).readObject(); - } - - private byte [] writeObject(Object o) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - new ObjectOutputStream(bos).writeObject(o); - return bos.toByteArray(); - } - - private long writeObject(DataOutputStream dos, long key, byte [] data) throws IOException { - dos.writeLong(key); - dos.writeInt(data.length); - dos.write(data); - return 12 + data.length; - } - - private long loadUncachedAndSave(DataOutputStream dos, long index) { - DataInputStream dis = null; - try { - dis = new DataInputStream(new FileInputStream(getFile())); - while (dis.available() >= 12) { - long key = dis.readLong(); - int length = dis.readInt(); - synchronized (objects) { - if (objects.containsKey(key)) { - if (dis.skip(length) != length) - throw new IOException("Failed to skip " + length + " bytes"); - } else { - byte [] data = new byte[length]; - int len = 0; - while (len < length) { - len += dis.read(data, len, length-len); - } - index += writeObject(dos, key, data); - } - } - } - } catch (IOException e) { - - } finally { - safeClose(dis); - } - return index; - } - - private long loadCachedAndSave(DataOutputStream dos, long index) throws IOException { - synchronized (objectIndex) { - synchronized (objects) { - for (Entry e : objects.entrySet()) { - long key = e.getKey().longValue(); - objectIndex.put(key, index); - index += writeObject(dos, key, writeObject(e.getValue())); - } - } - } - return index; - } - - private boolean loadPointers() { - DataInputStream dis = null; - try { - dis = new DataInputStream(new FileInputStream(getFile())); - long index = 0; - while (index != -1) { - index = loadObject(dis, index); - } - dis.close(); - loaded = true; - } catch (EOFException e) { - loaded = true; - } catch (IOException e) { - return false; - } finally { - safeClose(dis); - } - return true; - } - - private long loadObject(DataInputStream dis, long index) throws IOException { - if (dis.available() < 12) - return -1; - long key = dis.readLong(); - int length = dis.readInt(); - if (length < 0) - return -1; - if (dis.skip(length) != length) - throw new IOException("Failed to skip " + length + " bytes"); - synchronized (objectIndex) { - objectIndex.put(key, index); - } - return index + 12 + length; - } - - private boolean safeClose(OutputStream os) { - if (os == null) - return false; - try { - os.close(); - } catch (IOException e) { - return false; - } - return true; - } - - private boolean safeClose(InputStream is) { - if (is == null) - return false; - try { - is.close(); - } catch (IOException e) { - return false; - } - return true; - } - - private static final long hash(String string) { - long h = 1125899906842597L; - int len = string.length(); - - for (int i = 0; i < len; i++) { - h = 31*h + string.charAt(i); - } - return h; - } - -} \ No newline at end of file diff --git a/src/services/chat/ChatMailService.java b/src/services/chat/ChatMailService.java index f09fd756a..7dd58654b 100644 --- a/src/services/chat/ChatMailService.java +++ b/src/services/chat/ChatMailService.java @@ -37,6 +37,7 @@ import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.Locale; +import java.util.concurrent.atomic.AtomicReference; import network.packets.Packet; import network.packets.swg.SWGPacket; @@ -69,7 +70,7 @@ public class ChatMailService extends Service { private int maxMailId; public ChatMailService() { - mails = new CachedObjectDatabase<>("odb/mails.db"); + mails = new CachedObjectDatabase<>("odb/mails.db", Mail::create, Mail::saveMail); chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db"); insertChatLog = chatLogs.prepareStatement("INSERT INTO chat_log VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); maxMailId = 1; @@ -179,7 +180,7 @@ public class ChatMailService extends Service { mail.setId(maxMailId++); mail.setTimestamp((int) (new Date().getTime() / 1000)); mail.setOutOfBandPackage(request.getOutOfBandPackage()); - mails.put(mail.getId(), mail); + mails.add(mail); if (recipient != null) { sendPersistentMessage(recipient, mail, MailFlagType.HEADER_ONLY, galaxy); @@ -203,14 +204,13 @@ public class ChatMailService extends Service { maxMailId++; mail.setTimestamp((int) (new Date().getTime() / 1000)); - mails.put(mail.getId(), mail); + mails.add(mail); sendPersistentMessage(recipient, mail, MailFlagType.HEADER_ONLY, intent.getGalaxy()); } private void handlePersistentMessageRequest(Player player, String galaxy, ChatRequestPersistentMessage request) { - Mail mail = mails.get(request.getMailId()); - + Mail mail = getMail(request.getMailId()); if (mail == null) return; @@ -221,6 +221,18 @@ public class ChatMailService extends Service { sendPersistentMessage(player, mail, MailFlagType.FULL_MESSAGE, galaxy); } + private Mail getMail(int id) { + AtomicReference ref = new AtomicReference<>(null); + mails.traverseInterruptable((m) -> { + if (m.getId() == id) { + ref.set(m); + return false; + } + return true; + }); + return ref.get(); + } + private void sendPersistentMessageHeaders(Player player) { if (player == null || player.getCreatureObject() == null) return; @@ -244,7 +256,7 @@ public class ChatMailService extends Service { PlayerObject ghost = receiver.getPlayerObject(); if (ghost.isIgnored(mail.getSender())) { - mails.remove(mail.getId()); + mails.remove(mail); return; } @@ -263,7 +275,7 @@ public class ChatMailService extends Service { } private void deletePersistentMessage(int mailId) { - mails.remove(mailId); + mails.remove(getMail(mailId)); } private void logChat(long sendId, String sendName, long recvId, String recvName, String subject, String message) { diff --git a/src/services/chat/ChatRoomService.java b/src/services/chat/ChatRoomService.java index dba42bd7f..1c5f107e5 100644 --- a/src/services/chat/ChatRoomService.java +++ b/src/services/chat/ChatRoomService.java @@ -104,7 +104,7 @@ public class ChatRoomService extends Service { private int maxChatRoomId; public ChatRoomService() { - database = new CachedObjectDatabase<>("odb/chat_rooms.db"); + database = new CachedObjectDatabase("odb/chat_rooms.db", ChatRoom::create, (r, s)->r.save(s)); roomMap = new ConcurrentHashMap<>(); messages = new ConcurrentHashMap<>(); chatLogs = RelationalServerFactory.getServerDatabase("chat/chat_log.db"); @@ -737,7 +737,7 @@ public class ChatRoomService extends Service { roomMap.put(id, room); if (persist) - database.put(id, room); + database.add(room); return room; } diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index c1a41a3c3..a0514ce81 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -38,7 +38,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import intents.object.DestroyObjectIntent; import intents.object.ObjectCreatedIntent; import intents.object.ObjectTeleportIntent; -import intents.player.DeleteCharacterIntent; import intents.RequestZoneInIntent; import intents.network.GalacticPacketIntent; import network.packets.Packet; @@ -49,6 +48,7 @@ import resources.control.Manager; import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; import resources.objects.custom.AIObject; +import resources.persistable.SWGObjectFactory; import resources.player.Player; import resources.server_info.CachedObjectDatabase; import resources.server_info.Log; @@ -80,10 +80,10 @@ public class ObjectManager extends Manager { radialService = new RadialService(); clientBuildoutService = new ClientBuildoutService(); - database = new CachedObjectDatabase("odb/objects.db"); + database = new CachedObjectDatabase<>("odb/objects.db", SWGObjectFactory::create, SWGObjectFactory::save); objectMap = new Hashtable<>(16*1024); started = new AtomicBoolean(false); - + addChildService(objectAwareness); addChildService(mapManager); addChildService(staticService); @@ -95,7 +95,6 @@ public class ObjectManager extends Manager { registerForIntent(ObjectTeleportIntent.TYPE); registerForIntent(ObjectCreatedIntent.TYPE); registerForIntent(DestroyObjectIntent.TYPE); - registerForIntent(DeleteCharacterIntent.TYPE); } @Override @@ -110,11 +109,9 @@ public class ObjectManager extends Manager { long startLoad = System.nanoTime(); Log.i("ObjectManager", "Loading objects from ObjectDatabase..."); synchronized (database) { - if (database.fileExists()) { - if (!database.load()) - return false; - database.traverse((obj) -> loadObject(obj)); - } + if (!database.load() && database.fileExists()) + return false; + database.traverse((obj) -> loadObject(obj)); } double loadTime = (System.nanoTime() - startLoad) / 1E6; Log.i("ObjectManager", "Finished loading %d objects. Time: %fms", database.size(), loadTime); @@ -220,8 +217,8 @@ public class ObjectManager extends Manager { putObject(obj); if (obj instanceof CreatureObject && ((CreatureObject) obj).isPlayer()) { synchronized (database) { - database.put(obj.getObjectId(), obj); - database.save(); + if (database.add(obj)) + database.save(); } } if (!(obj instanceof AIObject)) @@ -278,7 +275,7 @@ public class ObjectManager extends Manager { objectAwareness.remove(object); object.clearAware(); synchronized (database) { - if (database.remove(object.getObjectId()) != null) + if (database.remove(object)) database.save(); } synchronized (objectMap) { diff --git a/src/services/player/LoginService.java b/src/services/player/LoginService.java index f84cd3617..59d61bef3 100644 --- a/src/services/player/LoginService.java +++ b/src/services/player/LoginService.java @@ -82,7 +82,6 @@ public class LoginService extends Service { private PreparedStatement getCharacter; private PreparedStatement getCharacters; private PreparedStatement deleteCharacter; - private boolean autoLogin; public LoginService() { random = new Random(); @@ -98,7 +97,6 @@ public class LoginService extends Service { getCharacter = local.prepareStatement("SELECT * FROM characters WHERE LOWER(name) = LOWER(?)"); getCharacters = local.prepareStatement("SELECT * FROM characters WHERE userid = ?"); deleteCharacter = local.prepareStatement("DELETE FROM characters WHERE id = ?"); - autoLogin = getConfig(ConfigFile.NETWORK).getInt("AUTO-LOGIN", 0) == 1; return super.initialize(); } @@ -154,11 +152,6 @@ public class LoginService extends Service { onLoginClientVersionError(player, id); return; } - if (autoLogin) { - String [] sessionHash = id.getPassword().split("-"); - id.setUsername(sessionHash[0]); - id.setPassword(sessionHash[1]); - } synchronized (getUser) { try { getUser.setString(1, id.getUsername()); diff --git a/test/resources/TestResources.java b/test/resources/TestResources.java index 8bf21fabe..8037a5809 100644 --- a/test/resources/TestResources.java +++ b/test/resources/TestResources.java @@ -36,7 +36,7 @@ import resources.collections.TestSWGBitSet; import resources.collections.TestSWGFlag; import resources.network.TestLittleEndianDataOutputStream; import resources.objects.quadtree.TestQuadTree; -import resources.server_info.TestObjectDatabase; +import resources.persistable.TestPersistable; import resources.services.TestConfig; @RunWith(Suite.class) @@ -46,7 +46,7 @@ import resources.services.TestConfig; TestSWGBitSet.class, TestWeatherType.class, TestQuadTree.class, - TestObjectDatabase.class, + TestPersistable.class, TestConfig.class, TestQuaternion.class, TestLittleEndianDataOutputStream.class diff --git a/test/resources/persistable/TestPersistable.java b/test/resources/persistable/TestPersistable.java new file mode 100644 index 000000000..879e7a429 --- /dev/null +++ b/test/resources/persistable/TestPersistable.java @@ -0,0 +1,41 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +import org.junit.runners.Suite.SuiteClasses; + +@RunWith(Suite.class) +@SuiteClasses({ + TestSimplePersistable.class, + TestSWGPersistable.class +}) +public class TestPersistable { + +} diff --git a/test/resources/persistable/TestSWGPersistable.java b/test/resources/persistable/TestSWGPersistable.java new file mode 100644 index 000000000..933154ca9 --- /dev/null +++ b/test/resources/persistable/TestSWGPersistable.java @@ -0,0 +1,146 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import resources.Race; +import resources.objects.SWGObject; +import resources.objects.building.BuildingObject; +import services.objects.ObjectCreator; + +@RunWith(JUnit4.class) +public class TestSWGPersistable { + + @Test + public void testCreatureObject() throws IOException { + test(Race.HUMAN_MALE.getFilename()); + } + + @Test + public void testPlayerObject() throws IOException { + test("object/player/shared_player.iff"); + } + + @Test + public void testTangibleObject() throws IOException { + test("object/tangible/inventory/shared_character_inventory.iff"); + } + + @Test + public void testWeaponObject() throws IOException { + test("object/weapon/melee/unarmed/shared_unarmed_default_player.iff"); + } + + @Test + public void testResourceObject() throws IOException { + test("object/resource_container/shared_resource_container_energy_gas.iff"); + } + + @Test + public void testWaypointObject() throws IOException { + test("object/waypoint/shared_world_waypoint_orange.iff"); + } + + @Test + public void testMissionObject() throws IOException { + test("object/mission/shared_mission_object.iff"); + } + + @Test + public void testFactoryObject() throws IOException { + test("object/factory/shared_factory_crate_weapon.iff"); + } + + @Test + public void testInstallationObject() throws IOException { + test("object/installation/generators/shared_power_generator_wind_style_1.iff"); + } + + @Test + public void testShipObject() throws IOException { + test("object/ship/shared_grievous_starship.iff"); + } + + @Test + public void testManufactureObject() throws IOException { + test("object/manufacture_schematic/shared_generic_schematic.iff"); + } + + @Test + public void testBuildingObject() throws IOException { + test("object/building/tatooine/shared_palace_tatooine_jabba.iff"); + BuildingObject expected = (BuildingObject) ObjectCreator.createObjectFromTemplate("object/building/tatooine/shared_palace_tatooine_jabba.iff"); + expected.populateCells(); + byte [] data = write(expected); + SWGObject obj = read(data); + test(expected, obj); + } + + @Test + public void testCellObject() throws IOException { + test("object/cell/shared_cell.iff"); + } + + private void test(String template) throws IOException { + SWGObject expected = ObjectCreator.createObjectFromTemplate(template); + byte [] data = write(expected); + SWGObject obj = read(data); + test(expected, obj); + } + + private void test(SWGObject expected, SWGObject actual) { + Assert.assertNotNull(actual); + Assert.assertTrue("actual instanceof expected", expected.getClass().isAssignableFrom(actual.getClass())); + Assert.assertEquals("expected.equals(actual)", expected, actual); + } + + private byte [] write(SWGObject obj) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputPersistenceStream os = new OutputPersistenceStream(baos); + os.write(obj, SWGObjectFactory::save); + os.close(); + return baos.toByteArray(); + } + + private SWGObject read(byte [] data) throws IOException { + try (InputPersistenceStream is = new InputPersistenceStream(new ByteArrayInputStream(data))) { + SWGObject obj = is.read(SWGObjectFactory::create); + Assert.assertEquals(0, is.available()); + return obj; + } + } + +} diff --git a/test/resources/persistable/TestSimplePersistable.java b/test/resources/persistable/TestSimplePersistable.java new file mode 100644 index 000000000..6a95e7813 --- /dev/null +++ b/test/resources/persistable/TestSimplePersistable.java @@ -0,0 +1,130 @@ +/************************************************************************************ + * Copyright (c) 2015 /// 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 . * + * * + ***********************************************************************************/ +package resources.persistable; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import resources.network.NetBufferStream; + +@RunWith(JUnit4.class) +public class TestSimplePersistable { + + @Test + public void testInputPersistenceStream() throws IOException { + InputPersistenceStream is = new InputPersistenceStream(new ByteArrayInputStream(createBuffer())); + PersistableObject po = is.read(PersistableObject::create); + Assert.assertEquals(13, po.getSomeInt()); + is.close(); + } + + @Test + public void testOutputPersistenceStream() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(8); + OutputPersistenceStream os = new OutputPersistenceStream(baos); + PersistableObject po = new PersistableObject(13); + os.write(po); + Assert.assertArrayEquals(createBuffer(), baos.toByteArray()); + os.close(); + } + + @Test + public void testPersistenceStreams() throws IOException { + File tmp = File.createTempFile("PersistableTest", "odb"); + OutputPersistenceStream os = new OutputPersistenceStream(new FileOutputStream(tmp)); + PersistableObject original = new PersistableObject(17); + os.write(original); + os.close(); + InputPersistenceStream is = new InputPersistenceStream(new FileInputStream(tmp)); + PersistableObject recreated = is.read(PersistableObject::create); + is.close(); + Assert.assertEquals(original.getSomeInt(), recreated.getSomeInt()); + } + + @Test + public void testPersistenceStreamMultiple() throws IOException { + File tmp = File.createTempFile("PersistableTest", "odb"); + OutputPersistenceStream os = new OutputPersistenceStream(new FileOutputStream(tmp)); + PersistableObject original = new PersistableObject(17); + os.write(original); + os.write(original); + os.write(original); + os.close(); + InputPersistenceStream is = new InputPersistenceStream(new FileInputStream(tmp)); + Assert.assertEquals(original.getSomeInt(), is.read(PersistableObject::create).getSomeInt()); + Assert.assertEquals(original.getSomeInt(), is.read(PersistableObject::create).getSomeInt()); + Assert.assertEquals(original.getSomeInt(), is.read(PersistableObject::create).getSomeInt()); + is.close(); + } + private byte [] createBuffer() { + NetBufferStream stream = new NetBufferStream(8); + stream.addInt(4); + stream.addInt(13); + byte [] array = stream.array(); + stream.close(); + return array; + } + + private static class PersistableObject implements Persistable { + + private final int someInt; + + public PersistableObject(int someInt) { + this.someInt = someInt; + } + + @Override + public void save(NetBufferStream stream) { + stream.addInt(someInt); + } + + @Override + public void read(NetBufferStream stream) { + + } + + public static PersistableObject create(NetBufferStream stream) { + return new PersistableObject(stream.getInt()); + } + + public int getSomeInt() { + return someInt; + } + + } + +} diff --git a/test/resources/server_info/TestObjectDatabase.java b/test/resources/server_info/TestObjectDatabase.java deleted file mode 100644 index fd159b0a5..000000000 --- a/test/resources/server_info/TestObjectDatabase.java +++ /dev/null @@ -1,123 +0,0 @@ -/*********************************************************************************** -* Copyright (c) 2015 /// 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 . * -* * -***********************************************************************************/ -package resources.server_info; - -import java.io.File; - -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -import resources.server_info.ObjectDatabase.Traverser; - -@RunWith(JUnit4.class) -public class TestObjectDatabase { - - private static final File file = new File("test_odb.db"); - - @AfterClass - public static void cleanup() { - if (file.exists() && !file.delete()) - System.err.println("Failed to delete file: " + file); - } - - @Test - public void testPutGet() { - cleanup(); - UncachedObjectDatabase odb = new UncachedObjectDatabase("test_odb.db"); - odb.put(500, 1024); - Assert.assertEquals(1024, odb.get(500).intValue()); - odb.put("testString", 128); - Assert.assertEquals(128, odb.get("testString").intValue()); - } - - @Test - public void testClearCache() { - cleanup(); - UncachedObjectDatabase odb = new UncachedObjectDatabase("test_odb.db"); - odb.put(500, 1024); - Assert.assertEquals(1024, odb.get(500).intValue()); - odb.clearCache(); - Assert.assertEquals(null, odb.get(500)); - } - - @Test - public void testSaveLoad() { - cleanup(); - UncachedObjectDatabase odb = new UncachedObjectDatabase("test_odb.db"); - odb.put(500, 1024); - Assert.assertEquals(1024, odb.get(500).intValue()); - odb.save(); - odb = new UncachedObjectDatabase("test_odb.db"); - Assert.assertEquals(1024, odb.get(500).intValue()); - } - - @Test - public void testSaveClearCache() { - cleanup(); - UncachedObjectDatabase odb = new UncachedObjectDatabase("test_odb.db"); - odb.put(500, 1024); - Assert.assertEquals(1024, odb.get(500).intValue()); - odb.save(); - odb.clearCache(); - Assert.assertEquals(1024, odb.get(500).intValue()); - Assert.assertEquals(1024, odb.get(500).intValue()); - } - - @Test - public void testCache() { - cleanup(); - UncachedObjectDatabase odb = new UncachedObjectDatabase("test_odb.db"); - odb.put(500, 1024); - Assert.assertEquals(1024, odb.get(500).intValue()); - odb.save(); - odb.clearCache(); - odb.loadToCache(); - Integer get = odb.get(500); - Assert.assertEquals(1024, get.intValue()); - } - - @Test - public void testTraverser() { - cleanup(); - UncachedObjectDatabase odb = new UncachedObjectDatabase("test_odb.db"); - odb.put(1024, 301); - odb.put(2048, 301); - odb.put(4096, 301); - final int [] traverseLoops = new int[] {0}; - odb.traverse(new Traverser() { - public void process(Integer i) { - traverseLoops[0]++; - } - }); - Assert.assertEquals(3, traverseLoops[0]); - } - -}