services.SimulationService.java Source code

Java tutorial

Introduction

Here is the source code for services.SimulationService.java

Source

/*******************************************************************************
 * Copyright (c) 2013 <Project SWG>
 * 
 * This File is part of NGECore2.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * Using NGEngine to work with NGECore2 is making a combined work based on NGEngine. 
 * Therefore all terms and conditions of the GNU Lesser General Public License cover the combination.
 ******************************************************************************/
package services;

import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

import main.NGECore;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;

import com.sleepycat.persist.EntityCursor;

import engine.clientdata.ClientFileManager;
import engine.clientdata.visitors.MeshVisitor;
import engine.clientdata.visitors.PortalVisitor;
import engine.clientdata.visitors.PortalVisitor.Cell;
import engine.clients.Client;
import engine.resources.common.Event;
import engine.resources.common.Mesh3DTriangle;
import engine.resources.common.RGB;
import engine.resources.common.Ray;
import engine.resources.container.Traverser;
import engine.resources.database.ODBCursor;
import engine.resources.objects.SWGObject;
import engine.resources.scene.Planet;
import engine.resources.scene.Point3D;
import engine.resources.scene.Quaternion;
import engine.resources.scene.quadtree.QuadTree;
import engine.resources.service.INetworkDispatch;
import engine.resources.service.INetworkRemoteEvent;
import protocol.swg.CmdStartScene;
import protocol.swg.HeartBeatMessage;
import protocol.swg.ObjControllerMessage;
import protocol.swg.OpenedContainerMessage;
import protocol.swg.UpdateTransformMessage;
import protocol.swg.UpdateTransformWithParentMessage;
import protocol.swg.chat.ChatFriendsListUpdate;
import protocol.swg.chat.ChatOnChangeFriendStatus;
import protocol.swg.chat.ChatOnGetFriendsList;
import protocol.swg.objectControllerObjects.DataTransform;
import protocol.swg.objectControllerObjects.DataTransformWithParent;
import protocol.swg.objectControllerObjects.TargetUpdate;
import resources.objects.building.BuildingObject;
import resources.objects.cell.CellObject;
import resources.objects.creature.CreatureObject;
import resources.objects.group.GroupObject;
import resources.objects.harvester.HarvesterObject;
import resources.objects.installation.InstallationObject;
import resources.objects.player.PlayerObject;
import resources.objects.staticobject.StaticObject;
import resources.objects.tangible.TangibleObject;
import resources.common.*;
import resources.common.collidables.AbstractCollidable;
import resources.datatables.DisplayType;
import resources.datatables.Locomotion;
import resources.datatables.Options;
import resources.datatables.PlayerFlags;
import resources.datatables.Posture;
import services.ai.LairActor;
import services.chat.ChatRoom;
import toxi.geom.Line3D;
import toxi.geom.Ray3D;
import toxi.geom.Vec3D;
import toxi.geom.mesh.TriangleMesh;
import wblut.geom.WB_AABB;
import wblut.geom.WB_AABBNode;
import wblut.geom.WB_AABBTree;
import wblut.geom.WB_Distance;
import wblut.geom.WB_Intersection;
import wblut.geom.WB_Point3d;
import wblut.geom.WB_Ray;
import wblut.geom.WB_Transform;
import wblut.geom.WB_Vector3d;
import wblut.hemesh.HE_Mesh;
import wblut.hemesh.HE_Vertex;
import wblut.math.WB_Epsilon;
import wblut.math.WB_M44;

@SuppressWarnings("unused")

public class SimulationService implements INetworkDispatch {

    Map<String, QuadTree<SWGObject>> quadTrees;
    Map<String, QuadTree<AbstractCollidable>> collidableQuadTrees;
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private NGECore core;
    private Map<String, MeshVisitor> cellMeshes = new ConcurrentHashMap<String, MeshVisitor>();

    public SimulationService(NGECore core) {
        this.core = core;
        TerrainService terrainService = core.terrainService;
        quadTrees = new ConcurrentHashMap<String, QuadTree<SWGObject>>();
        collidableQuadTrees = new ConcurrentHashMap<String, QuadTree<AbstractCollidable>>();

        for (int i = 0; i < core.terrainService.getPlanetList().size(); i++) {
            quadTrees.put(terrainService.getPlanetList().get(i).getName(),
                    new QuadTree<SWGObject>(-8192, -8192, 8192, 8192));
            collidableQuadTrees.put(terrainService.getPlanetList().get(i).getName(),
                    new QuadTree<AbstractCollidable>(-8192, -8192, 8192, 8192));
        }

        core.commandService.registerAlias("afk", "toggleawayfromkeyboard");
    }

    public void insertSnapShotObjects() {
        System.out.println("Inserting snapshot buildings...");
        List<SWGObject> objectList = new ArrayList<SWGObject>(core.objectService.getObjectList().values());
        for (SWGObject obj : objectList) {
            // Buildings are inserted via another method from the odb, so no need to load them into the quadtree as well
            if (obj.getParentId() == 0 && (obj.isInSnapshot() || obj.getAttachment("isBuildout") != null)
                    && obj.getAttachment("buildoutBuilding") == null) {
                add(obj, obj.getPosition().x, obj.getPosition().z);
            }
        }
        System.out.println("Snapshots inserted!");
    }

    public void insertPersistentBuildings() {
        ODBCursor cursor = core.getSWGObjectODB().getCursor();

        while (cursor.hasNext()) {
            Object next = cursor.next();
            if (next == null)
                continue;
            SWGObject building = core.objectService.getObject(((SWGObject) next).getObjectID());
            if (building == null
                    || (!(building instanceof BuildingObject) && !(building instanceof HarvesterObject)))
                continue;
            if (building.getAttachment("hasLoadedServerTemplate") == null)
                core.objectService.loadServerTemplate(building);
            add(building, building.getPosition().x, building.getPosition().z);
        }
        cursor.close();
    }

    public void addCollidable(AbstractCollidable collidable, float x, float y) {
        collidableQuadTrees.get(collidable.getPlanet().getName()).put(x, y, collidable);
    }

    public void removeCollidable(AbstractCollidable collidable, float x, float y) {
        collidableQuadTrees.get(collidable.getPlanet().getName()).remove(x, y, collidable);
    }

    public List<AbstractCollidable> getCollidables(Planet planet, float x, float y, float range) {
        return collidableQuadTrees.get(planet.getName()).get(x, y, range);
    }

    public boolean add(SWGObject object, float x, float z) {
        return add(object, x, z, false);
    }

    public boolean add(SWGObject object, float x, float z, boolean notifyObservers) {
        object.setIsInQuadtree(true);
        boolean success = quadTrees.get(object.getPlanet().getName()).put(x, z, object);
        if (success) {
            @SuppressWarnings("unchecked")
            Vector<SWGObject> childObjects = (Vector<SWGObject>) object.getAttachment("childObjects");
            if (childObjects != null) {
                addChildObjects(object, childObjects);
            }

            if (notifyObservers) {
                Point3D pos = new Point3D(x, 0, z);
                Collection<SWGObject> newAwareObjects = get(object.getPlanet(), x, z, 512);
                cleanAwareObjects(newAwareObjects); // Only objects that are in objectList are considered!!!
                for (Iterator<SWGObject> it = newAwareObjects.iterator(); it.hasNext();) {
                    SWGObject obj = it.next();
                    if ((obj.getAttachment("bigSpawnRange") == null
                            && obj.getWorldPosition().getDistance2D(pos) > 200) || obj == object)
                        continue;
                    //if(!obj.isInSnapshot())
                    //   System.out.println(obj.getTemplate());
                    if (object.getClient() != null)
                        object.makeAware(obj);
                    if (obj.getClient() != null)
                        obj.makeAware(object);

                    //               if (object.getTemplate().contains("dressed_eisley_officer"))
                    //                  System.out.println("ME quadtree add!");
                }
            }
        }
        return success;
    }

    public void cleanAwareObjects(Collection<SWGObject> newAwareObjects) {
        Collection<SWGObject> cleanUpObjects = new ArrayList<SWGObject>();
        for (Iterator<SWGObject> it = newAwareObjects.iterator(); it.hasNext();) {
            SWGObject obj = it.next();
            SWGObject objInList = NGECore.getInstance().objectService.getObject(obj.getObjectID());
            if (objInList == null)
                cleanUpObjects.add(obj);
        }
        newAwareObjects.removeAll(cleanUpObjects);
    }

    public void addChildObjects(SWGObject object, Vector<SWGObject> childObjects) {

        for (SWGObject childObject : childObjects) {
            if (childObject.getAttachment("cellNumber") == null)
                add(childObject, childObject.getWorldPosition().x, childObject.getWorldPosition().z, true);
            else {
                BuildingObject building = (BuildingObject) object;
                CellObject cell = building.getCellByCellNumber((Integer) childObject.getAttachment("cellNumber"));
                if (cell == null)
                    continue;
                cell.add(childObject);
            }

        }

    }

    public boolean checkForObject(int distance, SWGObject value) {
        AtomicBoolean checkObject = new AtomicBoolean();
        core.simulationService
                .get(value.getPlanet(), value.getWorldPosition().x, value.getWorldPosition().z, distance).stream()
                .forEach((objecta) -> {
                    if (objecta instanceof BuildingObject)
                        checkObject.set(true);
                });
        return checkObject.get();
    }

    public Vector<CreatureObject> getAllNearNPCs(int distance, SWGObject value) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService
                .get(value.getPlanet(), value.getWorldPosition().x, value.getWorldPosition().z, distance).stream()
                .forEach((objecta) -> {
                    if (objecta instanceof CreatureObject && objecta != value)
                        foundCreatures.add((CreatureObject) objecta);
                });
        return foundCreatures;
    }

    public Vector<CreatureObject> getAllNearPlayers(int distance, SWGObject value) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService
                .get(value.getPlanet(), value.getWorldPosition().x, value.getWorldPosition().z, distance).stream()
                .forEach((objecta) -> {
                    if (objecta instanceof CreatureObject && objecta != value)
                        if (((CreatureObject) objecta).isPlayer())
                            foundCreatures.add((CreatureObject) objecta);
                });
        return foundCreatures;
    }

    public Vector<CreatureObject> getAllNearPlayers(int distance, Planet planet, Point3D pos) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService.get(planet, pos.x, pos.z, distance).stream().forEach((objecta) -> {
            if (objecta instanceof CreatureObject)
                if (((CreatureObject) objecta).isPlayer())
                    foundCreatures.add((CreatureObject) objecta);
        });
        return foundCreatures;
    }

    public Vector<TangibleObject> getAllNearNonSameFactionTargets(int distance, SWGObject center) {
        Vector<TangibleObject> foundTargets = new Vector<TangibleObject>();
        core.simulationService
                .get(center.getPlanet(), center.getWorldPosition().x, center.getWorldPosition().z, distance)
                .stream().forEach((objecta) -> {
                    if (center.getObjectID() != objecta.getObjectID()) {
                        String centerfaction = "";
                        if (center instanceof CreatureObject)
                            centerfaction = ((CreatureObject) center).getFaction();
                        if (center instanceof InstallationObject)
                            centerfaction = ((InstallationObject) center).getFaction();
                        if (center instanceof TangibleObject)
                            centerfaction = ((TangibleObject) center).getFaction();

                        if (centerfaction.length() > 0 && !(objecta instanceof StaticObject)) {
                            if (objecta.getObjectID() != center.getObjectID()
                                    && NGECore.getInstance().factionService.isFactionEnemy((TangibleObject) objecta,
                                            (TangibleObject) center))
                                foundTargets.add((TangibleObject) objecta);
                        }
                    }
                });
        return foundTargets;
    }

    public Vector<CreatureObject> getAllNearNonSameFactionNPCs(int distance, SWGObject center) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService
                .get(center.getPlanet(), center.getWorldPosition().x, center.getWorldPosition().z, distance)
                .stream().forEach((objecta) -> {
                    if (center.getObjectID() != objecta.getObjectID()) {
                        String centerfaction = "";
                        if (center instanceof CreatureObject)
                            centerfaction = ((CreatureObject) center).getFaction();
                        if (center instanceof InstallationObject)
                            centerfaction = ((InstallationObject) center).getFaction();
                        if (center instanceof TangibleObject)
                            centerfaction = ((TangibleObject) center).getFaction();

                        if (centerfaction.length() > 0 && objecta instanceof CreatureObject) {
                            if (objecta.getObjectID() != center.getObjectID()
                                    && NGECore.getInstance().factionService.isFactionEnemy((CreatureObject) objecta,
                                            (TangibleObject) center))
                                foundCreatures.add((CreatureObject) objecta);
                        }
                    }
                });
        return foundCreatures;
    }

    public Vector<CreatureObject> getAllNearNonSameFactionPlayers(int distance, SWGObject center) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService
                .get(center.getPlanet(), center.getWorldPosition().x, center.getWorldPosition().z, distance)
                .stream().forEach((objecta) -> {
                    if (center.getObjectID() != objecta.getObjectID()) {
                        String centerfaction = "";
                        if (center instanceof CreatureObject)
                            centerfaction = ((CreatureObject) center).getFaction();
                        if (center instanceof InstallationObject)
                            centerfaction = ((InstallationObject) center).getFaction();
                        if (center instanceof TangibleObject)
                            centerfaction = ((TangibleObject) center).getFaction();

                        if (centerfaction.length() > 0 && objecta instanceof CreatureObject) {
                            if (((CreatureObject) objecta).isPlayer()
                                    && objecta.getObjectID() != center.getObjectID()
                                    && NGECore.getInstance().factionService.isFactionEnemy((CreatureObject) objecta,
                                            (TangibleObject) center))
                                foundCreatures.add((CreatureObject) objecta);
                        }
                    }
                });
        return foundCreatures;
    }

    public Vector<CreatureObject> getAllNearSameFactionNPCs(int distance, SWGObject center) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService
                .get(center.getPlanet(), center.getWorldPosition().x, center.getWorldPosition().z, distance)
                .stream().forEach((objecta) -> {

                    String centerfaction = "";
                    if (center instanceof CreatureObject)
                        centerfaction = ((CreatureObject) center).getFaction();
                    if (center instanceof InstallationObject)
                        centerfaction = ((InstallationObject) center).getFaction();
                    if (center instanceof TangibleObject)
                        centerfaction = ((TangibleObject) center).getFaction();

                    if (centerfaction.length() > 0 && objecta instanceof CreatureObject) {
                        if (objecta.getObjectID() != center.getObjectID() && NGECore.getInstance().factionService
                                .isFactionAlly((TangibleObject) objecta, (TangibleObject) center))
                            foundCreatures.add((CreatureObject) objecta);
                    }
                });
        return foundCreatures;
    }

    public Vector<CreatureObject> getAllNearSameFactionPlayers(int distance, Point3D centerPos, Planet planet,
            String factionName) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService.get(planet, centerPos.x, centerPos.z, distance).stream().forEach((objecta) -> {

            if (factionName.length() > 0 && objecta instanceof CreatureObject) {
                if (((CreatureObject) objecta).isPlayer() && NGECore.getInstance().factionService
                        .isFactionAlly(((CreatureObject) objecta).getFaction(), factionName))
                    foundCreatures.add((CreatureObject) objecta);
            }
        });
        return foundCreatures;
    }

    public Vector<CreatureObject> getAllNearSameFactionCreatures(int distance, Point3D centerPos, Planet planet,
            String factionName) {
        Vector<CreatureObject> foundCreatures = new Vector<CreatureObject>();
        core.simulationService.get(planet, centerPos.x, centerPos.z, distance).stream().forEach((objecta) -> {
            if (factionName.length() > 0 && objecta instanceof CreatureObject) {
                if (NGECore.getInstance().factionService.isFactionAlly(((CreatureObject) objecta).getFaction(),
                        factionName))
                    foundCreatures.add((CreatureObject) objecta);
            }
        });
        return foundCreatures;
    }

    public Vector<TangibleObject> getAllNearTANOs(int distance, SWGObject value) {
        Vector<TangibleObject> foundTANOs = new Vector<TangibleObject>();
        core.simulationService
                .get(value.getPlanet(), value.getWorldPosition().x, value.getWorldPosition().z, distance).stream()
                .forEach((objecta) -> {
                    if (objecta instanceof TangibleObject && objecta != value)
                        foundTANOs.add((TangibleObject) objecta);
                });
        return foundTANOs;
    }

    public Vector<TangibleObject> getAllNearNonSameFactionTANOs(int distance, SWGObject center) {
        Vector<TangibleObject> foundTANOs = new Vector<TangibleObject>();
        core.simulationService
                .get(center.getPlanet(), center.getWorldPosition().x, center.getWorldPosition().z, distance)
                .stream().forEach((objecta) -> {

                    //if (objecta.getTemplate().contains("shared_adv_turret_dish_sm_heat")){
                    String centerfaction = "";
                    if (center instanceof CreatureObject)
                        centerfaction = ((CreatureObject) center).getFaction();
                    if (center instanceof InstallationObject)
                        centerfaction = ((InstallationObject) center).getFaction();
                    if (center instanceof TangibleObject)
                        centerfaction = ((TangibleObject) center).getFaction();

                    if (centerfaction.length() > 0 && objecta instanceof TangibleObject
                            && !(objecta instanceof CreatureObject)) {
                        if (objecta.getObjectID() != center.getObjectID() && NGECore.getInstance().factionService
                                .isFactionEnemy((TangibleObject) objecta, (TangibleObject) center))
                            foundTANOs.add((TangibleObject) objecta);
                    }

                });
        return foundTANOs;
    }

    public boolean move(SWGObject object, int oldX, int oldZ, int newX, int newZ) {
        if (quadTrees.get(object.getPlanet().getName()).remove(oldX, oldZ, object)) {
            return quadTrees.get(object.getPlanet().getName()).put(newX, newZ, object);
        }

        return false;
    }

    public boolean move(SWGObject object, float oldX, float oldZ, float newX, float newZ) {
        long startTime = System.nanoTime();
        if (quadTrees.get(object.getPlanet().getName()).remove(oldX, oldZ, object)) {
            boolean success = quadTrees.get(object.getPlanet().getName()).put(newX, newZ, object);
            return success;
        }
        // Note: This sysout keeps getting spammed, so the quadtree remove fails for some reason
        // The NPC does move though
        //System.out.println("Move failed.");
        return false;
    }

    public List<SWGObject> get(Planet planet, float x, float z, int range) {
        List<SWGObject> list = quadTrees.get(planet.getName()).get((int) x, (int) z, range);
        return list;
    }

    public boolean remove(SWGObject object, float x, float z) {
        return remove(object, x, z, false);
    }

    public boolean remove(SWGObject object, float x, float z, boolean notifyObservers) {
        if (object == null || !object.isInQuadtree()) {
            return false;
        }

        boolean success = quadTrees.get(object.getPlanet().getName()).remove(x, z, object);
        object.setIsInQuadtree(success);
        if (success && notifyObservers) {
            HashSet<Client> oldObservers = new HashSet<Client>(object.getObservers());
            for (Iterator<Client> it = oldObservers.iterator(); it.hasNext();) {
                Client observerClient = it.next();
                if (observerClient.getParent() != null) {
                    observerClient.getParent().makeUnaware(object);

                    // Experimental until engine fixed
                    if (observerClient.getParent().getAwareObjects().contains(object)) {

                        object.viewChildren(observerClient.getParent(), false, false, new Traverser() {
                            @Override
                            public void process(SWGObject object) {
                                if (object == null)
                                    return;
                                if (object.getClient() != null)
                                    object.makeUnaware(observerClient.getParent());
                                observerClient.getParent().makeUnaware(object);
                            }
                        });
                        if (!object.isInSnapshot())
                            object.sendDestroy(observerClient);
                        object.removeObserver(observerClient.getParent());
                        observerClient.getParent().getAwareObjects().remove(object);
                    }
                    // Experimental until engine fixed
                }
            }
        }
        return success;
    }

    @Override
    public void insertOpcodes(Map<Integer, INetworkRemoteEvent> swgOpcodes,
            Map<Integer, INetworkRemoteEvent> objControllerOpcodes) {

        objControllerOpcodes.put(ObjControllerOpcodes.DATA_TRANSFORM, new INetworkRemoteEvent() {

            @Override
            public void handlePacket(IoSession session, IoBuffer data) throws Exception {

                data.order(ByteOrder.LITTLE_ENDIAN);

                DataTransform dataTransform = new DataTransform();
                dataTransform.deserialize(data);
                //System.out.println("Movement Counter: " + dataTransform.getMovementCounter());
                Client client = core.getClient(session);

                if (client == null) {
                    System.out.println("NULL Client");
                    return;
                }

                if (client.getParent() == null) {
                    System.out.println("NULL Object");
                    return;
                }

                CreatureObject creature = (CreatureObject) client.getParent();
                if (creature.getPosture() == Posture.Dead || creature.getPosture() == Posture.Incapacitated)
                    return;

                CreatureObject object = creature;

                if (core.mountService.isMounted(creature)
                        && creature.getObjectID() == ((CreatureObject) creature.getContainer()).getOwnerId()) {
                    object = (CreatureObject) object.getContainer();
                }

                Point3D newPos;
                Point3D oldPos;

                synchronized (object.getMutex()) {
                    newPos = new Point3D(dataTransform.getXPosition(), dataTransform.getYPosition(),
                            dataTransform.getZPosition());
                    if (Float.isNaN(newPos.x) || Float.isNaN(newPos.y) || Float.isNaN(newPos.z))
                        return;
                    oldPos = object.getPosition();
                }

                if (object instanceof CreatureObject && object.getOption(Options.MOUNT)) {
                    if (!checkLineOfSight(object, newPos)) {
                        newPos = oldPos;
                    }
                }

                synchronized (object.getMutex()) {
                    //Collection<Client> oldObservers = object.getObservers();
                    //Collection<Client> newObservers = new HashSet<Client>();
                    if (object.getContainer() == null)
                        move(object, oldPos.x, oldPos.z, newPos.x, newPos.z);
                    Quaternion newOrientation = new Quaternion(dataTransform.getWOrientation(),
                            dataTransform.getXOrientation(), dataTransform.getYOrientation(),
                            dataTransform.getZOrientation());
                    object.setPosition(newPos);
                    creature.setPosition(newPos);
                    object.setOrientation(newOrientation);
                    creature.setOrientation(newOrientation);
                    object.setMovementCounter(dataTransform.getMovementCounter());
                    creature.setMovementCounter(dataTransform.getMovementCounter());
                }

                synchronized (creature.getMutex()) {
                    if (dataTransform.getSpeed() > 0.0f) {
                        switch (creature.getLocomotion()) {
                        case Locomotion.Prone:
                            creature.setLocomotion(Locomotion.Crawling);
                            break;
                        case Locomotion.ClimbingStationary:
                            creature.setLocomotion(Locomotion.Climbing);
                            break;
                        case Locomotion.Standing:
                        case Locomotion.Running:
                        case Locomotion.Walking:
                            if (dataTransform.getSpeed() >= (creature.getRunSpeed()
                                    * (creature.getSpeedMultiplierBase() + creature.getSpeedMultiplierMod()))) {
                                creature.setLocomotion(Locomotion.Running);
                            } else {
                                creature.setLocomotion(Locomotion.Walking);
                            }

                            break;
                        case Locomotion.Sneaking:
                        case Locomotion.CrouchSneaking:
                        case Locomotion.CrouchWalking:
                            if (dataTransform.getSpeed() >= (creature.getRunSpeed()
                                    * (creature.getSpeedMultiplierBase() + creature.getSpeedMultiplierMod()))) {
                                creature.setLocomotion(Locomotion.CrouchSneaking);
                            } else {
                                creature.setLocomotion(Locomotion.CrouchWalking);
                            }

                            break;
                        }
                    } else {
                        switch (creature.getLocomotion()) {
                        case Locomotion.Crawling:
                            creature.setLocomotion(Locomotion.Prone);
                            break;
                        case Locomotion.Climbing:
                            creature.setLocomotion(Locomotion.ClimbingStationary);
                            break;
                        case Locomotion.Running:
                        case Locomotion.Walking:
                            creature.setLocomotion(Locomotion.Standing);
                            break;
                        case Locomotion.CrouchSneaking:
                        case Locomotion.CrouchWalking:
                            creature.setLocomotion(Locomotion.Sneaking);
                            break;
                        }
                    }
                }

                if (object.getContainer() != null) {
                    object.getContainer()._remove(object);
                    add(object, newPos.x, newPos.z);
                }

                //object.setParentId(0);
                //object.setParent(null);
                //   System.out.println("Parsed Height: " + core.terrainService.getHeight(object.getPlanetId(), dataTransform.getXPosition(), dataTransform.getZPosition())
                //       + " should be: " + dataTransform.getYPosition());
                UpdateTransformMessage utm = new UpdateTransformMessage(object.getObjectID(),
                        dataTransform.getTransformedX(), dataTransform.getTransformedY(),
                        dataTransform.getTransformedZ(), dataTransform.getMovementCounter(),
                        (byte) dataTransform.getMovementAngle(), dataTransform.getSpeed());
                object.notifyObservers(utm, false);

                List<SWGObject> newAwareObjects = get(creature.getPlanet(), newPos.x, newPos.z, 512);
                ArrayList<SWGObject> oldAwareObjects = new ArrayList<SWGObject>(creature.getAwareObjects());
                @SuppressWarnings("unchecked")
                Collection<SWGObject> updateAwareObjects = CollectionUtils.intersection(oldAwareObjects,
                        newAwareObjects);

                for (int i = 0; i < oldAwareObjects.size(); i++) {
                    SWGObject obj = oldAwareObjects.get(i);
                    if (!updateAwareObjects.contains(obj) && obj != creature
                            && obj.getWorldPosition().getDistance2D(newPos) > 200
                            && obj.isInQuadtree() /*&& obj.getParentId() == 0*/) {
                        if (obj.getAttachment("bigSpawnRange") != null
                                && obj.getWorldPosition().getDistance2D(newPos) < 512)
                            continue;
                        creature.makeUnaware(obj);
                        if (obj.getClient() != null)
                            obj.makeUnaware(creature);
                    } else if (obj != creature && obj.getWorldPosition().getDistance2D(newPos) > 200
                            && obj.isInQuadtree() && obj.getAttachment("bigSpawnRange") == null) {
                        creature.makeUnaware(obj);
                        if (obj.getClient() != null)
                            obj.makeUnaware(creature);
                    }
                }

                for (int i = 0; i < newAwareObjects.size(); i++) {
                    SWGObject obj = newAwareObjects.get(i);
                    //System.out.println(obj.getTemplate());
                    if (!updateAwareObjects.contains(obj) && obj != creature
                            && !creature.getAwareObjects().contains(obj) && obj.getContainer() != creature
                            && obj.isInQuadtree()) {
                        if (obj.getAttachment("bigSpawnRange") == null
                                && obj.getWorldPosition().getDistance2D(newPos) > 200)
                            continue;
                        creature.makeAware(obj);
                        if (obj.getClient() != null)
                            obj.makeAware(creature);
                    }
                }

                checkForCollidables(object);
                object.setAttachment("lastValidPosition", object.getPosition());
                MoveEvent event = new MoveEvent();
                event.object = object;
                object.getEventBus().publish(event);

            }

        });

        objControllerOpcodes.put(ObjControllerOpcodes.DATA_TRANSFORM_WITH_PARENT, new INetworkRemoteEvent() {

            @Override
            public void handlePacket(IoSession session, IoBuffer data) throws Exception {

                data.order(ByteOrder.LITTLE_ENDIAN);

                DataTransformWithParent dataTransform = new DataTransformWithParent();
                dataTransform.deserialize(data);
                Client client = core.getClient(session);

                if (core.objectService.getObject(dataTransform.getCellId()) == null)
                    return;

                SWGObject parent = core.objectService.getObject(dataTransform.getCellId());

                if (client == null) {
                    System.out.println("NULL Client");
                    return;
                }

                if (client.getParent() == null) {
                    System.out.println("NULL Object");
                    return;
                }

                CreatureObject object = (CreatureObject) client.getParent();
                if (object.getPosture() == Posture.Dead || object.getPosture() == Posture.Incapacitated)
                    return;

                if (core.mountService.isMounted(object)) {
                    object.sendSystemMessage(OutOfBand.ProsePackage("@pet_menu:cant_mount"), DisplayType.Broadcast);
                    core.mountService.dismount(object, (CreatureObject) object.getContainer());
                }

                Point3D newPos = new Point3D(dataTransform.getXPosition(), dataTransform.getYPosition(),
                        dataTransform.getZPosition());
                newPos.setCell((CellObject) parent);
                if (Float.isNaN(newPos.x) || Float.isNaN(newPos.y) || Float.isNaN(newPos.z))
                    return;
                Point3D oldPos = object.getPosition();
                Quaternion newOrientation = new Quaternion(dataTransform.getWOrientation(),
                        dataTransform.getXOrientation(), dataTransform.getYOrientation(),
                        dataTransform.getZOrientation());

                UpdateTransformWithParentMessage utm = new UpdateTransformWithParentMessage(object.getObjectID(),
                        dataTransform.getCellId(), dataTransform.getTransformedX(), dataTransform.getTransformedY(),
                        dataTransform.getTransformedZ(), dataTransform.getMovementCounter(),
                        (byte) dataTransform.getMovementAngle(), dataTransform.getSpeed());

                if (object.getContainer() != parent) {
                    remove(object, oldPos.x, oldPos.z);
                    if (object.getContainer() != null)
                        object.getContainer()._remove(object);
                    if (object.getClient() == null)
                        System.err.println("Client is null!  This is a very strange error.");
                    //if (object.getClient() != null && object.getClient().isGM() && parent != null && parent instanceof CellObject && parent.getContainer() != null)
                    //object.sendSystemMessage("BuildingId - Dec: " + parent.getContainer().getObjectID() + " Hex: " + Long.toHexString(parent.getContainer().getObjectID()) + " CellNumber: " + ((CellObject) parent).getCellNumber(), DisplayType.Broadcast);
                    parent._add(object);
                }
                object.setPosition(newPos);
                object.setOrientation(newOrientation);
                object.setMovementCounter(dataTransform.getMovementCounter());
                object.notifyObservers(utm, false);

                checkForCollidables(object);
                object.setAttachment("lastValidPosition", object.getPosition());

                synchronized (object.getMutex()) {
                    if (dataTransform.getSpeed() > 0.0f) {
                        switch (object.getLocomotion()) {
                        case Locomotion.Prone:
                            object.setLocomotion(Locomotion.Crawling);
                            break;
                        case Locomotion.ClimbingStationary:
                            object.setLocomotion(Locomotion.Climbing);
                            break;
                        case Locomotion.Standing:
                        case Locomotion.Running:
                        case Locomotion.Walking:
                            if (dataTransform.getSpeed() >= (object.getRunSpeed()
                                    * (object.getSpeedMultiplierBase() + object.getSpeedMultiplierMod()))) {
                                object.setLocomotion(Locomotion.Running);
                            } else {
                                object.setLocomotion(Locomotion.Walking);
                            }

                            break;
                        case Locomotion.Sneaking:
                        case Locomotion.CrouchSneaking:
                        case Locomotion.CrouchWalking:
                            if (dataTransform.getSpeed() >= (object.getRunSpeed()
                                    * (object.getSpeedMultiplierBase() + object.getSpeedMultiplierMod()))) {
                                object.setLocomotion(Locomotion.CrouchSneaking);
                            } else {
                                object.setLocomotion(Locomotion.CrouchWalking);
                            }

                            break;
                        }
                    } else {
                        switch (object.getLocomotion()) {
                        case Locomotion.Crawling:
                            object.setLocomotion(Locomotion.Prone);
                            break;
                        case Locomotion.Climbing:
                            object.setLocomotion(Locomotion.ClimbingStationary);
                            break;
                        case Locomotion.Running:
                        case Locomotion.Walking:
                            object.setLocomotion(Locomotion.Standing);
                            break;
                        case Locomotion.CrouchSneaking:
                        case Locomotion.CrouchWalking:
                            object.setLocomotion(Locomotion.Sneaking);
                            break;
                        }
                    }
                }
            }

        });

        swgOpcodes.put(Opcodes.ClientOpenContainerMessage, new INetworkRemoteEvent() {

            @Override
            public void handlePacket(IoSession session, IoBuffer data) throws Exception {
                System.out.println("Open Container Request");
            }

        });

        objControllerOpcodes.put(ObjControllerOpcodes.lookAtTarget, new INetworkRemoteEvent() {

            @Override
            public void handlePacket(IoSession session, IoBuffer data) throws Exception {

                data.order(ByteOrder.LITTLE_ENDIAN);

                Client client = core.getClient(session);

                if (client == null) {
                    System.out.println("NULL Client");
                    return;
                }

                if (client.getParent() == null) {
                    System.out.println("NULL Object");
                    return;
                }
                CreatureObject object = (CreatureObject) client.getParent();

                TargetUpdate targetUpdate = new TargetUpdate();
                targetUpdate.deserialize(data);

                object.setLookAtTarget(targetUpdate.getTargetId());

            }

        });

        objControllerOpcodes.put(ObjControllerOpcodes.intendedTarget, new INetworkRemoteEvent() {

            @Override
            public void handlePacket(IoSession session, IoBuffer data) throws Exception {

                data.order(ByteOrder.LITTLE_ENDIAN);

                Client client = core.getClient(session);

                if (client == null) {
                    System.out.println("NULL Client");
                    return;
                }

                if (client.getParent() == null) {
                    System.out.println("NULL Object");
                    return;
                }
                CreatureObject object = (CreatureObject) client.getParent();

                TargetUpdate targetUpdate = new TargetUpdate();
                targetUpdate.deserialize(data);

                object.setIntendedTarget(targetUpdate.getTargetId());

            }

        });

    }

    public void moveObject(SWGObject object, Point3D newPosition, Quaternion newOrientation, int movementCounter,
            float speed, CellObject cell) {

        if (Float.isNaN(newPosition.x) || Float.isNaN(newPosition.y) || Float.isNaN(newPosition.z))
            return;

        if (object instanceof CreatureObject) {
            CreatureObject cre = (CreatureObject) object;
            if (cre.getPosture() == Posture.Dead || cre.getPosture() == Posture.Incapacitated)
                return;
        }

        if (cell == null) {

            Point3D oldPos;
            synchronized (object.getMutex()) {
                oldPos = object.getPosition();
                if (object.getContainer() == null)
                    move(object, oldPos.x, oldPos.z, newPosition.x, newPosition.z);
                object.setPosition(newPosition);
                object.setOrientation(newOrientation);
                object.setMovementCounter(movementCounter + 1);
            }
            if (object.getContainer() != null && newPosition != oldPos) {
                object.getContainer()._remove(object);
                add(object, newPosition.x, newPosition.z);
            }

            if (object.getPlanet().getName().equals("talus") && object.getTemplate().contains("stormtrooper")) {
                //            float xx = object.getWorldPosition().x - newPosition.x;
                //            float zz = object.getWorldPosition().z - newPosition.z;
                //            float diff = (float) Math.sqrt(xx*xx+zz*zz);
                //            System.out.println(" ((CreatureObject)object).getSpeedMultiplierBase());: " + ((CreatureObject)object).getSpeedMultiplierBase());
                //            System.out.println(" ((CreatureObject)object).getSpeedMultiplierMod());: " + ((CreatureObject)object).getSpeedMultiplierMod());
                //   
            }

            UpdateTransformMessage utm = new UpdateTransformMessage(object.getObjectID(),
                    (short) (newPosition.x * 4 + 0.5), (short) (newPosition.y * 4 + 0.5),
                    (short) (newPosition.z * 4 + 0.5), movementCounter + 1, getSpecialDirection(newOrientation),
                    speed);

            List<SWGObject> newAwareObjects = get(object.getPlanet(), newPosition.x, newPosition.z, 512);
            ArrayList<SWGObject> oldAwareObjects = new ArrayList<SWGObject>(object.getAwareObjects());
            @SuppressWarnings("unchecked")
            Collection<SWGObject> updateAwareObjects = CollectionUtils.intersection(oldAwareObjects,
                    newAwareObjects);
            object.notifyObservers(utm, false);

            for (int i = 0; i < oldAwareObjects.size(); i++) {
                SWGObject obj = oldAwareObjects.get(i);
                if (!updateAwareObjects.contains(obj) && obj != object
                        && obj.getWorldPosition().getDistance2D(newPosition) > 200
                        && obj.isInQuadtree() /*&& obj.getParentId() == 0*/) {
                    if (obj.getAttachment("bigSpawnRange") != null
                            && obj.getWorldPosition().getDistance2D(newPosition) < 512)
                        continue;
                    object.makeUnaware(obj);
                    if (obj.getClient() != null)
                        obj.makeUnaware(object);
                } else if (obj != object && obj.getWorldPosition().getDistance2D(newPosition) > 200
                        && obj.isInQuadtree() && obj.getAttachment("bigSpawnRange") == null) {
                    object.makeUnaware(obj);
                    if (obj.getClient() != null)
                        obj.makeUnaware(object);
                }
            }
            for (int i = 0; i < newAwareObjects.size(); i++) {
                SWGObject obj = newAwareObjects.get(i);
                //System.out.println(obj.getTemplate());
                if (!updateAwareObjects.contains(obj) && obj != object && !object.getAwareObjects().contains(obj)
                        && obj.getContainer() != object && obj.isInQuadtree()) {
                    if (obj.getAttachment("bigSpawnRange") == null
                            && obj.getWorldPosition().getDistance2D(newPosition) > 200)
                        continue;
                    object.makeAware(obj);
                    if (obj.getClient() != null)
                        obj.makeAware(object);
                }
            }

            checkForCollidables(object);
            MoveEvent event = new MoveEvent();
            event.object = object;
            object.getEventBus().publish(event);

        } else {

            newPosition.setCell(cell);
            Point3D oldPos = object.getPosition();
            object.setPosition(newPosition);
            object.setOrientation(newOrientation);
            object.setMovementCounter(movementCounter + 1);

            UpdateTransformWithParentMessage utm = new UpdateTransformWithParentMessage(object.getObjectID(),
                    cell.getObjectID(), (short) (newPosition.x * 8 + 0.5), (short) (newPosition.y * 8 + 0.5),
                    (short) (newPosition.z * 8 + 0.5), movementCounter + 1, getSpecialDirection(newOrientation),
                    speed);

            if (object.getContainer() != cell) {
                remove(object, oldPos.x, oldPos.z);
                if (object.getContainer() != null)
                    object.getContainer()._remove(object);
                cell._add(object);
            }
            object.notifyObservers(utm, false);

            checkForCollidables(object);

        }

    }

    public byte getSpecialDirection(Quaternion orientation) {
        byte movementAngle = (byte) 0.0f;
        float wOrient = orientation.w;
        float yOrient = orientation.y;
        float sq = (float) Math.sqrt(1 - (orientation.w * orientation.w));

        if (sq != 0) {
            if (orientation.w > 0 && orientation.y < 0) {
                wOrient *= -1;
                yOrient *= -1;
            }
            movementAngle = (byte) ((yOrient / sq) * (2 * Math.acos(wOrient) / 0.06283f));
        }

        return movementAngle;
    }

    @Override
    public void shutdown() {
        // TODO Auto-generated method stub

    }

    /*public WB_AABBTree getAABBTree(SWGObject object, int collisionBlockFlag) {
           
       if(object.getMeshVisitor() == null || object.getTemplateData() == null) {
     System.out.println("NULL Mesh Visitor for: " + object.getTemplate());
     return null;
       }
           
       if(object.getTemplateData().getAttribute("collisionActionBlockFlags") != null) {
     int bit = (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags") & collisionBlockFlag;
     //if(bit == (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags"))
     //   return null;
       }
           
       Point3D position = object.getPosition();
       HE_Mesh mesh = object.getMeshVisitor().createMesh();
            
       if(mesh == null)
     return null;
        
       float angle = (float) (object.getRadians() * (180 / Math.PI));
       System.out.println("Angle: " + angle);
        
       Quaternion quat = object.getOrientation();
           
       //WB_Transform transform = new WB_Transform();
       //transform.addRotateZ(object.getRadians());
           
       //mesh = mesh.transform(transform);
        
       //mesh = mesh.move(position.x, position.z, position.y);
        
           
       WB_AABBTree aabbTree = new WB_AABBTree(mesh, mesh.numberOfFaces());
       return aabbTree;
    }*/

    public Ray convertRayToModelSpace(Point3D origin, Point3D end, SWGObject object) {

        Point3D position = object.getPosition();

        WB_M44 translateMatrix = new WB_M44(1, 0, 0, position.x, 0, 1, 0, position.y, 0, 0, 1, position.z, 0, 0, 0,
                1);

        float radians = object.getRadians();
        float sin = (float) Math.sin(radians);
        float cos = (float) Math.cos(radians);

        WB_M44 rotationMatrix = new WB_M44(cos, 0, sin, 0, 0, 1, 0, 0, -sin, 0, cos, 0, 0, 0, 0, 1);

        WB_M44 modelSpace = null;
        try {
            modelSpace = translateMatrix.mult(rotationMatrix).inverse();
        } catch (Exception ex) {
            // It's usually a bank terminal causing this
            //System.out.println("The object " + object.getTemplate() + " at x:" + object.getWorldPosition().x + " z:" + object.getWorldPosition().z + " causes a problem during modelspaceconversion. Can be safely ignored.");
            if (modelSpace == null)
                return new Ray(origin, new Vector3D(0, 0, 0));
        }

        float originX = (float) (modelSpace.m11 * origin.x + modelSpace.m12 * origin.y + modelSpace.m13 * origin.z
                + modelSpace.m14);
        float originY = (float) (modelSpace.m21 * origin.x + modelSpace.m22 * origin.y + modelSpace.m23 * origin.z
                + modelSpace.m24);
        float originZ = (float) (modelSpace.m31 * origin.x + modelSpace.m32 * origin.y + modelSpace.m33 * origin.z
                + modelSpace.m34);

        origin = new Point3D(originX, originY, originZ);

        float endX = (float) (modelSpace.m11 * end.x + modelSpace.m12 * end.y + modelSpace.m13 * end.z
                + modelSpace.m14);
        float endY = (float) (modelSpace.m21 * end.x + modelSpace.m22 * end.y + modelSpace.m23 * end.z
                + modelSpace.m24);
        float endZ = (float) (modelSpace.m31 * end.x + modelSpace.m32 * end.y + modelSpace.m33 * end.z
                + modelSpace.m34);

        end = new Point3D(endX, endY, endZ);
        Vector3D direction = new Vector3D(end.x - origin.x, end.y - origin.y, end.z - origin.z);
        if (direction.getX() > 0 && direction.getY() > 0 && direction.getZ() > 0)
            direction.normalize();

        return new Ray(origin, direction);

    }

    public Point3D convertPointToModelSpace(Point3D point, SWGObject object) {

        Point3D position = object.getPosition();

        WB_M44 translateMatrix = new WB_M44(1, 0, 0, position.x, 0, 1, 0, position.y, 0, 0, 1, position.z, 0, 0, 0,
                1);

        float radians = object.getRadians();
        float sin = (float) Math.sin(radians);
        float cos = (float) Math.cos(radians);

        WB_M44 rotationMatrix = new WB_M44(cos, 0, sin, 0, 0, 1, 0, 0, -sin, 0, cos, 0, 0, 0, 0, 1);

        WB_M44 modelSpace = translateMatrix.mult(rotationMatrix).inverse();

        float x = (float) (modelSpace.m11 * point.x + modelSpace.m12 * point.y + modelSpace.m13 * point.z
                + modelSpace.m14);
        float y = (float) (modelSpace.m21 * point.x + modelSpace.m22 * point.y + modelSpace.m23 * point.z
                + modelSpace.m24);
        float z = (float) (modelSpace.m31 * point.x + modelSpace.m32 * point.y + modelSpace.m33 * point.z
                + modelSpace.m34);

        return new Point3D(x, y, z);

    }

    public Point3D convertModelSpaceToPoint(Point3D point, SWGObject object) {

        Point3D position = object.getPosition();
        WB_M44 translateMatrix = new WB_M44(1, 0, 0, position.x, 0, 1, 0, position.y, 0, 0, 1, position.z, 0, 0, 0,
                1);

        float radians = object.getRadians();
        float sin = (float) Math.sin(radians);
        float cos = (float) Math.cos(radians);

        WB_M44 rotationMatrix = new WB_M44(cos, 0, sin, 0, 0, 1, 0, 0, -sin, 0, cos, 0, 0, 0, 0, 1); //non-inverse matrix

        WB_M44 modelSpace = translateMatrix.mult(rotationMatrix);

        float x = (float) (modelSpace.m11 * point.x + modelSpace.m12 * point.y + modelSpace.m13 * point.z
                + modelSpace.m14);
        float y = (float) (modelSpace.m21 * point.x + modelSpace.m22 * point.y + modelSpace.m23 * point.z
                + modelSpace.m24);
        float z = (float) (modelSpace.m31 * point.x + modelSpace.m32 * point.y + modelSpace.m33 * point.z
                + modelSpace.m34);

        return new Point3D(x, y, z);

    }

    /*
     * Moved this to ConnectionService which will disconnect them
     * from the server if they don't send packets for 5 minutes or more
     * like on live.
     * 
     * We had significant issues with client nulls due to us taking
     * client disconnect requests too seriously.  It has a weird tendency
     * to bluff and send a disconnect packet when it's not disconnecting
     * and continues sending packets.
     */
    public void handleDisconnect(final IoSession session) {
        final Client client = core.getClient(session);

        if (client == null)
            return;

        if (client.getParent() == null)
            return;

        final CreatureObject object = (CreatureObject) client.getParent();
        SWGObject container = object.getContainer();
        PlayerObject ghost = (PlayerObject) object.getSlottedObject("ghost");

        if (object.getAttachment("proposer") != null)
            object.setAttachment("proposer", null);

        final long objectId = object.getObjectID();

        if (!ghost.isSet(PlayerFlags.LD))
            ghost.toggleFlag(PlayerFlags.LD);

        try {
            if (core.mountService.isMounted(object)) {
                core.mountService.dismount(object, (CreatureObject) container);
            }

            core.mountService.storeAll(object);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            for (Integer roomId : ghost.getJoinedChatChannels()) {
                ChatRoom room = core.chatService.getChatRoom(roomId.intValue());

                if (room != null) {
                    core.chatService.leaveChatRoom(object, roomId.intValue(), false);
                } else {
                    // work-around for any channels that may have been deleted, or only spawn on server startup, that were added to the joined channels
                    ghost.removeChannel(roomId);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        ScheduledFuture<?> disconnectTask = scheduler.schedule(new Runnable() {
            @Override
            public void run() {
                SWGObject object = core.objectService.getObject(objectId);

                if (object.getAttachment("disconnectTask") != null) {
                    core.connectionService.disconnect(client);
                    /*
                    try {
                       Thread.sleep(900000)
                    } catch (Exception e) {
                       e.printStackTrace();
                    }
                        
                    // If connectionService fails for some reason, this will call disconnect again after 15 mins.
                    // This should never actually be needed though:
                        
                    try {
                       if (object != null && object.getAttachment("disconnectTask") != null && client != null) {
                          core.connectionService.disconnect(client);
                       }
                    } catch (Exception e) {
                       System.err.println("ConnectionService:disconnect(): Error disconnecting client.");
                       e.printStackTrace();
                    }
                    */
                }
            }
        }, 120, TimeUnit.SECONDS);

        core.removeClient(session);

        object.setAttachment("disconnectTask", disconnectTask);

    }

    public void handleZoneIn(Client client) {

        if (client.getParent() == null)
            return;

        CreatureObject object = (CreatureObject) client.getParent();
        Quaternion orientation = object.getOrientation();
        Point3D position = object.getPosition();

        Point3D pos = object.getWorldPosition();

        if (object.getParentId() != 0) {
            Collection<SWGObject> newAwareObjects = get(object.getPlanet(), pos.x, pos.z, 512);
            for (Iterator<SWGObject> it = newAwareObjects.iterator(); it.hasNext();) {
                SWGObject obj = it.next();
                if (obj.getAttachment("bigSpawnRange") == null && obj.getWorldPosition().getDistance2D(pos) > 200)
                    continue;
                //System.out.println(obj.getTemplate());
                object.makeAware(obj);
                if (obj.getClient() != null)
                    obj.makeAware(object);
            }
        } else {
            add(object, pos.x, pos.z, true);
        }

        PlayerObject ghost = (PlayerObject) object.getSlottedObject("ghost");

        core.weatherService.sendWeather(object);

        //core.chatService.joinChatRoom(object.getCustomName().toLowerCase(), "SWG." + core.getGalaxyName() + "." + object.getPlanet().getName());

        if (!object.hasSkill(ghost.getProfessionWheelPosition())) {
            object.showFlyText(OutOfBand.ProsePackage("@cbt_spam:skill_up"), 2.5f, new RGB(154, 205, 50), 0, true);
            object.playEffectObject("clienteffect/skill_granted.cef", "");
            object.playMusic("sound/music_acq_bountyhunter.snd");
            core.skillService.addSkill(object, ghost.getProfessionWheelPosition());
        }

        if (object.getGroupId() != 0 && core.objectService.getObject(object.getGroupId()) instanceof GroupObject)
            object.makeAware(core.objectService.getObject(object.getGroupId()));

        if (object.getPosture() == Posture.Dead)
            core.playerService.sendCloningWindow(object, false);

        ChatRoom zoneRoom = core.chatService.getChatRoomByAddress(
                "SWG." + core.getGalaxyName() + "." + object.getPlanet().getName() + ".Planet");
        if (zoneRoom != null) {
            String chatName = object.getCustomName().toLowerCase();

            if (chatName.contains(" "))
                chatName = chatName.split(" ")[0];

            if (!zoneRoom.getUserList().contains(chatName)) {
                core.chatService.joinChatRoom(chatName, zoneRoom.getRoomId(), true);
            }
        }

    }

    public void transferToPlanet(SWGObject object, Planet planet, Point3D newPos, Quaternion newOrientation,
            SWGObject newParent) {

        if (planet == null)
            return;

        Client client = object.getClient();

        if (client == null)
            return;

        IoSession session = client.getSession();

        if (session == null)
            return;

        Point3D position = object.getPosition();

        if (object.getParentId() == 0 && object.getContainer() == null) {
            remove(object, position.x, position.z, true);
        } else {
            object.getContainer().remove(object);
        }

        /*HashSet<Client> oldObservers = new HashSet<Client>(object.getObservers());
            
        for(Client observerClient : oldObservers) {
           if(observerClient.getParent() != null) {
        observerClient.getParent().makeUnaware(object);
           }
        }*/

        synchronized (object.getMutex()) {
            object.getAwareObjects().removeAll(object.getAwareObjects());
        }

        object.setPlanet(planet);
        object.setPlanetId(planet.getID());
        object.setPosition(newPos);
        object.setOrientation(newOrientation);

        if (newParent != null && newParent instanceof CellObject)
            newParent._add(object);

        HeartBeatMessage heartBeat = new HeartBeatMessage();
        session.write(heartBeat.serialize());

        CmdStartScene startScene = new CmdStartScene((byte) 0, object.getObjectID(), object.getPlanet().getPath(),
                object.getTemplate(), newPos.x, newPos.y, newPos.z, core.getGalacticTime() / 1000,
                object.getRadians());
        session.write(startScene.serialize());

        handleZoneIn(client);
        object.makeAware(object);

    }

    public void openContainer(SWGObject requester, SWGObject container) {

        if (container.getPermissions().canView(requester, container)) {
            OpenedContainerMessage opm = new OpenedContainerMessage(container.getObjectID());
            if (requester.getClient() != null && requester.getClient().getSession() != null
                    && !(container instanceof CreatureObject)) {
                requester.getClient().getSession().write(opm.serialize());
            }
        }
    }

    public void transform(TangibleObject obj, Point3D position) {
        Point3D oldPosition = obj.getPosition();
        Point3D newPosition = new Point3D(oldPosition.x + position.x, oldPosition.y + position.y,
                oldPosition.z + position.z);

        teleport(obj, newPosition, obj.getOrientation(), obj.getParentId());
    }

    public void transform(SWGObject obj, float rotation, Point3D axis) {
        rotation *= (Math.PI / 180);

        Quaternion oldRotation = obj.getOrientation();
        Quaternion newRotation = resources.common.MathUtilities.rotateQuaternion(oldRotation, rotation, axis);

        teleport(obj, obj.getPosition(), newRotation, obj.getParentId());
    }

    public void rotateToFaceTarget(SWGObject object, SWGObject target) {
        float radians = (float) (((float) Math.atan2(target.getPosition().z - object.getPosition().z,
                target.getPosition().x - object.getPosition().x)) - object.getRadians());
        transform(object, radians, object.getPosition());
    }

    public void faceTarget(SWGObject object, SWGObject target) {
        float direction = (float) Math.atan2(target.getWorldPosition().x - object.getWorldPosition().x,
                target.getWorldPosition().z - object.getWorldPosition().z);

        if (direction < 0) {
            direction = (float) (2 * Math.PI + direction);
        }

        if (Math.abs(direction - object.getRadians()) < 0.05) {
            return;
        }

        Quaternion quaternion = new Quaternion((float) Math.cos(direction / 2), 0, (float) Math.sin(direction / 2),
                0);

        if (quaternion.y < 0.0f && quaternion.w > 0.0f) {
            quaternion.y *= -1;
            quaternion.w *= -1;
        }

        if (object.getContainer() instanceof CellObject) {
            NGECore.getInstance().simulationService.moveObject(object, object.getPosition(), quaternion,
                    object.getMovementCounter(), 0, (CellObject) object.getContainer());
        } else {
            NGECore.getInstance().simulationService.moveObject(object, object.getPosition(), quaternion,
                    object.getMovementCounter(), 0, null);
        }
    }

    public void teleport(SWGObject obj, Point3D position, Quaternion orientation, long cellId) {

        if (obj.getPosition().getDistance2D(position) > 150) {
            if (cellId != 0)
                transferToPlanet(obj, obj.getPlanet(), position, orientation, core.objectService.getObject(cellId));
            else
                transferToPlanet(obj, obj.getPlanet(), position, orientation, null);
            return;
        }

        if (cellId == 0) {
            if (position.x >= -8192 && position.x <= 8192 && position.z >= -8192 && position.z <= 8192) {
                obj.setMovementCounter(obj.getMovementCounter() + 1);
                DataTransform dataTransform = new DataTransform(new Point3D(position.x, position.y, position.z),
                        orientation, obj.getMovementCounter(), obj.getObjectID());
                ObjControllerMessage objController = new ObjControllerMessage(0x1B, dataTransform);
                obj.notifyObservers(objController, true);
            }
        } else {
            obj.setMovementCounter(obj.getMovementCounter() + 1);
            DataTransformWithParent dataTransform = new DataTransformWithParent(
                    new Point3D(position.x, position.y, position.z), orientation, obj.getMovementCounter(),
                    obj.getObjectID(), cellId);
            ObjControllerMessage objController = new ObjControllerMessage(0x1B, dataTransform);
            obj.notifyObservers(objController, true);

            obj.setPosition(position);
            obj.setOrientation(orientation);

            // Shouldn't the parent be set?
        }

    }

    /* Check world line of sight between an object and coordinates, instead of between two objects
     * Needed for vehicles.
     */
    public boolean checkLineOfSight(SWGObject object, Point3D position2) {
        long startTime = System.nanoTime();

        float heightOrigin = 1.75f;
        float heightDirection = 1.75f;

        if (object instanceof CreatureObject) {
            heightOrigin = getHeightOrigin((CreatureObject) object);
        }

        Point3D position1 = object.getWorldPosition();

        Point3D origin = new Point3D(position1.x, position1.y + heightOrigin, position1.z);
        Point3D end = new Point3D(position2.x, position2.y + heightDirection, position2.z);
        float distance = position1.getDistance2D(position2);

        List<SWGObject> inRangeObjects = get(object.getPlanet(), position1.x, position1.z, (int) distance);

        for (SWGObject inRangeObject : inRangeObjects) {
            if (inRangeObject == object) {
                continue;
            }

            if (object.getTemplate().contains("_barricade")
                    || object.getTemplate().contains("shared_dejarik_table_base"))
                continue;

            if (object.getTemplateData() != null
                    && object.getTemplateData().getAttribute("collisionActionBlockFlags") != null) {
                int bit = (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags") & 255;

                if (bit == (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags")) {
                    continue;
                }
            }

            Ray ray = convertRayToModelSpace(origin, end, object);

            MeshVisitor visitor = object.getMeshVisitor();

            if (visitor == null) {
                continue;
            }

            List<Mesh3DTriangle> tris = visitor.getTriangles();

            if (tris.isEmpty()) {
                continue;
            }

            for (Mesh3DTriangle tri : tris) {
                if (ray.intersectsTriangle(tri, distance) != null) {
                    return false;
                }
            }
        }

        return true;
    }

    public boolean checkLineOfSight2(SWGObject obj1, Point3D obj2) {
        long startTime = System.nanoTime();

        float heightOrigin = 1.75f;
        float heightDirection = 1.75f;

        if (obj1 instanceof CreatureObject)
            heightOrigin = getHeightOrigin((CreatureObject) obj1);

        Point3D position1 = obj1.getWorldPosition();
        Point3D position2 = obj2;

        Point3D origin = new Point3D(position1.x, position1.y + heightOrigin, position1.z);
        Point3D end = new Point3D(position2.x, position2.y + heightDirection, position2.z);
        float distance = position1.getDistance2D(position2);

        List<SWGObject> inRangeObjects = get(obj1.getPlanet(), position1.x, position1.z, (int) (distance + 10));

        for (SWGObject object : inRangeObjects) {

            if (object == obj1)
                continue;

            if (object.getTemplate().contains("_barricade")
                    || object.getTemplate().contains("shared_dejarik_table_base"))
                continue;

            if (object.getTemplateData() != null
                    && object.getTemplateData().getAttribute("collisionActionBlockFlags") != null) {
                int bit = (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags") & 255;
                if (bit == (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags"))
                    continue;
            }

            Ray ray = convertRayToModelSpace(origin, end, object);

            MeshVisitor visitor = object.getMeshVisitor();

            if (visitor == null)
                continue;

            List<Mesh3DTriangle> tris = visitor.getTriangles();

            if (tris.isEmpty())
                continue;

            for (Mesh3DTriangle tri : tris) {

                if (ray.intersectsTriangle(tri, distance) != null) {
                    //System.out.println("Collision took: " + (System.nanoTime() - startTime) + " ns (collided)");
                    //   System.out.println("Collided with " + object.getTemplate() + " X: " + object.getPosition().x + " Y: " + object.getPosition().y + " Z: " + object.getPosition().z);   
                    return false;
                }

            }

        }

        List<Vec3D> segments = new ArrayList<Vec3D>();
        Line3D.splitIntoSegments(new Vec3D(position1.x, position1.y + 1, position1.z),
                new Vec3D(position2.x, position2.y + 1, position2.z), (float) 1, segments, true);

        for (Vec3D segment : segments) {
            float y = segment.y;

            int height = (int) core.terrainService.getHeight(obj1.getPlanetId(), segment.x, segment.z); // round down to int

            if (height > y) {
                //System.out.println("Collision took: " + (System.nanoTime() - startTime) + " ns (terrain collision)");            
                return false;
            }
        }
        //System.out.println("Collision took: " + (System.nanoTime() - startTime) + " ns (did not collide)");

        return true;

    }

    public boolean checkLineOfSight(SWGObject obj1, SWGObject obj2) {
        long startTime = System.nanoTime();
        if (obj1.getPlanet() != obj2.getPlanet())
            return false;

        // If obj1 is container of obj2 vice versa
        if (obj1 == obj2.getContainer() || obj2 == obj1.getContainer() || obj1 == obj2.getGrandparent()
                || obj2 == obj1.getGrandparent()) {
            return true;
        }

        if (obj1.getGrandparent() != null || obj2.getGrandparent() != null) {

            if (obj1.getGrandparent() == obj2.getGrandparent())
                return checkLineOfSightInBuilding(obj1, obj2, obj1.getGrandparent());
            else if (obj1.getGrandparent() != null && obj2.getGrandparent() != null)
                return false;

        }

        //      float heightOrigin = 1.f;
        //      float heightDirection = 1.f;
        float heightOrigin = 1.75f;
        float heightDirection = 1.75f;

        if (obj2.getTemplate().equals("object/tangible/inventory/shared_character_inventory.iff")) {
            obj2 = obj2.getContainer(); // LOS message fix on corpse
        }

        if (obj1 instanceof CreatureObject)
            heightOrigin = getHeightOrigin((CreatureObject) obj1);

        if (obj2 instanceof CreatureObject)
            heightDirection = getHeightOrigin((CreatureObject) obj2);

        Point3D position1 = obj1.getWorldPosition();
        Point3D position2 = obj2.getWorldPosition();

        Point3D origin = new Point3D(position1.x, position1.y + heightOrigin, position1.z);
        Point3D end = new Point3D(position2.x, position2.y + heightDirection, position2.z);
        float distance = position1.getDistance2D(position2);

        List<SWGObject> inRangeObjects = get(obj1.getPlanet(), position1.x, position1.z, (int) (distance + 10));

        for (SWGObject object : inRangeObjects) {

            if (object == obj1 || object == obj2)
                continue;

            if (object.getTemplate().contains("_barricade")
                    || object.getTemplate().contains("shared_dejarik_table_base"))
                continue;

            if (object.getTemplateData() != null
                    && object.getTemplateData().getAttribute("collisionActionBlockFlags") != null) {
                int bit = (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags") & 255;
                if (bit == (Integer) object.getTemplateData().getAttribute("collisionActionBlockFlags"))
                    continue;
            }

            Ray ray = convertRayToModelSpace(origin, end, object);

            MeshVisitor visitor = object.getMeshVisitor();

            if (visitor == null)
                continue;

            List<Mesh3DTriangle> tris = visitor.getTriangles();

            if (tris.isEmpty())
                continue;

            for (Mesh3DTriangle tri : tris) {

                if (ray.intersectsTriangle(tri, distance) != null) {
                    //System.out.println("Collision took: " + (System.nanoTime() - startTime) + " ns (collided)");
                    //   System.out.println("Collided with " + object.getTemplate() + " X: " + object.getPosition().x + " Y: " + object.getPosition().y + " Z: " + object.getPosition().z);   
                    return false;
                }

            }

        }

        if (obj1.getContainer() != null || obj2.getContainer() != null) {

            CellObject cell = null;

            if (obj1.getContainer() != null && obj1.getContainer() instanceof CellObject)
                cell = (CellObject) obj1.getContainer();
            else if (obj2.getContainer() != null && obj2.getContainer() instanceof CellObject)
                cell = (CellObject) obj2.getContainer();

            if (cell != null)
                return checkLineOfSightWorldToCell(obj1, obj2, cell);
        }

        List<Vec3D> segments = new ArrayList<Vec3D>();
        Line3D.splitIntoSegments(new Vec3D(position1.x, position1.y + 1, position1.z),
                new Vec3D(position2.x, position2.y + 1, position2.z), (float) 1, segments, true);

        for (Vec3D segment : segments) {
            float y = segment.y;

            int height = (int) core.terrainService.getHeight(obj1.getPlanetId(), segment.x, segment.z); // round down to int

            if (height > y) {
                //System.out.println("Collision took: " + (System.nanoTime() - startTime) + " ns (terrain collision)");            
                return false;
            }
        }
        //System.out.println("Collision took: " + (System.nanoTime() - startTime) + " ns (did not collide)");

        return true;

    }

    public boolean checkLineOfSightInBuilding(SWGObject obj1, SWGObject obj2, SWGObject building) {

        PortalVisitor portalVisitor = building.getPortalVisitor();

        if (portalVisitor == null)
            return true;

        Point3D position1 = obj1.getPosition();
        Point3D position2 = obj2.getPosition();

        Point3D origin = new Point3D(position1.x, position1.y + 1, position1.z);
        Point3D end = new Point3D(position2.x, position2.y + 1, position2.z);

        Vector3D direction = new Vector3D(end.x - origin.x, end.y - origin.y, end.z - origin.z);

        if (direction.getNorm() != 0) {
            direction.normalize();
        } else {
            System.out.println("WARNING: checkLineOfSightInBuilding: Vector norm was 0.");
        }

        float distance = position1.getDistance2D(position2);
        Ray ray = new Ray(origin, direction);

        for (int i = 1; i < portalVisitor.cells.size(); i++) {

            Cell cell = portalVisitor.cells.get(i);
            try {

                MeshVisitor meshVisitor;
                if (!cellMeshes.containsKey(cell.mesh)) {
                    meshVisitor = ClientFileManager.loadFile(cell.mesh, MeshVisitor.class);
                    meshVisitor.getTriangles();
                    cellMeshes.put(cell.mesh, meshVisitor);
                } else {
                    meshVisitor = cellMeshes.get(cell.mesh);
                }

                if (meshVisitor == null)
                    continue;

                List<Mesh3DTriangle> tris = meshVisitor.getTriangles();

                if (tris.isEmpty())
                    continue;

                for (Mesh3DTriangle tri : tris) {

                    if (ray.intersectsTriangle(tri, distance) != null) {
                        //   System.out.println("Collision with: " + cell.name);
                        return false;
                    }

                }

            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }

        }

        return true;

    }

    public boolean checkLineOfSightWorldToCell(SWGObject obj1, SWGObject obj2, CellObject cell) {

        SWGObject building = cell.getContainer();

        if (building == null)
            return true;

        PortalVisitor portalVisitor = building.getPortalVisitor();

        if (portalVisitor == null)
            return true;

        float heightOrigin = 1.f;
        float heightDirection = 1.f;

        if (obj1 instanceof CreatureObject)
            heightOrigin = getHeightOrigin((CreatureObject) obj1);

        if (obj2 instanceof CreatureObject)
            heightDirection = getHeightOrigin((CreatureObject) obj2);

        Point3D position1 = obj1.getWorldPosition();
        Point3D position2 = obj2.getWorldPosition();

        Point3D origin = new Point3D(position1.x, position1.y + heightOrigin, position1.z);
        Point3D end = new Point3D(position2.x, position2.y + heightDirection, position2.z);

        Ray ray = convertRayToModelSpace(origin, end, building);

        if (cell.getCellNumber() >= portalVisitor.cellCount)
            return true;

        try {

            MeshVisitor meshVisitor = ClientFileManager.loadFile(portalVisitor.cells.get(cell.getCellNumber()).mesh,
                    MeshVisitor.class);

            if (meshVisitor == null)
                return true;

            List<Mesh3DTriangle> tris = meshVisitor.getTriangles();

            if (tris.isEmpty())
                return true;

            for (Mesh3DTriangle tri : tris) {

                if (ray.intersectsTriangle(tri) != null) {
                    return false;
                }

            }

        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }

        return true;
    }

    public float getHeightOrigin(CreatureObject creature) {

        float height = (float) (creature.getHeight()/* - 0.3*/);

        if (creature.getPosture() == 2 || creature.getPosture() == 13 || creature.getPosture() == 14)
            height = 0.45f;
        else if (creature.getPosture() == 1)
            height /= 2.f;

        return height;

    }

    public void notifyPlanet(Planet planet, IoBuffer packet) {

        ConcurrentHashMap<IoSession, Client> clients = core.getActiveConnectionsMap();

        for (Client client : clients.values()) {

            if (client.getParent() == null)
                continue;

            if (client.getParent().getPlanet() == null)
                continue;
            else if (client.getParent().getPlanet() == planet)
                client.getSession().write(packet);

        }

    }

    public void notifyAllClients(IoBuffer packet) {

        ConcurrentHashMap<IoSession, Client> clients = core.getActiveConnectionsMap();

        for (Client client : clients.values()) {

            if (client.getParent() == null)
                continue;

            client.getSession().write(packet);

        }

    }

    public void checkForCollidables(SWGObject object) {
        Point3D objectPos = object.getWorldPosition();
        List<AbstractCollidable> collidables = getCollidables(object.getPlanet(), objectPos.x, objectPos.z, 2050);

        for (AbstractCollidable collidable : collidables) {
            collidable.doCollisionCheck(object);
        }
    }

    public class MoveEvent implements Event {

        public SWGObject object;

    }

}