Files
NGECore2/src/services/SimulationService.java
T
Waverunner d38bc9eb29 Changed CmdStartScene to use galacticTime
This should fix the time of day's being incorrect when using multiple
clients
2014-05-10 17:13:06 -04:00

1298 lines
46 KiB
Java

/*******************************************************************************
* 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.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.player.PlayerObject;
import resources.objects.tangible.TangibleObject;
import resources.common.*;
import resources.common.collidables.AbstractCollidable;
import resources.datatables.DisplayType;
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.registerCommand("opencontainer");
core.commandService.registerCommand("transferitem");
core.commandService.registerCommand("transferitemarmor");
core.commandService.registerCommand("transferitemweapon");
core.commandService.registerCommand("transferitemmisc");
core.commandService.registerCommand("equip");
core.commandService.registerCommand("prone");
core.commandService.registerCommand("stand");
core.commandService.registerCommand("sitserver");
core.commandService.registerCommand("kneel");
core.commandService.registerCommand("serverdestroyobject");
core.commandService.registerGmCommand("giveitem");
core.commandService.registerGmCommand("object");
core.commandService.registerCommand("getattributesbatch");
core.commandService.registerCommand("pvp");
core.commandService.registerCommand("setcurrentskilltitle");
core.commandService.registerCommand("tip");
core.commandService.registerCommand("faction");
core.commandService.registerGmCommand("setspeed");
core.commandService.registerCommand("waypoint");
core.commandService.registerCommand("setwaypointactivestatus");
core.commandService.registerCommand("setwaypointname");
core.commandService.registerCommand("getfriendlist");
core.commandService.registerCommand("deathblow");
core.commandService.registerCommand("endduel");
core.commandService.registerCommand("duel");
core.commandService.registerCommand("purchaseticket");
core.commandService.registerCommand("boardshuttle");
core.commandService.registerCommand("getplayerid");
core.commandService.registerCommand("inspire");
core.commandService.registerGmCommand("setgodmode");
core.commandService.registerCommand("requestwaypointatposition");
core.commandService.registerCommand("meditate");
core.commandService.registerGmCommand("server");
core.commandService.registerCommand("toggleawayfromkeyboard");
core.commandService.registerCommand("lfg");
core.commandService.registerCommand("newbiehelper");
core.commandService.registerCommand("roleplay");
core.commandService.registerAlias("afk", "toggleawayfromkeyboard");
core.commandService.registerCommand("toggledisplayingfactionrank");
core.commandService.registerCommand("editbiography");
core.commandService.registerCommand("setbiography");
core.commandService.registerCommand("requestbiography");
core.commandService.registerCommand("eject");
core.commandService.registerGmCommand("broadcast");
core.commandService.registerGmCommand("teleporttarget");
core.commandService.registerGmCommand("getplayerid");
core.commandService.registerCommand("npcconversationselect");
core.commandService.registerCommand("npcconversationstop");
}
public void insertSnapShotObjects() {
List<SWGObject> objectList = new ArrayList<SWGObject>(core.objectService.getObjectList().values());
for(SWGObject obj : objectList) {
if(obj.getParentId() == 0 && /*(*/obj.isInSnapshot() /*|| obj.getAttachment("isBuildout") != null)*/)
add(obj, obj.getPosition().x, obj.getPosition().z);
}
}
public void insertPersistentBuildings() {
ODBCursor cursor = core.getSWGObjectODB().getCursor();
while(cursor.hasNext()) {
SWGObject building = core.objectService.getObject(((SWGObject) cursor.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);
object.setAttachment("childObjects", null);
}
if(notifyObservers) {
Point3D pos = new Point3D(x, 0, z);
Collection<SWGObject> newAwareObjects = get(object.getPlanet(), x, z, 512);
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);
}
}
}
return success;
}
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 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;
}
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);
}
}
}
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 object = (CreatureObject) client.getParent();
if (core.mountService.isMounted(object)) {
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();
//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);
object.setOrientation(newOrientation);
object.setMovementCounter(dataTransform.getMovementCounter());
}
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());
List<SWGObject> newAwareObjects = get(object.getPlanet(), newPos.x, newPos.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(newPos) > 200 && obj.isInQuadtree() /*&& obj.getParentId() == 0*/) {
if(obj.getAttachment("bigSpawnRange") != null && obj.getWorldPosition().getDistance2D(newPos) < 512)
continue;
object.makeUnaware(obj);
if(obj.getClient() != null)
obj.makeUnaware(object);
} else if(obj != object && obj.getWorldPosition().getDistance2D(newPos) > 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(newPos) > 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);
}
});
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 (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());
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);
parent._add(object);
}
object.setPosition(newPos);
object.setOrientation(newOrientation);
object.setMovementCounter(dataTransform.getMovementCounter());
object.notifyObservers(utm, false);
checkForCollidables(object);
}
});
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(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);
}
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 = translateMatrix.mult(rotationMatrix).inverse();
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);
}
/*
* 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);
object.setPvPBitmask(0);
//session.suspendWrite();
final long objectId = object.getObjectID();
if(!ghost.isSet(PlayerFlags.LD))
ghost.toggleFlag(PlayerFlags.LD);
for (CreatureObject opponent : new ArrayList<CreatureObject>(object.getDuelList())) {
if (opponent != null) {
core.combatService.handleEndDuel(object, opponent, true);
}
}
if (core.mountService.isMounted(object)) {
core.mountService.dismount(object, (CreatureObject) container);
}
core.mountService.storeAll(object);
/*
object.createTransaction(core.getCreatureODB().getEnvironment());
core.getCreatureODB().put(object, Long.class, CreatureObject.class, object.getTransaction());
object.getTransaction().commitSync();*/
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);
core.simulationService.remove(object, object.getPosition().x, object.getPosition().z, true);
}
}
}, 120, TimeUnit.SECONDS);
core.removeClient(session);
object.setAttachment("disconnectTask", disconnectTask);
core.combatService.endCombat(object); // temp fix for ending combat on disconnect
}
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().getDistance(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) {
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(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);
}
}
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;
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.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;
}
}