package services.objects; import intents.GalacticPacketIntent; import intents.swgobject_events.SWGObjectEventIntent; import intents.swgobject_events.SWGObjectMovedIntent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import main.ProjectSWG; import network.packets.swg.zone.HeartBeatMessage; import network.packets.swg.zone.ParametersMessage; import network.packets.swg.zone.UpdatePvpStatusMessage; import network.packets.swg.zone.chat.ChatOnConnectAvatar; import network.packets.swg.zone.chat.VoiceChatStatus; import network.packets.swg.zone.insertion.ChatServerStatus; import network.packets.swg.zone.insertion.CmdStartScene; import network.packets.swg.zone.insertion.SelectCharacter; import resources.Location; import resources.Race; import resources.Terrain; import resources.client_info.ClientFactory; import resources.client_info.visitors.ObjectData; import resources.control.Intent; import resources.control.Manager; import resources.objects.SWGObject; import resources.objects.creature.CreatureObject; import resources.objects.intangible.IntangibleObject; import resources.objects.player.PlayerObject; import resources.objects.quadtree.QuadTree; import resources.objects.tangible.TangibleObject; import resources.objects.waypoint.WaypointObject; import resources.objects.weapon.WeaponObject; import resources.player.Player; import resources.server_info.ObjectDatabase; import resources.server_info.ObjectDatabase.Traverser; import services.player.PlayerManager; public class ObjectManager extends Manager { private static final double AWARE_RANGE = 200; private ClientFactory clientFac; private ObjectDatabase objects; private Map > quadTree; private long maxObjectId; public ObjectManager() { objects = new ObjectDatabase("odb/objects.db"); quadTree = new HashMap>(); maxObjectId = 1; } @Override public boolean initialize() { registerForIntent(SWGObjectEventIntent.TYPE); registerForIntent(GalacticPacketIntent.TYPE); for (Terrain t : Terrain.values()) { quadTree.put(t.getFile(), new QuadTree(-5000, -5000, 5000, 5000)); } objects.loadToCache(); System.out.println("ObjectManager: Loading " + objects.size() + " objects from ObjectDatabase..."); objects.traverse(new Traverser() { @Override public void process(SWGObject obj) { Location l = obj.getLocation(); if (l.getTerrain() != null) { QuadTree tree = quadTree.get(l.getTerrain().getFile()); if (tree != null) { System.out.println(l.getX() + ", " + l.getZ()); tree.put(l.getX(), l.getZ(), obj); } else { System.err.println("ObjectManager: Unable to load QuadTree for object " + obj.getObjectId() + " and terrain: " + l.getTerrain()); } } } }); clientFac = new ClientFactory(); return super.initialize(); } @Override public boolean terminate() { objects.save(); return super.terminate(); } @Override public void onIntentReceived(Intent i) { if (i instanceof SWGObjectMovedIntent) { Location oTerrain = ((SWGObjectMovedIntent) i).getOldLocation(); Location nTerrain = ((SWGObjectMovedIntent) i).getNewLocation(); SWGObject obj = ((SWGObjectMovedIntent) i).getObject(); if (oTerrain.getTerrain() == null || nTerrain.getTerrain() == null) return; double x = oTerrain.getX(); double y = oTerrain.getZ(); quadTree.get(oTerrain.getTerrain().getFile()).remove(x, y, obj); x = nTerrain.getX(); y = nTerrain.getZ(); QuadTree tree = quadTree.get(nTerrain.getTerrain().getFile()); tree.put(x, y, obj); List updatedAware = new ArrayList(); for (SWGObject inRange : tree.getWithinRange(x, y, AWARE_RANGE)) { if (inRange.getOwner() != null) updatedAware.add(inRange.getOwner()); } obj.updateAwareness(updatedAware); } else if (i instanceof GalacticPacketIntent) { GalacticPacketIntent gpi = (GalacticPacketIntent) i; if (gpi.getPacket() instanceof SelectCharacter) { zoneInCharacter(gpi.getPlayerManager(), gpi.getNetworkId(), ((SelectCharacter)gpi.getPacket()).getCharacterId()); } } } public SWGObject createObject(String template) { return createObject(template, new Location()); } public SWGObject createObject(String template, Location l) { synchronized (objects) { long objectId = getNextObjectId(); SWGObject obj = createObjectFromTemplate(objectId, template); addObjectAttributes(obj, template); obj.setTemplate(template); obj.setLocation(l); objects.put(objectId, obj); return obj; } } private void addObjectAttributes(SWGObject obj, String template) { ObjectData attributes = (ObjectData) clientFac.getInfoFromFile(ClientFactory.formatToSharedFile(template)); // TODO: Remove debug code when error fixed Object objectName = attributes.getAttribute("objectName"); if (objectName != null) obj.setStf((String) objectName); else System.err.println("objectName attribute is null in " + ClientFactory.formatToSharedFile(template)); Object detailStf = attributes.getAttribute("detailedDescription"); if (detailStf != null) obj.setDetailStf((String) detailStf); else System.err.println("detailedDescription attributes is null in " + ClientFactory.formatToSharedFile(template)); } private void zoneInCharacter(PlayerManager playerManager, long netId, long characterId) { Player player = playerManager.getPlayerFromNetworkId(netId); if (player != null) { verifyPlayerObjectsSet(player, characterId); long objId = player.getCreatureObject().getObjectId(); Race race = ((CreatureObject) player.getCreatureObject()).getRace(); Location l = player.getCreatureObject().getLocation(); long time = (long)(ProjectSWG.getCoreTime()/1E3); sendPacket(player, new HeartBeatMessage()); sendPacket(player, new ChatServerStatus(true)); sendPacket(player, new VoiceChatStatus()); sendPacket(player, new ParametersMessage()); sendPacket(player, new ChatOnConnectAvatar()); sendPacket(player, new CmdStartScene(false, objId, race, l, time)); // player.getCreatureObject().createObject(player); CreatureObject creature = (CreatureObject) player.getCreatureObject(); player.sendPacket(new UpdatePvpStatusMessage(creature.getPvpType(), creature.getPvpFactionId(), creature.getObjectId())); creature.createObject(player); } } private void verifyPlayerObjectsSet(Player player, long characterId) { if (player.getCreatureObject() != null && player.getPlayerObject() != null) return; SWGObject creature = objects.get(characterId); if (creature == null) { System.err.println("ObjectManager: Failed to start zone - CreatureObject could not be fetched from database"); throw new NullPointerException("CreatureObject for ID: " + characterId + " cannot be null!"); } player.setCreatureObject(creature); for (SWGObject obj : creature.getChildren()) { if (obj instanceof PlayerObject) { player.setPlayerObject(obj); break; } } } private long getNextObjectId() { synchronized (objects) { return maxObjectId++; } } private String getFirstTemplatePart(String template) { int ind = template.indexOf('/'); if (ind == -1) return ""; return template.substring(0, ind); } private SWGObject createObjectFromTemplate(long objectId, String template) { if (!template.startsWith("object/")) return null; if (!template.endsWith(".iff")) return null; template = template.substring(7, template.length()-7-4); switch (getFirstTemplatePart(template)) { case "creature": return createCreatureObject(objectId, template); case "player": return createPlayerObject(objectId, template); case "tangible": return createTangibleObject(objectId, template); case "intangible": return createIntangibleObject(objectId, template); case "waypoint": return createWaypointObject(objectId, template); case "weapon": return createWeaponObject(objectId, template); case "building": break; case "cell": break; } return null; } private CreatureObject createCreatureObject(long objectId, String template) { return new CreatureObject(objectId); } private PlayerObject createPlayerObject(long objectId, String template) { return new PlayerObject(objectId); } private TangibleObject createTangibleObject(long objectId, String template) { return new TangibleObject(objectId); } private IntangibleObject createIntangibleObject(long objectId, String template) { return new IntangibleObject(objectId); } private WaypointObject createWaypointObject(long objectId, String template) { return new WaypointObject(objectId); } private WeaponObject createWeaponObject(long objectId, String template) { return new WeaponObject(objectId); } }