Java tutorial
/******************************************************************************* * 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; } }