diff --git a/.classpath b/.classpath index e4494fb5d..5c61c2b5f 100644 --- a/.classpath +++ b/.classpath @@ -6,5 +6,8 @@ + + + diff --git a/lib/jgit-4.0.0.201506020755-rc3.jar b/lib/jgit-4.0.0.201506020755-rc3.jar new file mode 100644 index 000000000..745d4d893 Binary files /dev/null and b/lib/jgit-4.0.0.201506020755-rc3.jar differ diff --git a/lib/slf4j-1.7.12/slf4j-api-1.7.12.jar b/lib/slf4j-1.7.12/slf4j-api-1.7.12.jar new file mode 100644 index 000000000..e357ddc7f Binary files /dev/null and b/lib/slf4j-1.7.12/slf4j-api-1.7.12.jar differ diff --git a/lib/slf4j-1.7.12/slf4j-simple-1.7.12.jar b/lib/slf4j-1.7.12/slf4j-simple-1.7.12.jar new file mode 100644 index 000000000..354a78e2b Binary files /dev/null and b/lib/slf4j-1.7.12/slf4j-simple-1.7.12.jar differ diff --git a/scripts/commands/generic/toggleAwayFromKeyBoard.py b/scripts/commands/generic/toggleAwayFromKeyBoard.py new file mode 100644 index 000000000..7b47f0707 --- /dev/null +++ b/scripts/commands/generic/toggleAwayFromKeyBoard.py @@ -0,0 +1,6 @@ +import sys +from resources.player.PlayerFlags import AFK + +def execute(objManager, player, target, args): + player.getPlayerObject().toggleFlag(PlayerFlags.AFK) + return \ No newline at end of file diff --git a/scripts/commands/generic/transferItemMisc.py b/scripts/commands/generic/transferItemMisc.py index 1b13ef7eb..6efa0f714 100644 --- a/scripts/commands/generic/transferItemMisc.py +++ b/scripts/commands/generic/transferItemMisc.py @@ -11,12 +11,12 @@ def execute(galacticManager, player, target, args): return if target.getParent() == actor: + result = target.moveToContainer(actor, inventory) actor.removeEquipment(target) - target.moveToContainer(actor, inventory) return else: - target.moveToContainer(actor, actor) - # actor.addEquipment(target) # This seems to crash the client, look to + result = target.moveToContainer(actor, actor) + actor.addEquipment(target) return return \ No newline at end of file diff --git a/src/network/packets/swg/zone/UpdateContainmentMessage.java b/src/network/packets/swg/zone/UpdateContainmentMessage.java index 6ba83b3fb..e3f6c83fa 100644 --- a/src/network/packets/swg/zone/UpdateContainmentMessage.java +++ b/src/network/packets/swg/zone/UpdateContainmentMessage.java @@ -58,8 +58,7 @@ public class UpdateContainmentMessage extends SWGPacket { } public ByteBuffer encode() { - int length = 26; - ByteBuffer data = ByteBuffer.allocate(length); + ByteBuffer data = ByteBuffer.allocate(26); addShort(data, 4); addInt( data, CRC); addLong( data, objectId); diff --git a/src/network/packets/swg/zone/deltas/DeltasMessage.java b/src/network/packets/swg/zone/deltas/DeltasMessage.java index 5fab6119c..9c6ce12a1 100644 --- a/src/network/packets/swg/zone/deltas/DeltasMessage.java +++ b/src/network/packets/swg/zone/deltas/DeltasMessage.java @@ -78,7 +78,7 @@ public class DeltasMessage extends SWGPacket { addByte(data, num); addInt(data, deltaData.length + 4); addShort(data, 1); // TODO: How many updates there is (1 always for now until a queue system is built - addShort(data, update); // TODO: This should be part of the data, for now we'll keep it here until the queue system is in + addShort(data, update); data.put(deltaData); return data; } diff --git a/src/resources/client_info/ClientFactory.java b/src/resources/client_info/ClientFactory.java index d232b5980..0f24c210b 100644 --- a/src/resources/client_info/ClientFactory.java +++ b/src/resources/client_info/ClientFactory.java @@ -46,7 +46,8 @@ import resources.client_info.visitors.SlotDescriptorData; import utilities.ByteUtilities; public class ClientFactory { - + private static ClientFactory instance; + private Map dataMap = new HashMap(); private Map typeMap = new HashMap(); @@ -81,11 +82,17 @@ public class ClientFactory { * A null instance of {@link ClientData} means that parsing for the type of file is not done, or a file was entered that doesn't exist on the * file system. */ - public synchronized ClientData getInfoFromFile(String file, boolean saveInfo) { - ClientData data = dataMap.get(file); + public synchronized static ClientData getInfoFromFile(String file, boolean saveInfo) { + ClientFactory factory = ClientFactory.instance; + if (factory == null) { + ClientFactory.instance = new ClientFactory(); + factory = ClientFactory.instance; + } + + ClientData data = factory.dataMap.get(file); if (data == null) { - data = readFile(file); + data = factory.readFile(file); if (data == null) { return null; } @@ -100,7 +107,7 @@ public class ClientFactory { return data; } - public synchronized ClientData getInfoFromFile(String file) { + public synchronized static ClientData getInfoFromFile(String file) { return getInfoFromFile(file, true); } @@ -184,7 +191,7 @@ public class ClientFactory { switch (c) { case "CrcStringTableData": return new CrcStringTableData(); case "DatatableData": return new DatatableData(); - case "ObjectData": return new ObjectData(this); + case "ObjectData": return new ObjectData(); case "ProfTemplateData": return new ProfTemplateData(); case "SlotDescriptorData": return new SlotDescriptorData(); case "SlotDefinitionData": return new SlotDefinitionData(); diff --git a/src/resources/client_info/visitors/ObjectData.java b/src/resources/client_info/visitors/ObjectData.java index e6c8a1498..d596fb423 100644 --- a/src/resources/client_info/visitors/ObjectData.java +++ b/src/resources/client_info/visitors/ObjectData.java @@ -39,7 +39,6 @@ import utilities.ByteUtilities; public class ObjectData extends ClientData { private Map attributes = new HashMap(); - private ClientFactory factory; private List parsedFiles = new ArrayList(); public static final String APPEARANCE_FILE = "appearanceFilename"; @@ -50,9 +49,7 @@ public class ObjectData extends ClientData { public static final String PORTAL_LAYOUT = "portalLayoutFilename"; public static final String SLOT_DESCRIPTOR = "slotDescriptorFilename"; - public ObjectData(ClientFactory factory) { - this.factory = factory; - } + public ObjectData() {} @Override public void handleData(String node, ByteBuffer data, int size) { @@ -64,7 +61,7 @@ public class ObjectData extends ClientData { if (parsedFiles.contains(file)) // some DERVXXX were repeated and we do not want to replace any attributes unless they're overriden by a more specific obj break; - ClientData attrData = factory.getInfoFromFile(file); + ClientData attrData = ClientFactory.getInfoFromFile(file); if (attrData == null || !(attrData instanceof ObjectData)) { System.out.println("Could not load attribute data from file " + file + "!"); return; // break out of whole method as we should only continue if we have all the extended attributes diff --git a/src/resources/client_info/visitors/WorldSnapshotData.java b/src/resources/client_info/visitors/WorldSnapshotData.java new file mode 100644 index 000000000..dceb09536 --- /dev/null +++ b/src/resources/client_info/visitors/WorldSnapshotData.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * 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.client_info.visitors; + +import resources.Location; +import utilities.ByteUtilities; + +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class WorldSnapshotData extends ClientData { + private Map objectTemplateNames = new HashMap<>(); + private List chunks = new ArrayList<>(); + + @Override + public void handleData(String node, ByteBuffer data, int size) { + switch (node) { + case "OTNL": + // Object Template Name Table + int n = data.getInt(); + + for (int i = 0; i < n; i++) { + String template = ByteUtilities.nextString(data); + objectTemplateNames.put(i, template); + } + break; + case "0000DATA": + Chunk chunk = new Chunk(); + chunk.setId(data.getInt()); + chunk.setContainerId(data.getInt()); + chunk.setObjectTemplateNameIndex(data.getInt()); + chunk.setCellIndex(data.getInt()); + Location location = new Location(); + location.setOrientationW(data.getFloat()); + location.setOrientationX(data.getFloat()); + location.setOrientationY(data.getFloat()); + location.setOrientationZ(data.getFloat()); + location.setX(data.getFloat()); + location.setY(data.getFloat()); + location.setZ(data.getFloat()); + chunk.setLocation(location); + chunk.setRadius(data.getFloat()); + chunk.setPortalLayoutCrc(data.getInt()); + break; + } + } + + public Map getObjectTemplateNames() { + return objectTemplateNames; + } + + public List getChunks() { + return chunks; + } + + public class Chunk { + private int id; + private int containerId; + private int objectTemplateNameIndex; + private int cellIndex; + private Location location; + private float radius; + private int portalLayoutCrc; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getContainerId() { + return containerId; + } + + public void setContainerId(int containerId) { + this.containerId = containerId; + } + + public int getObjectTemplateNameIndex() { + return objectTemplateNameIndex; + } + + public void setObjectTemplateNameIndex(int objectTemplateNameIndex) { + this.objectTemplateNameIndex = objectTemplateNameIndex; + } + + public int getCellIndex() { + return cellIndex; + } + + public void setCellIndex(int cellIndex) { + this.cellIndex = cellIndex; + } + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public float getRadius() { + return radius; + } + + public void setRadius(float radius) { + this.radius = radius; + } + + public int getPortalLayoutCrc() { + return portalLayoutCrc; + } + + public void setPortalLayoutCrc(int portalLayoutCrc) { + this.portalLayoutCrc = portalLayoutCrc; + } + } +} diff --git a/src/resources/collections/SWGList.java b/src/resources/collections/SWGList.java index 845c7a8f9..cfcc9cd55 100644 --- a/src/resources/collections/SWGList.java +++ b/src/resources/collections/SWGList.java @@ -30,16 +30,13 @@ package resources.collections; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.AbstractList; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import network.packets.swg.zone.baselines.Baseline.BaselineType; -import network.packets.swg.zone.deltas.DeltasMessage; import resources.network.BaselineBuilder.Encodable; import resources.network.DeltaBuilder; import resources.objects.SWGObject; @@ -65,7 +62,7 @@ public class SWGList extends AbstractList implements Encodable { private transient int updateCount; private int dataSize; - private boolean indexed = false; + private boolean indexed = true; private boolean noUpdates = false; private StringType strType = StringType.UNSPECIFIED; @@ -108,7 +105,7 @@ public class SWGList extends AbstractList implements Encodable { boolean added = list.add(e); if (added) { - addData(list.lastIndexOf(e), e); + addObjectData(list.lastIndexOf(e), e); } return added; @@ -119,23 +116,32 @@ public class SWGList extends AbstractList implements Encodable { updateCount++; list.add(index, e); - addData(index, e); + addObjectData(index, e); } @Override public E set(int index, E element) { + // Sends a "change" delta updateCount++; E previous = list.set(index, element); - if (previous != null) + if (previous != null) { removeDataSize(index); - addData(index, element, (byte) 2); + removeData(index); + } + addObjectData(index, element, (byte) 2); return previous; } @Override public E remove(int index) { - // TODO: Remove elements in list - throw new UnsupportedOperationException(); + // Method is also called for remove(E element), just replaced by the index + updateCount++; + E element = list.remove(index); + + if (element != null) + removeObjectData(index, element, (byte) 0); + + return element; } @Override @@ -163,9 +169,9 @@ public class SWGList extends AbstractList implements Encodable { if (size != data.size()) { // Data got out of sync with the list, so lets clean that up! - data.clear(); + clearAllData(); for (int i = 0; i < size; i++) { - addData(i, list.get(i), (byte) 0); + addObjectData(i, list.get(i), (byte) 0); } } @@ -182,7 +188,7 @@ public class SWGList extends AbstractList implements Encodable { } public void sendDeltaMessage(SWGObject target) { - if (!(deltas.size() > 0)) + if (deltas.size() == 0) return; if (target.getOwner() == null || target.getOwner().getPlayerState() != PlayerState.ZONED_IN) { @@ -192,13 +198,21 @@ public class SWGList extends AbstractList implements Encodable { DeltaBuilder builder = new DeltaBuilder(target, baseline, view, updateType, (noUpdates ? encode() : getDeltaData())); builder.send(); + // Clear the queue since the delta has been sent to observers through the builder + clearDeltaQueue(); } public void clearDeltaQueue() { deltas.clear(); deltaSize = 0; } - + + private void clearAllData() { + data.clear(); + dataSize = 0; + clearDeltaQueue(); + } + public void setUpdateCount(int count) { this.updateCount = count; } @@ -225,7 +239,7 @@ public class SWGList extends AbstractList implements Encodable { } } - private void addData(int index, Object obj, byte update) { + private void addObjectData(int index, Object obj, byte update) { byte[] encodedData = Encoder.encode(obj, strType); data.put(index, encodedData); @@ -244,21 +258,38 @@ public class SWGList extends AbstractList implements Encodable { } } - private void addData(int index, Object obj) { - addData(index, obj, (byte) 1); + private void addObjectData(int index, Object obj) { + addObjectData(index, obj, (byte) 1); } - - // Removes obj size of data and removes it from the data map - private void removeData(Object obj) { - dataSize -= data.remove(indexOf(obj)).length; + + private void removeObjectData(int index, Object object, byte update) { + if (data.get(index) != null) { + dataSize -= data.remove(index).length; + } + + if (indexed && !noUpdates) { + // Only the index is sent for removing data + ByteBuffer buffer = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN); + buffer.putShort((short) index); + createDeltaData(buffer.array(), update); + } } - + // Removes obj size of data without removing it from the data map private void removeDataSize(int index) { dataSize -= data.get(index).length; } - + + private void removeData(int index) { + data.remove(index); + } + public BaselineType getBaseline() { return baseline; } public int getViewType() { return view; } public int getUpdateType() { return updateType; } + + @Override + public String toString() { + return "SWGList[" + baseline + "0" + view + ":" + updateType + "]"; + } } diff --git a/src/resources/collections/SWGMap.java b/src/resources/collections/SWGMap.java index 6b3f2ab96..63ecc9a10 100644 --- a/src/resources/collections/SWGMap.java +++ b/src/resources/collections/SWGMap.java @@ -163,7 +163,7 @@ public class SWGMap extends AbstractMap implements Encodable { if (data.size() != size) { // Data got out of sync with the map, so lets clean that up! - data.clear(); + clearAllData(); for (Entry entry : map.entrySet()) { addData(entry.getKey(), entry.getValue(), (byte) 0); } @@ -188,7 +188,7 @@ public class SWGMap extends AbstractMap implements Encodable { DeltaBuilder builder = new DeltaBuilder(target, baseline, view, updateType, getDeltaData()); builder.send(); - + // Clear the queue since the delta has been sent to observers through the builder clearDeltaQueue(); } @@ -222,7 +222,14 @@ public class SWGMap extends AbstractMap implements Encodable { deltas.put(key, combindedUpdate); } } - + + private void clearAllData() { + dataSize = 0; + data.clear(); + + clearDeltaQueue(); + } + private void addData(Object key, Object value, byte update) { byte[] encodedKey = Encoder.encode(key, strType); byte[] encodedValue = Encoder.encode(value, strType); diff --git a/src/resources/commands/callbacks/AfkCmdCallback.java b/src/resources/commands/callbacks/AfkCmdCallback.java deleted file mode 100644 index b5929f081..000000000 --- a/src/resources/commands/callbacks/AfkCmdCallback.java +++ /dev/null @@ -1,44 +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.commands.callbacks; - -import resources.commands.ICmdCallback; -import resources.objects.SWGObject; -import resources.player.Player; -import resources.player.PlayerFlags; -import services.galaxy.GalacticManager; - -public class AfkCmdCallback implements ICmdCallback { - - @Override - public void execute(GalacticManager galacticManager, Player player, - SWGObject target, String args) { - player.getPlayerObject().toggleFlag(PlayerFlags.AFK); - } - -} diff --git a/src/resources/commands/callbacks/RequestWaypointCmdCallback.java b/src/resources/commands/callbacks/RequestWaypointCmdCallback.java index 3c7364c9a..a7ccbf777 100644 --- a/src/resources/commands/callbacks/RequestWaypointCmdCallback.java +++ b/src/resources/commands/callbacks/RequestWaypointCmdCallback.java @@ -38,14 +38,32 @@ public class RequestWaypointCmdCallback implements ICmdCallback { @Override public void execute(GalacticManager galacticManager, Player player, SWGObject target, String args) { + // First parameter can be name of the planet or an int for the color // Args: (^-,=+_)color_1(,+-=_^)=1 planet x 0.0 z PlayerObject ghost = player.getPlayerObject(); if (ghost == null) return; - - String[] cmd = args.split(" ", 5); + + String[] cmd = args.split(" ", 6); + WaypointObject.WaypointColor color = WaypointObject.WaypointColor.BLUE; + +/* if (cmd[0].contains("color_")) { + // Command is in color planet x y z name format + String colorId = cmd[0].substring(14, cmd[0].length() - 10); + color = WaypointObject.WaypointColor.values()[Integer.valueOf(colorId) - 1]; + }*/ + + double x = (color != null ? Double.valueOf(cmd[2]) : Double.valueOf(cmd[1])); + double y = (color != null ? Double.valueOf(cmd[3]) : Double.valueOf(cmd[2])); + double z = (color != null ? Double.valueOf(cmd[4]) : Double.valueOf(cmd[3])); + + String name = (cmd.length == 6 ? cmd[5] : "New Waypoint"); + WaypointObject waypoint = (WaypointObject) galacticManager.getObjectManager().createObject("object/waypoint/shared_waypoint.iff", player.getCreatureObject().getLocation()); - waypoint.setLocation(Double.valueOf(cmd[2]), 0, Double.valueOf(cmd[4])); + waypoint.setLocation(x, y, z); + waypoint.setName(name); + if (color != null) + waypoint.setColor(color); ghost.addWaypoint(waypoint); } } diff --git a/src/resources/commands/callbacks/WaypointCmdCallback.java b/src/resources/commands/callbacks/WaypointCmdCallback.java index 9b52ddd98..74c254983 100644 --- a/src/resources/commands/callbacks/WaypointCmdCallback.java +++ b/src/resources/commands/callbacks/WaypointCmdCallback.java @@ -27,7 +27,6 @@ ***********************************************************************************/ package resources.commands.callbacks; -import network.packets.swg.zone.chat.ChatSystemMessage; import resources.Location; import resources.Terrain; import resources.commands.ICmdCallback; @@ -87,11 +86,8 @@ public class WaypointCmdCallback implements ICmdCallback { default: break; } - if (ghost.getWaypoints().size() < 250) { WaypointObject waypoint = createWaypoint(galacticManager.getObjectManager(), terrain, color, name, x, y, player.getCreatureObject().getLocation()); ghost.addWaypoint(waypoint); - } else - ghost.sendSelf(new ChatSystemMessage(ChatSystemMessage.SystemChatType.SCREEN_AND_CHAT, "@base_player:too_many_waypoints")); } diff --git a/src/resources/encodables/player/Equipment.java b/src/resources/encodables/player/Equipment.java index e5afae432..6fd7f17d6 100644 --- a/src/resources/encodables/player/Equipment.java +++ b/src/resources/encodables/player/Equipment.java @@ -32,6 +32,7 @@ import java.nio.ByteOrder; import resources.common.CRC; import resources.network.BaselineBuilder.Encodable; +import resources.objects.SWGObject; import resources.objects.weapon.WeaponObject; public class Equipment implements Encodable { @@ -41,16 +42,15 @@ public class Equipment implements Encodable { private byte[] customizationString; private int arrangementId = 4; private long objectId; - private int templateCRC; + private String template; public Equipment(long objectId, String template) { this.objectId = objectId; - this.templateCRC = CRC.getCrc(template); + this.template = template; } public Equipment(WeaponObject weapon) { - this.objectId = weapon.getObjectId(); - this.templateCRC = weapon.getCrc(); + this(weapon.getObjectId(), weapon.getTemplate()); this.weapon = weapon; } @@ -72,7 +72,7 @@ public class Equipment implements Encodable { buffer.putInt(arrangementId); buffer.putLong(objectId); - buffer.putInt(templateCRC); + buffer.putInt(CRC.getCrc(template)); if (weapon != null) { buffer.put((byte) 0x01); @@ -93,6 +93,19 @@ public class Equipment implements Encodable { public long getObjectId() { return objectId; } public void setObjectId(long objectId) { this.objectId = objectId; } - public int getTemplateCRC() { return templateCRC; } - public void setTemplateCRC(int templateCRC) { this.templateCRC = templateCRC; } + public String getTemplate() { return template; } + public void setTemplate(String template) { this.template = template; } + + @Override + public String toString() { + return "Equipment: " + template; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof SWGObject)) + return super.equals(o); + + return ((SWGObject) o).getObjectId() == objectId; + } } diff --git a/src/resources/objects/SWGObject.java b/src/resources/objects/SWGObject.java index 5dc0245f2..9cc3e4e2d 100644 --- a/src/resources/objects/SWGObject.java +++ b/src/resources/objects/SWGObject.java @@ -165,7 +165,7 @@ public abstract class SWGObject implements Serializable, Comparable { int arrangementId = container.getArrangementId(this); if (arrangementId == -1) { // Item is going to go into the container, so check to see if it'll fit - if (container.getMaxContainerSize() >= container.getContainedObjects().size()) { + if (container.getMaxContainerSize() <= container.getContainedObjects().size()) { return ContainerResult.CONTAINER_FULL; } } @@ -176,15 +176,19 @@ public abstract class SWGObject implements Serializable, Comparable { List oldObservers = getChildrenAwareness(); // Remove this object from the old parent if one exists + SWGObject oldParent = null; if (parent != null) { + oldParent = parent; parent.removeObject(this); } - container.addObject(this); + if (!container.addObject(this)) + System.err.println("Failed adding " + this + " to " + container); // Observer notification sendUpdatedContainment(oldObservers, new ArrayList<>(container.getChildrenAwareness())); + Log.i("Container", "Moved %s from %s to %s", this, oldParent, container); return ContainerResult.SUCCESS; } @@ -424,7 +428,7 @@ public abstract class SWGObject implements Serializable, Comparable { * @return Arrangement ID for the object */ public int getArrangementId(SWGObject object) { - if (object.getArrangement() == null) + if (slots.size() == 0 || object.getArrangement() == null) return -1; int arrangementId = 4; @@ -437,8 +441,7 @@ public abstract class SWGObject implements Serializable, Comparable { if (!hasSlot(slot)) { isValid = false; break; - } - if (slots.get(slot) != null) { + } else if (slots.get(slot) != null) { passesCompletely = false; } } @@ -449,7 +452,7 @@ public abstract class SWGObject implements Serializable, Comparable { arrangementId++; } - return (filledId != -1) ? arrangementId : 4; + return (filledId != -1) ? filledId : -1; } protected final void sendSceneCreateObject(Player target) { @@ -576,6 +579,8 @@ public abstract class SWGObject implements Serializable, Comparable { } private void sendUpdatedContainment(List oldObservers, List newObservers) { + if (parent == null) + return; List same = new ArrayList<>(oldObservers); same.retainAll(newObservers); @@ -657,29 +662,61 @@ public abstract class SWGObject implements Serializable, Comparable { } protected void createChildrenObjects(Player target) { + if (slots.size() == 0 && containedObjects.size() == 0) + return; + if (!hasPermission(target.getCreatureObject(), ContainerPermissions.Permission.OPEN)) { - Log.w("SWGObject", target.getCreatureObject() + " doesn't have permission to view " + this + " -- skipping packet sending"); + Log.i("SWGObject", target.getCreatureObject() + " doesn't have permission to view " + this + " -- skipping packet sending"); return; } + List sentObjects = new ArrayList<>(); + // First create the objects in the slots for (SWGObject slotObject : slots.values()) { - if (slotObject != null) { - //Log.d("Sending slotObj " + slotObject + " to " + target); + if (slotObject != null && !sentObjects.contains(slotObject)) { + //Log.i("ChildrenObjects", "Sending slotObj " + slotObject + " to " + target); slotObject.createObject(target); + sentObjects.add(slotObject); } } // Now create the contained objects for (SWGObject containedObject : containedObjects.values()) { - if (containedObject != null) { - //Log.d("SWGObject", "Sending containedObj " + containedObject + " to " + target); + if (containedObject != null && sentObjects.contains(containedObject)) { + //Log.i("ChildrenObjects", "Sending containedObj " + containedObject + " to " + target); //Log.d("SWGObject", "Sending to location " + containedObject.getLocation()); containedObject.createObject(target); } } } - + + private void debug_printSlotInfo(int tabs) { + String s = ""; + for (int i = 0; i < tabs; i++) { + s += "\t"; + } + System.out.println(s + "=== debug_printSlotInfo ===: " + this); + if (slots.size() == 0 && containedObjects.size() == 0) { + System.out.println(s + "NO CHILDREN"); + return; + } + + if (slots.size() > 0) System.out.println(s + "= Slots ="); + for (Map.Entry entry : slots.entrySet()) { + System.out.println(s + "Slot: " + entry.getKey() + " Value: " + entry.getValue() + (entry.getValue() != null ? " arrangement: " + entry.getValue().slotArrangement : "")); + if (entry.getValue() != null) entry.getValue().debug_printSlotInfo(tabs + 1); + } + + if (containedObjects.size() > 0) System.out.println(s + "= ContainerObjects ="); + for (SWGObject object : containedObjects.values()) { + System.out.println(s + "ContainedObject: " + object + " arrangementId: " + object.slotArrangement); + object.debug_printSlotInfo(tabs + 1); + } + + + } + @Override public String toString() { return "SWGObject[ID=" + objectId + " NAME=" + objectName + " TEMPLATE=" + template + "]"; diff --git a/src/resources/objects/buildouts/BuildoutLoader.java b/src/resources/objects/buildouts/BuildoutLoader.java index d4228b6aa..a071a5346 100644 --- a/src/resources/objects/buildouts/BuildoutLoader.java +++ b/src/resources/objects/buildouts/BuildoutLoader.java @@ -39,9 +39,7 @@ import resources.objects.SWGObject; import resources.server_info.Log; public class BuildoutLoader { - - private static final ClientFactory clientFactory = new ClientFactory(); - private static final CrcStringTableData crcTable = (CrcStringTableData) clientFactory.getInfoFromFile("misc/object_template_crc_string_table.iff"); + private static final CrcStringTableData crcTable = (CrcStringTableData) ClientFactory.getInfoFromFile("misc/object_template_crc_string_table.iff"); public static List loadAllBuildouts() { List objects = new LinkedList(); @@ -51,10 +49,10 @@ public class BuildoutLoader { } public static List loadBuildoutsForTerrain(Terrain terrain) { - DatatableData table = (DatatableData) clientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff"); + DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff"); for (int row = 0; row < table.getRowCount(); row++) { if (table.getCell(row, 0).equals(terrain.name().toLowerCase(Locale.ENGLISH))) { - TerrainBuildoutLoader loader = new TerrainBuildoutLoader(clientFactory, crcTable, terrain); + TerrainBuildoutLoader loader = new TerrainBuildoutLoader(crcTable, terrain); loader.load(row); return loader.getObjects(); } @@ -65,7 +63,7 @@ public class BuildoutLoader { } private static List getTerrainsToLoad() { - DatatableData table = (DatatableData) clientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff"); + DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("datatables/buildout/buildout_scenes.iff"); List terrains = new LinkedList(); for (int row = 0; row < table.getRowCount(); row++) { Terrain t = Terrain.getTerrainFromName((String) table.getCell(row, 0)); diff --git a/src/resources/objects/buildouts/TerrainBuildoutLoader.java b/src/resources/objects/buildouts/TerrainBuildoutLoader.java index 722683437..086420750 100644 --- a/src/resources/objects/buildouts/TerrainBuildoutLoader.java +++ b/src/resources/objects/buildouts/TerrainBuildoutLoader.java @@ -45,15 +45,13 @@ import services.objects.ObjectCreator; class TerrainBuildoutLoader { private static final String BASE_PATH = "datatables/buildout/"; - - private final ClientFactory clientFactory; + private final CrcStringTableData crcTable; private final Terrain terrain; private final Map objectTable; private final List objects; - public TerrainBuildoutLoader(ClientFactory clientFactory, CrcStringTableData crcTable, Terrain terrain) { - this.clientFactory = clientFactory; + public TerrainBuildoutLoader(CrcStringTableData crcTable, Terrain terrain) { this.crcTable = crcTable; this.terrain = terrain; this.objectTable = new Hashtable(12*1024); @@ -72,7 +70,7 @@ class TerrainBuildoutLoader { private void loadAreas(int sceneNumber) { objects.clear(); String file = BASE_PATH+"areas_"+terrain.getName()+".iff"; - DatatableData areaTable = (DatatableData) clientFactory.getInfoFromFile(file); + DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file); for (int row = 0; row < areaTable.getRowCount(); row++) { BuildoutArea area = new BuildoutArea(); area.load(areaTable.getRow(row), sceneNumber, row); @@ -84,7 +82,7 @@ class TerrainBuildoutLoader { private void loadArea(BuildoutArea area) { String file = BASE_PATH+terrain.getName()+"/"+area.getName().replace("server", "client")+".iff"; - DatatableData areaTable = (DatatableData) clientFactory.getInfoFromFile(file); + DatatableData areaTable = (DatatableData) ClientFactory.getInfoFromFile(file); BuildoutRow buildoutRow = new BuildoutRow(area); for (int row = 0; row < areaTable.getRowCount(); row++) { buildoutRow.load(areaTable.getRow(row), crcTable); diff --git a/src/resources/objects/creature/CreatureObject.java b/src/resources/objects/creature/CreatureObject.java index 4f01eb9c4..ad425d336 100644 --- a/src/resources/objects/creature/CreatureObject.java +++ b/src/resources/objects/creature/CreatureObject.java @@ -112,8 +112,13 @@ public class CreatureObject extends TangibleObject { public void removeEquipment(SWGObject obj) { synchronized (equipmentList) { - if (equipmentList.remove(obj)) - equipmentList.sendDeltaMessage(this); + for (Equipment equipment : equipmentList) { + if (equipment.getObjectId() == obj.getObjectId()) { + equipmentList.remove(equipment); + equipmentList.sendDeltaMessage(this); + break; + } + } } } @@ -136,8 +141,12 @@ public class CreatureObject extends TangibleObject { public void removeAppearanceItem(SWGObject obj) { synchronized (appearanceList) { - if (appearanceList.remove(obj)) - appearanceList.sendDeltaMessage(this); + for (Equipment equipment : appearanceList) { + if (equipment.getObjectId() == obj.getObjectId()) { + appearanceList.remove(equipment); + appearanceList.sendDeltaMessage(this); + } + } } } diff --git a/src/resources/objects/player/PlayerObject.java b/src/resources/objects/player/PlayerObject.java index 0e1bfb720..0137c7448 100644 --- a/src/resources/objects/player/PlayerObject.java +++ b/src/resources/objects/player/PlayerObject.java @@ -29,6 +29,7 @@ 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.SWGList; import resources.collections.SWGMap; import resources.network.BaselineBuilder; @@ -102,8 +103,13 @@ 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")); + } } } diff --git a/src/services/commands/CommandService.java b/src/services/commands/CommandService.java index 46e8588ec..c6980cb8c 100644 --- a/src/services/commands/CommandService.java +++ b/src/services/commands/CommandService.java @@ -128,17 +128,16 @@ public class CommandService extends Service { } private void loadBaseCommands() { - final ClientFactory factory = new ClientFactory(); final String [] commandTables = new String [] {"command_table", "client_command_table", "command_table_ground"}; clearCommands(); for (String table : commandTables) { - loadBaseCommands(factory, table); + loadBaseCommands(table); } } - private void loadBaseCommands(ClientFactory factory, String table) { - DatatableData baseCommands = (DatatableData) factory.getInfoFromFile("datatables/command/"+table+".iff"); + private void loadBaseCommands(String table) { + DatatableData baseCommands = (DatatableData) ClientFactory.getInfoFromFile("datatables/command/"+table+".iff"); for (int row = 0; row < baseCommands.getRowCount(); row++) { Object [] cmdRow = baseCommands.getRow(row); @@ -171,7 +170,6 @@ public class CommandService extends Service { registerCallback("teleport", new AdminTeleportCallback()); registerCallback("prone", new ProneCmdCallback()); registerCallback("kneel", new KneelCmdCallback()); - registerCallback("toggleAwayFromKeyBoard", new AfkCmdCallback()); registerCallback("jumpServer", new JumpCmdCallback()); registerCallback("serverDestroyObject", new ServerDestroyObjectCmdCallback()); } diff --git a/src/services/map/MapService.java b/src/services/map/MapService.java index 863b75406..0c0aef138 100644 --- a/src/services/map/MapService.java +++ b/src/services/map/MapService.java @@ -69,9 +69,8 @@ public class MapService extends Service { dynamicMapLocations = new ConcurrentHashMap<>(); persistentMapLocations = new ConcurrentHashMap<>(); - ClientFactory clientFactory = new ClientFactory(); - loadMapCategories(clientFactory); - loadMappingTemplates(clientFactory); + loadMapCategories(); + loadMappingTemplates(); } @Override @@ -129,8 +128,8 @@ public class MapService extends Service { player.sendPacket(responseMessage); } - private void loadMapCategories(ClientFactory clientFactory) { - DatatableData table = (DatatableData) clientFactory.getInfoFromFile("datatables/player/planet_map_cat.iff"); + private void loadMapCategories() { + DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("datatables/player/planet_map_cat.iff"); for (int row = 0; row < table.getRowCount(); row++) { MapCategory category = new MapCategory(); category.setName(table.getCell(row, 0).toString()); @@ -144,8 +143,8 @@ public class MapService extends Service { } } - private void loadMappingTemplates(ClientFactory clientFactory) { - DatatableData table = (DatatableData) clientFactory.getInfoFromFile("map_locations.iff"); + private void loadMappingTemplates() { + DatatableData table = (DatatableData) ClientFactory.getInfoFromFile("map_locations.iff"); for (int row = 0; row < table.getRowCount(); row++) { MappingTemplate template = new MappingTemplate(); template.setTemplate(ClientFactory.formatToSharedFile(table.getCell(row, 0).toString())); @@ -159,7 +158,6 @@ public class MapService extends Service { } } - public void addMapLocation(SWGObject object, MapType type) { if (!mappingTemplates.containsKey(object.getTemplate())) return; @@ -191,7 +189,7 @@ public class MapService extends Service { } } - private void addStaticMapLocation(String planet, MapLocation location) { + public void addStaticMapLocation(String planet, MapLocation location) { if (staticMapLocations.containsKey(planet)) { location.setId(staticMapLocations.get(planet).size() + 1); staticMapLocations.get(planet).add(location); @@ -202,7 +200,7 @@ public class MapService extends Service { } } - private void addDynamicMapLocation(String planet, MapLocation location) { + public void addDynamicMapLocation(String planet, MapLocation location) { if (dynamicMapLocations.containsKey(planet)) { location.setId(dynamicMapLocations.get(planet).size() + 1); dynamicMapLocations.get(planet).add(location); @@ -213,7 +211,7 @@ public class MapService extends Service { } } - private void addPersistentMapLocation(String planet, MapLocation location) { + public void addPersistentMapLocation(String planet, MapLocation location) { if (persistentMapLocations.containsKey(planet)) { location.setId(persistentMapLocations.get(planet).size() + 1); persistentMapLocations.get(planet).add(location); diff --git a/src/services/objects/ObjectCreator.java b/src/services/objects/ObjectCreator.java index 85e7d200b..09eacbaea 100644 --- a/src/services/objects/ObjectCreator.java +++ b/src/services/objects/ObjectCreator.java @@ -50,9 +50,7 @@ import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; public final class ObjectCreator { - - private static final ClientFactory clientFac = new ClientFactory(); - + public static final SWGObject createObjectFromTemplate(long objectId, String template) { if (!template.startsWith("object/")) return null; @@ -93,7 +91,7 @@ public final class ObjectCreator { } private static void addObjectAttributes(SWGObject obj, String template) { - ObjectData attributes = (ObjectData) clientFac.getInfoFromFile(ClientFactory.formatToSharedFile(template)); + ObjectData attributes = (ObjectData) ClientFactory.getInfoFromFile(ClientFactory.formatToSharedFile(template)); String stf = (String) attributes.getAttribute(ObjectData.OBJ_STF); String detailStf = (String) attributes.getAttribute(ObjectData.DETAIL_STF); @@ -122,7 +120,7 @@ public final class ObjectCreator { private static void createObjectSlots(SWGObject object) { if (object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR) != null) { // These are the slots that the object *HAS* - SlotDescriptorData descriptor = (SlotDescriptorData) clientFac.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR)); + SlotDescriptorData descriptor = (SlotDescriptorData) ClientFactory.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.SLOT_DESCRIPTOR)); for (String slotName : descriptor.getSlots()) { object.getSlots().put(slotName, null); @@ -131,7 +129,7 @@ public final class ObjectCreator { if (object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE) != null) { // This is what slots the created object is able to go into/use - SlotArrangementData arrangementData = (SlotArrangementData) clientFac.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE)); + SlotArrangementData arrangementData = (SlotArrangementData) ClientFactory.getInfoFromFile((String) object.getTemplateAttribute(ObjectData.ARRANGEMENT_FILE)); object.setArrangement(arrangementData.getArrangement()); } } diff --git a/src/services/objects/ObjectManager.java b/src/services/objects/ObjectManager.java index 48d2f371e..5bdcf234e 100644 --- a/src/services/objects/ObjectManager.java +++ b/src/services/objects/ObjectManager.java @@ -238,6 +238,7 @@ public class ObjectManager extends Manager { SWGObject obj = objects.remove(objId); if (obj == null) return null; + obj.clearAware(); objectAwareness.remove(obj); Log.i("ObjectManager", "Deleted object %d [%s]", obj.getObjectId(), obj.getTemplate()); return obj; @@ -287,7 +288,15 @@ public class ObjectManager extends Manager { return createObject(template, null); } + public SWGObject createObject(String template, boolean addToAwareness) { + return createObject(template, null, addToAwareness); + } + public SWGObject createObject(String template, Location l) { + return createObject(template, l, true); + } + + public SWGObject createObject(String template, Location l, boolean addToAwareness) { synchronized (objects) { long objectId = getNextObjectId(); SWGObject obj = ObjectCreator.createObjectFromTemplate(objectId, template); @@ -296,7 +305,9 @@ public class ObjectManager extends Manager { return null; } obj.setLocation(l); - objectAwareness.add(obj); + if (addToAwareness) { + objectAwareness.add(obj); + } objects.put(objectId, obj); Log.i("ObjectManager", "Created object %d [%s]", obj.getObjectId(), obj.getTemplate()); return obj; diff --git a/src/services/player/ZoneService.java b/src/services/player/ZoneService.java index 2ec76f79b..add49b2af 100644 --- a/src/services/player/ZoneService.java +++ b/src/services/player/ZoneService.java @@ -31,6 +31,8 @@ import intents.GalacticIntent; import intents.PlayerEventIntent; import intents.ZoneInIntent; +import java.io.File; +import java.io.IOException; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; @@ -41,6 +43,11 @@ import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; + import main.ProjectSWG; import network.packets.Packet; import network.packets.soe.SessionRequest; @@ -68,6 +75,7 @@ import network.packets.swg.zone.ShowBackpack; import network.packets.swg.zone.ShowHelmet; import network.packets.swg.zone.UpdatePvpStatusMessage; import network.packets.swg.zone.chat.ChatOnConnectAvatar; +import network.packets.swg.zone.chat.ChatSystemMessage; import network.packets.swg.zone.chat.VoiceChatStatus; import network.packets.swg.zone.insertion.ChatServerStatus; import network.packets.swg.zone.insertion.CmdStartScene; @@ -102,7 +110,6 @@ public class ZoneService extends Service { private final Map lockedNames; private final Map profTemplates; - private final ClientFactory clientFac; private final NameFilter nameFilter; private final SWGNameGenerator nameGenerator; private final CharacterCreationRestriction creationRestriction; @@ -110,14 +117,15 @@ public class ZoneService extends Service { private PreparedStatement createCharacter; private PreparedStatement getCharacter; private PreparedStatement getLikeCharacterName; + private String commitHistory; public ZoneService() { lockedNames = new HashMap(); profTemplates = new ConcurrentHashMap(); - clientFac = new ClientFactory(); nameFilter = new NameFilter("namegen/bad_word_list.txt", "namegen/reserved_words.txt", "namegen/fiction_reserved.txt"); nameGenerator = new SWGNameGenerator(nameFilter); creationRestriction = new CharacterCreationRestriction(2); + commitHistory = ""; } @Override @@ -128,6 +136,7 @@ public class ZoneService extends Service { getLikeCharacterName = getLocalDatabase().prepareStatement("SELECT name FROM characters WHERE name ilike ?"); //NOTE: ilike is not SQL standard. It is an extension for postgres only. nameGenerator.loadAllRules(); loadProfTemplates(); + loadCommitHistory(); if (!nameFilter.load()) System.err.println("Failed to load name filter!"); registerForIntent(ZoneInIntent.TYPE); @@ -182,9 +191,48 @@ public class ZoneService extends Service { creature.createObject(player); System.out.printf("[%s] %s is zoning in%n", player.getUsername(), player.getCharacterName()); Log.i("ObjectManager", "Zoning in %s with character %s", player.getUsername(), player.getCharacterName()); + sendCommitHistory(player); new PlayerEventIntent(player, galaxy, PlayerEvent.PE_ZONE_IN).broadcast(); } + private void loadCommitHistory() { + File repoDir = new File("./" + Constants.DOT_GIT); // Ziggy: Get the git directory + Git git = null; + Repository repo = null; + int commitCount = 3; + int iterations = 0; + + try { + git = Git.open(repoDir); + repo = git.getRepository(); + + try { + commitHistory = "The " + commitCount + " most recent commits in branch '" + repo.getBranch() + "':\n"; + + for(RevCommit commit : git.log().setMaxCount(commitCount).call()) { + commitHistory += commit.getName().substring(0, 7) + " " + commit.getShortMessage(); + + if(commitCount > iterations++) + commitHistory += "\n"; + } + + } catch (Throwable t) { + t.printStackTrace(); + } + + } catch (IOException e) { + // Ziggy: An exception is thrown if bash isn't installed + // It works fine anyways. + // https://www.eclipse.org/forums/index.php/t/1031740/ + } + + + } + + private void sendCommitHistory(Player player) { + player.sendPacket(new ChatSystemMessage(ChatSystemMessage.SystemChatType.CHAT, commitHistory)); + } + private void sendZonePackets(Player player, CreatureObject creature) { long objId = creature.getObjectId(); Race race = creature.getRace(); @@ -488,13 +536,13 @@ public class ZoneService extends Service { } private void loadProfTemplates() { - profTemplates.put("crafting_artisan", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_combat_brawler.iff")); - profTemplates.put("combat_brawler", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_combat_brawler.iff")); - profTemplates.put("social_entertainer", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_social_entertainer.iff")); - profTemplates.put("combat_marksman", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_combat_marksman.iff")); - profTemplates.put("science_medic", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_science_medic.iff")); - profTemplates.put("outdoors_scout", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_outdoors_scout.iff")); - profTemplates.put("jedi", (ProfTemplateData) clientFac.getInfoFromFile("creation/profession_defaults_jedi.iff")); + profTemplates.put("crafting_artisan", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_combat_brawler.iff")); + profTemplates.put("combat_brawler", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_combat_brawler.iff")); + profTemplates.put("social_entertainer", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_social_entertainer.iff")); + profTemplates.put("combat_marksman", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_combat_marksman.iff")); + profTemplates.put("science_medic", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_science_medic.iff")); + profTemplates.put("outdoors_scout", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_outdoors_scout.iff")); + profTemplates.put("jedi", (ProfTemplateData) ClientFactory.getInfoFromFile("creation/profession_defaults_jedi.iff")); } private boolean lockName(String name, Player player) {