Pathfinding!
This commit is contained in:
parent
3185866fa4
commit
5f4eb22fa9
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
"graphicsDebugDrawCollisionSpheres" : false,
|
"graphicsDebugDrawCollisionSpheres" : false,
|
||||||
"graphicsDebugDrawPhysicsObjects" : false,
|
"graphicsDebugDrawPhysicsObjects" : false,
|
||||||
"graphicsDebugDrawMovementVectors" : false
|
"graphicsDebugDrawMovementVectors" : false,
|
||||||
|
"graphicsDebugDrawNavmesh" : true
|
||||||
|
|
||||||
}
|
}
|
||||||
BIN
assets/Models/waypoint1.fbx
Normal file
BIN
assets/Models/waypoint1.fbx
Normal file
Binary file not shown.
@ -29,7 +29,7 @@ import electrosphere.game.server.saves.SaveUtils;
|
|||||||
import electrosphere.game.server.terrain.models.TerrainModification;
|
import electrosphere.game.server.terrain.models.TerrainModification;
|
||||||
import electrosphere.game.server.town.Town;
|
import electrosphere.game.server.town.Town;
|
||||||
import electrosphere.game.server.world.MacroData;
|
import electrosphere.game.server.world.MacroData;
|
||||||
import electrosphere.game.server.world.datacell.DataCellManager;
|
import electrosphere.game.server.datacell.DataCellManager;
|
||||||
import electrosphere.game.state.MicroSimulation;
|
import electrosphere.game.state.MicroSimulation;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.main.Globals;
|
import electrosphere.main.Globals;
|
||||||
@ -42,6 +42,9 @@ import electrosphere.renderer.ActorUtils;
|
|||||||
import electrosphere.renderer.Model;
|
import electrosphere.renderer.Model;
|
||||||
import electrosphere.renderer.RenderUtils;
|
import electrosphere.renderer.RenderUtils;
|
||||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
|
import electrosphere.game.server.pathfinding.NavMeshPathfinder;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavCube;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -591,6 +594,13 @@ public class LoadingThread extends Thread {
|
|||||||
Entity bow = ItemUtils.spawnBasicItem("Bow");
|
Entity bow = ItemUtils.spawnBasicItem("Bow");
|
||||||
EntityUtils.getPosition(bow).set(1, 1, 2);
|
EntityUtils.getPosition(bow).set(1, 1, 2);
|
||||||
|
|
||||||
|
NavMeshPathfinder.navigatePointToPointInMesh(Globals.navMeshManager.getMeshes().get(0), new Vector3d(10,0,5), new Vector3d(5,0,10));
|
||||||
|
|
||||||
|
// NavMesh mesh = new NavMesh();
|
||||||
|
// NavCube cube = new NavCube(5,0,0,10,5,5);
|
||||||
|
// mesh.addNode(cube);
|
||||||
|
// Globals.navMeshManager.addMesh(mesh);
|
||||||
|
|
||||||
// Entity fallOak = FoliageUtils.spawnBasicFoliage("FallOak1");
|
// Entity fallOak = FoliageUtils.spawnBasicFoliage("FallOak1");
|
||||||
// EntityUtils.getPosition(fallOak).set(1,0,3);
|
// EntityUtils.getPosition(fallOak).set(1,0,3);
|
||||||
//
|
//
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
package electrosphere.entity.types.waypoint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author amaterasu
|
||||||
|
*/
|
||||||
|
public class WaypointUtils {
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@ package electrosphere.game.client.world;
|
|||||||
|
|
||||||
import electrosphere.game.server.world.*;
|
import electrosphere.game.server.world.*;
|
||||||
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.game.server.world.datacell.ServerDataCell;
|
import electrosphere.game.server.datacell.ServerDataCell;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.joml.Vector2f;
|
import org.joml.Vector2f;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|||||||
@ -37,6 +37,7 @@ public class UserSettings {
|
|||||||
boolean graphicsDebugDrawCollisionSpheres;
|
boolean graphicsDebugDrawCollisionSpheres;
|
||||||
boolean graphicsDebugDrawPhysicsObjects;
|
boolean graphicsDebugDrawPhysicsObjects;
|
||||||
boolean graphicsDebugDrawMovementVectors;
|
boolean graphicsDebugDrawMovementVectors;
|
||||||
|
boolean graphicsDebugDrawNavmesh;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -88,6 +89,10 @@ public class UserSettings {
|
|||||||
public int getGraphicsPerformanceLODChunkRadius() {
|
public int getGraphicsPerformanceLODChunkRadius() {
|
||||||
return graphicsPerformanceLODChunkRadius;
|
return graphicsPerformanceLODChunkRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean graphicsDebugDrawNavmesh() {
|
||||||
|
return graphicsDebugDrawNavmesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -116,6 +121,7 @@ public class UserSettings {
|
|||||||
rVal.graphicsDebugDrawCollisionSpheres = false;
|
rVal.graphicsDebugDrawCollisionSpheres = false;
|
||||||
rVal.graphicsDebugDrawMovementVectors = false;
|
rVal.graphicsDebugDrawMovementVectors = false;
|
||||||
rVal.graphicsDebugDrawPhysicsObjects = false;
|
rVal.graphicsDebugDrawPhysicsObjects = false;
|
||||||
|
rVal.graphicsDebugDrawNavmesh = false;
|
||||||
rVal.graphicsPerformanceLODChunkRadius = 5;
|
rVal.graphicsPerformanceLODChunkRadius = 5;
|
||||||
rVal.graphicsFOV = 90.0f;
|
rVal.graphicsFOV = 90.0f;
|
||||||
rVal.graphicsPerformanceDrawShadows = true;
|
rVal.graphicsPerformanceDrawShadows = true;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
package electrosphere.game.server.world.datacell;
|
package electrosphere.game.server.datacell;
|
||||||
|
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package electrosphere.game.server.world.datacell;
|
package electrosphere.game.server.datacell;
|
||||||
|
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.EntityUtils;
|
import electrosphere.entity.EntityUtils;
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package electrosphere.game.server.world.datacell;
|
package electrosphere.game.server.datacell;
|
||||||
|
|
||||||
import electrosphere.entity.Entity;
|
import electrosphere.entity.Entity;
|
||||||
import electrosphere.entity.types.creature.CreatureUtils;
|
import electrosphere.entity.types.creature.CreatureUtils;
|
||||||
@ -6,6 +6,8 @@ import electrosphere.entity.types.item.ItemUtils;
|
|||||||
import electrosphere.entity.types.structure.StructureUtils;
|
import electrosphere.entity.types.structure.StructureUtils;
|
||||||
import electrosphere.net.server.Player;
|
import electrosphere.net.server.Player;
|
||||||
import electrosphere.game.server.character.Character;
|
import electrosphere.game.server.character.Character;
|
||||||
|
import electrosphere.game.server.pathfinding.NavMeshUtils;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
||||||
import electrosphere.main.Globals;
|
import electrosphere.main.Globals;
|
||||||
import electrosphere.net.parser.net.message.NetworkMessage;
|
import electrosphere.net.parser.net.message.NetworkMessage;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@ -22,6 +24,7 @@ public class ServerDataCell {
|
|||||||
|
|
||||||
List<Entity> loadedEntities = new LinkedList();
|
List<Entity> loadedEntities = new LinkedList();
|
||||||
List<Player> activePlayers = new LinkedList();
|
List<Player> activePlayers = new LinkedList();
|
||||||
|
NavMesh navMesh;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,6 +44,7 @@ public class ServerDataCell {
|
|||||||
//else create from scratch
|
//else create from scratch
|
||||||
EnvironmentGenerator.generatePlains(rVal.loadedEntities, worldX, worldY, Globals.serverTerrainManager.getRandomizerAtPoint(worldX, worldY));
|
EnvironmentGenerator.generatePlains(rVal.loadedEntities, worldX, worldY, Globals.serverTerrainManager.getRandomizerAtPoint(worldX, worldY));
|
||||||
}
|
}
|
||||||
|
rVal.navMesh = NavMeshUtils.createMeshFromChunk(Globals.serverTerrainManager.getChunk(worldX, worldY),Globals.navMeshManager.getBlockerCache().getBlocker(worldX, worldY));
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,11 +1,16 @@
|
|||||||
package electrosphere.game.server.pathfinding;
|
package electrosphere.game.server.pathfinding;
|
||||||
|
|
||||||
|
import electrosphere.game.server.pathfinding.blocker.NavBlocker;
|
||||||
|
import electrosphere.game.server.pathfinding.blocker.NavTerrainBlockerCache;
|
||||||
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavShape;
|
||||||
|
import electrosphere.game.server.pathfinding.path.Waypoint;
|
||||||
import electrosphere.game.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.game.server.terrain.manager.ServerTerrainChunk;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -15,6 +20,34 @@ public class NavMeshManager {
|
|||||||
|
|
||||||
List<NavMesh> meshes = new LinkedList();
|
List<NavMesh> meshes = new LinkedList();
|
||||||
Map<ServerTerrainChunk,ChunkMeshList> chunkToMeshListMap = new HashMap();
|
Map<ServerTerrainChunk,ChunkMeshList> chunkToMeshListMap = new HashMap();
|
||||||
|
NavTerrainBlockerCache blockerCache = new NavTerrainBlockerCache();
|
||||||
|
|
||||||
|
public NavMesh createNavMesh(){
|
||||||
|
NavMesh rVal = new NavMesh();
|
||||||
|
meshes.add(rVal);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addMesh(NavMesh mesh){
|
||||||
|
meshes.add(mesh);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NavMesh> getMeshes(){
|
||||||
|
return meshes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<NavMesh> navigateMeshToMesh(NavMesh startMesh, NavMesh endMesh){
|
||||||
|
List<NavMesh> rVal = null;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavBlocker getNavBlockerForChunk(int x, int y){
|
||||||
|
NavBlocker rVal = null;
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavTerrainBlockerCache getBlockerCache(){
|
||||||
|
return blockerCache;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,450 @@
|
|||||||
|
package electrosphere.game.server.pathfinding;
|
||||||
|
|
||||||
|
import electrosphere.entity.Entity;
|
||||||
|
import electrosphere.entity.EntityUtils;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavCube;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavShape;
|
||||||
|
import electrosphere.game.server.pathfinding.path.Waypoint;
|
||||||
|
import java.awt.geom.Line2D;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import org.joml.Vector3d;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author amaterasu
|
||||||
|
*/
|
||||||
|
public class NavMeshPathfinder {
|
||||||
|
|
||||||
|
//TODO: add movement type mask to this function
|
||||||
|
public static List<Waypoint> navigatePointToPointInMesh(NavMesh mesh, Vector3d start, Vector3d end){
|
||||||
|
|
||||||
|
List<Waypoint> rVal = new LinkedList();
|
||||||
|
|
||||||
|
NavShape startNode = null;
|
||||||
|
NavShape endNode = null;
|
||||||
|
|
||||||
|
for(NavShape node : mesh.getNodes()){
|
||||||
|
if(node.containsPoint(start.x, start.y, start.z)){
|
||||||
|
startNode = node;
|
||||||
|
}
|
||||||
|
if(node.containsPoint(end.x, end.y, end.z)){
|
||||||
|
endNode = node;
|
||||||
|
}
|
||||||
|
if(startNode != null && endNode != null){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if the start and end nodes aren't both present, exit
|
||||||
|
//need to do broadphase still
|
||||||
|
if(startNode == null || endNode == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//theta *
|
||||||
|
List<NavShape> openSet = new LinkedList();
|
||||||
|
List<NavShape> closedSet = new LinkedList();
|
||||||
|
PriorityQueue<SetItem> pathItemsQueue = new PriorityQueue();
|
||||||
|
Map<NavShape,SetItem> pathItems = new HashMap();
|
||||||
|
|
||||||
|
openSet.add(startNode);
|
||||||
|
SetItem startSetItem = new SetItem(null,startNode,0,start);
|
||||||
|
startSetItem.currentPos = start;
|
||||||
|
pathItems.put(startNode, startSetItem);
|
||||||
|
pathItemsQueue.add(startSetItem);
|
||||||
|
|
||||||
|
while(!openSet.isEmpty()){
|
||||||
|
//get lowest cost item
|
||||||
|
SetItem currentItem = pathItemsQueue.poll();
|
||||||
|
NavShape currentNode = currentItem.getNode();
|
||||||
|
openSet.remove(currentNode);
|
||||||
|
|
||||||
|
//return path if found end
|
||||||
|
if(currentNode == endNode){
|
||||||
|
System.out.println("Found path!");
|
||||||
|
//TODO: return path
|
||||||
|
while(currentItem != null){
|
||||||
|
if(currentItem.node == endNode){
|
||||||
|
Entity waypoint = EntityUtils.spawnDrawableEntity("Models/waypoint1.fbx");
|
||||||
|
System.out.println(end);
|
||||||
|
EntityUtils.getPosition(waypoint).set(end.x,end.y + 1,end.z);
|
||||||
|
EntityUtils.getRotation(waypoint).rotateLocalX(-(float)Math.PI/2.0f);
|
||||||
|
} else {
|
||||||
|
Entity waypoint = EntityUtils.spawnDrawableEntity("Models/waypoint1.fbx");
|
||||||
|
System.out.println(currentItem.currentPos);
|
||||||
|
EntityUtils.getPosition(waypoint).set(currentItem.currentPos.x,currentItem.currentPos.y + 1,currentItem.currentPos.z);
|
||||||
|
EntityUtils.getRotation(waypoint).rotateLocalX(-(float)Math.PI/2.0f);
|
||||||
|
}
|
||||||
|
currentItem = currentItem.parent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
closedSet.add(currentNode);
|
||||||
|
for(NavShape neighbor : currentNode.getNodeNeighbors()){
|
||||||
|
if(!closedSet.contains(neighbor)){
|
||||||
|
if(!openSet.contains(neighbor)){
|
||||||
|
Vector3d centerPoint = calculateCenterOfShape(neighbor);
|
||||||
|
SetItem newSetItem = new SetItem(currentItem,neighbor,currentItem.getCost() + (float)currentItem.currentPos.distance(centerPoint),centerPoint);
|
||||||
|
pathItems.put(neighbor, newSetItem);
|
||||||
|
pathItemsQueue.add(newSetItem);
|
||||||
|
openSet.add(neighbor);
|
||||||
|
}
|
||||||
|
//update vertex
|
||||||
|
updateVertices(currentItem, pathItems.get(neighbor),pathItemsQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void updateVertices(SetItem current, SetItem neighbor, PriorityQueue<SetItem> queue){
|
||||||
|
// This part of the algorithm is the main difference between A* and Theta*
|
||||||
|
if(current.getParent() != null){
|
||||||
|
LOSResult losResult = null;
|
||||||
|
Vector3d neighborCenter = calculateCenterOfShape(neighbor.node);
|
||||||
|
if(current.getParent().currentPos == null){
|
||||||
|
current.getParent().currentPos = calculateCenterOfShape(current.getParent().node);
|
||||||
|
}
|
||||||
|
Vector3d parentPos = current.getParent().currentPos;
|
||||||
|
if((losResult = lineOfSight(current.getParent(), current, neighbor))==null){
|
||||||
|
// Vector3d neighborCenter = calculateCenterOfShape(neighbor.node);
|
||||||
|
// Vector3d parentPos = current.getParent().currentPos;
|
||||||
|
float dist = (float)neighborCenter.distance(parentPos);
|
||||||
|
// If there is line-of-sight between parent(s) and neighbor
|
||||||
|
// then ignore s and use the path from parent(s) to neighbor
|
||||||
|
if(current.getParent().cost + dist < neighbor.cost){
|
||||||
|
// c(s, neighbor) is the Euclidean distance from s to neighbor
|
||||||
|
neighbor.cost = current.getParent().cost + dist;
|
||||||
|
neighbor.parent = current.getParent();
|
||||||
|
|
||||||
|
//update prio q
|
||||||
|
queue.remove(neighbor);
|
||||||
|
queue.add(neighbor);
|
||||||
|
// if(neighbor in open){
|
||||||
|
// open.remove(neighbor);
|
||||||
|
// }
|
||||||
|
// open.insert(neighbor, gScore(neighbor) + heuristic(neighbor));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//find midpoint
|
||||||
|
// Vector3d neighborCenter = calculateCenterOfShape(neighbor.node);
|
||||||
|
// Vector3d parentPos = current.getParent().currentPos;
|
||||||
|
if(losResult.hit){
|
||||||
|
float distToMidpoint = (float)neighborCenter.distance(losResult.currentPos);
|
||||||
|
float distToParent = (float)losResult.currentPos.distance(losResult.parentPos);
|
||||||
|
float dist = distToMidpoint + distToParent;
|
||||||
|
// If the length of the path from start to s and from s to
|
||||||
|
// neighbor is shorter than the shortest currently known distance
|
||||||
|
// from start to neighbor, then update node with the new distance
|
||||||
|
if(current.cost + dist < neighbor.cost){
|
||||||
|
neighbor.cost = current.cost + dist;
|
||||||
|
neighbor.parent = current;
|
||||||
|
|
||||||
|
//update prio q
|
||||||
|
queue.remove(neighbor);
|
||||||
|
queue.add(neighbor);
|
||||||
|
|
||||||
|
current.getParent().currentPos = losResult.parentPos;
|
||||||
|
current.currentPos = losResult.currentPos;
|
||||||
|
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float dist = (float)neighborCenter.distance(parentPos);
|
||||||
|
// If there is line-of-sight between parent(s) and neighbor
|
||||||
|
// then ignore s and use the path from parent(s) to neighbor
|
||||||
|
if(current.getParent().cost + dist < neighbor.cost){
|
||||||
|
// c(s, neighbor) is the Euclidean distance from s to neighbor
|
||||||
|
neighbor.cost = current.getParent().cost + dist;
|
||||||
|
neighbor.parent = current.getParent();
|
||||||
|
|
||||||
|
//update prio q
|
||||||
|
queue.remove(neighbor);
|
||||||
|
queue.add(neighbor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class LOSResult{
|
||||||
|
Vector3d parentPos;
|
||||||
|
Vector3d currentPos;
|
||||||
|
boolean hit;
|
||||||
|
}
|
||||||
|
|
||||||
|
//calculates the line of sight ACROSS current FROM PARENT TO NEIGHBOR
|
||||||
|
static LOSResult lineOfSight(SetItem parent, SetItem current, SetItem neighbor){
|
||||||
|
if(parent.node instanceof NavCube && current.node instanceof NavCube && neighbor.node instanceof NavCube){
|
||||||
|
//get points on border of current and neighbor, this is one of the lines
|
||||||
|
double borderMinX = 0;
|
||||||
|
double borderMinZ = 0;
|
||||||
|
double borderMaxX = 0;
|
||||||
|
double borderMaxZ = 0;
|
||||||
|
NavCube parentCube = (NavCube)parent.node;
|
||||||
|
NavCube currentCube = (NavCube)current.node;
|
||||||
|
NavCube neighborCube = (NavCube)neighbor.node;
|
||||||
|
//resolve min/max pos
|
||||||
|
// Vector3d currentMin = currentCube.getMinPoint();
|
||||||
|
// Vector3d currentMax = currentCube.getMaxPoint();
|
||||||
|
// Vector3d neighborMin = neighborCube.getMinPoint();
|
||||||
|
// Vector3d neighborMax = neighborCube.getMaxPoint();
|
||||||
|
|
||||||
|
BoxInternalBorder parentCurrentBorder = getBoxInternalBorder(parentCube.getMinPoint(),parentCube.getMaxPoint(),currentCube.getMinPoint(),currentCube.getMaxPoint());
|
||||||
|
BoxInternalBorder currentChildBorder = getBoxInternalBorder(currentCube.getMinPoint(),currentCube.getMaxPoint(),neighborCube.getMinPoint(),neighborCube.getMaxPoint());
|
||||||
|
|
||||||
|
boolean intersectsParentBorder = Line2D.linesIntersect(
|
||||||
|
parentCurrentBorder.minPoint.x, parentCurrentBorder.minPoint.z,
|
||||||
|
parentCurrentBorder.maxPoint.x, parentCurrentBorder.maxPoint.z,
|
||||||
|
neighbor.currentPos.x, neighbor.currentPos.z,
|
||||||
|
parent.currentPos.x, parent.currentPos.z
|
||||||
|
);
|
||||||
|
boolean intersectsChildBorder = Line2D.linesIntersect(
|
||||||
|
currentChildBorder.minPoint.x, currentChildBorder.minPoint.z,
|
||||||
|
currentChildBorder.maxPoint.x, currentChildBorder.maxPoint.z,
|
||||||
|
neighbor.currentPos.x, neighbor.currentPos.z,
|
||||||
|
parent.currentPos.x, parent.currentPos.z
|
||||||
|
);
|
||||||
|
|
||||||
|
LOSResult rVal = new LOSResult();
|
||||||
|
|
||||||
|
if(intersectsParentBorder && intersectsChildBorder){
|
||||||
|
rVal.hit = false;
|
||||||
|
} else {
|
||||||
|
rVal.hit = true;
|
||||||
|
// rVal.currentPos = new Vector3d();
|
||||||
|
if(neighbor.currentPos.distance(currentChildBorder.minPoint) < neighbor.currentPos.distance(currentChildBorder.maxPoint)){
|
||||||
|
rVal.currentPos = currentChildBorder.minPoint;
|
||||||
|
} else {
|
||||||
|
rVal.currentPos = currentChildBorder.maxPoint;
|
||||||
|
}
|
||||||
|
if(parent.currentPos.distance(parentCurrentBorder.minPoint) < parent.currentPos.distance(parentCurrentBorder.maxPoint)){
|
||||||
|
rVal.parentPos = parentCurrentBorder.minPoint;
|
||||||
|
} else {
|
||||||
|
rVal.parentPos = parentCurrentBorder.maxPoint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rVal;
|
||||||
|
|
||||||
|
//the other line comes from earlier
|
||||||
|
// if(Line2D.linesIntersect(borderMinX, borderMinZ, borderMaxX, borderMaxZ, rayStart.x, rayStart.z, rayEnd.x, rayEnd.z)){
|
||||||
|
// return null;
|
||||||
|
// } else {
|
||||||
|
// double distMin = Line2D.ptLineDist(rayStart.x, rayStart.z, rayEnd.x, rayEnd.z, borderMinX, borderMinZ);
|
||||||
|
// double distMax = Line2D.ptLineDist(rayStart.x, rayStart.z, rayEnd.x, rayEnd.z, borderMaxX, borderMaxZ);
|
||||||
|
// if(distMin < distMax){
|
||||||
|
// return new Vector3d(borderMinX, 0, borderMinZ);
|
||||||
|
// } else {
|
||||||
|
// return new Vector3d(borderMaxX, 0, borderMaxZ);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class BoxInternalBorder {
|
||||||
|
Vector3d minPoint = new Vector3d();
|
||||||
|
Vector3d maxPoint = new Vector3d();
|
||||||
|
}
|
||||||
|
|
||||||
|
static BoxInternalBorder getBoxInternalBorder(Vector3d currentMin, Vector3d currentMax, Vector3d neighborMin, Vector3d neighborMax){
|
||||||
|
BoxInternalBorder rVal = new BoxInternalBorder();
|
||||||
|
if(currentMin.x == neighborMax.x){
|
||||||
|
double targetX = currentMin.x;
|
||||||
|
if(currentMin.z >= neighborMin.z && currentMax.z <= neighborMax.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = currentMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = currentMax.z;
|
||||||
|
} else if(neighborMin.z >= currentMin.z && neighborMax.z <= currentMax.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = neighborMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = neighborMax.z;
|
||||||
|
} else if(currentMin.z >= neighborMin.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = currentMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = neighborMax.z;
|
||||||
|
} else if(neighborMin.z >= currentMin.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = neighborMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = currentMax.z;
|
||||||
|
} else {
|
||||||
|
//they all line up or something
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = currentMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = currentMax.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentMax.x == neighborMin.x){
|
||||||
|
double targetX = currentMax.x;
|
||||||
|
if(currentMin.z >= neighborMin.z && currentMax.z <= neighborMax.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = currentMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = currentMax.z;
|
||||||
|
} else if(neighborMin.z >= currentMin.z && neighborMax.z <= currentMax.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = neighborMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = neighborMax.z;
|
||||||
|
} else if(currentMin.z >= neighborMin.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = currentMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = neighborMax.z;
|
||||||
|
} else if(neighborMin.z >= currentMin.z){
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = neighborMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = currentMax.z;
|
||||||
|
} else {
|
||||||
|
//they all line up or something
|
||||||
|
rVal.minPoint.x = targetX;
|
||||||
|
rVal.minPoint.z = currentMin.z;
|
||||||
|
rVal.maxPoint.x = targetX;
|
||||||
|
rVal.maxPoint.z = currentMax.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentMin.z == neighborMax.z){
|
||||||
|
double targetZ = currentMin.x;
|
||||||
|
if(currentMin.x >= neighborMin.x && currentMax.x <= neighborMax.x){
|
||||||
|
rVal.minPoint.x = currentMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = currentMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else if(neighborMin.x >= currentMin.x && neighborMax.x <= currentMax.x){
|
||||||
|
rVal.minPoint.x = neighborMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = neighborMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else if(currentMin.x >= neighborMin.x){
|
||||||
|
rVal.minPoint.x = currentMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = neighborMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else if(neighborMin.x >= currentMin.x){
|
||||||
|
rVal.minPoint.x = neighborMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = currentMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else {
|
||||||
|
//they all line up or something
|
||||||
|
rVal.minPoint.x = currentMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = currentMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(currentMax.z == neighborMin.z){
|
||||||
|
double targetZ = currentMax.x;
|
||||||
|
if(currentMin.x >= neighborMin.x && currentMax.x <= neighborMax.x){
|
||||||
|
rVal.minPoint.x = currentMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = currentMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else if(neighborMin.x >= currentMin.x && neighborMax.x <= currentMax.x){
|
||||||
|
rVal.minPoint.x = neighborMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = neighborMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else if(currentMin.x >= neighborMin.x){
|
||||||
|
rVal.minPoint.x = currentMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = neighborMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else if(neighborMin.x >= currentMin.x){
|
||||||
|
rVal.minPoint.x = neighborMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = currentMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
} else {
|
||||||
|
//they all line up or something
|
||||||
|
rVal.minPoint.x = currentMin.x;
|
||||||
|
rVal.minPoint.z = targetZ;
|
||||||
|
rVal.maxPoint.x = currentMax.x;
|
||||||
|
rVal.maxPoint.z = targetZ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static float lineDistCalc(SetItem current, SetItem target){
|
||||||
|
// float rVal = -1.0f;
|
||||||
|
// return rVal;
|
||||||
|
// }
|
||||||
|
|
||||||
|
static Vector3d calculateCenterOfShape(NavShape shape){
|
||||||
|
Vector3d rVal = new Vector3d();
|
||||||
|
if(shape instanceof NavCube){
|
||||||
|
NavCube cube = (NavCube)shape;
|
||||||
|
rVal.add(cube.getMaxPoint()).add(cube.getMinPoint());
|
||||||
|
rVal.mul(0.5);
|
||||||
|
}
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static class SetItem implements Comparable {
|
||||||
|
SetItem parent;
|
||||||
|
NavShape node;
|
||||||
|
float cost;
|
||||||
|
//closest point from parent's parent
|
||||||
|
Vector3d currentPos;
|
||||||
|
|
||||||
|
public SetItem(SetItem parent, NavShape node, float cost, Vector3d currentPos){
|
||||||
|
this.parent = parent;
|
||||||
|
this.node = node;
|
||||||
|
this.cost = cost;
|
||||||
|
this.currentPos = currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SetItem getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavShape getNode() {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getCost() {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCost(float cost) {
|
||||||
|
this.cost = cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Object o) {
|
||||||
|
SetItem target = (SetItem)o;
|
||||||
|
if(this.cost < target.cost){
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(this.cost > target.cost){
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3d getCurrentPos() {
|
||||||
|
return currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCurrentPos(Vector3d currentPos) {
|
||||||
|
this.currentPos = currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,16 @@
|
|||||||
package electrosphere.game.server.pathfinding;
|
package electrosphere.game.server.pathfinding;
|
||||||
|
|
||||||
|
import electrosphere.game.server.pathfinding.blocker.NavBlocker;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavCube;
|
||||||
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavShape;
|
||||||
import electrosphere.game.server.terrain.manager.ServerTerrainChunk;
|
import electrosphere.game.server.terrain.manager.ServerTerrainChunk;
|
||||||
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.main.Globals;
|
import electrosphere.main.Globals;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.joml.Vector2i;
|
||||||
|
import org.joml.Vector4i;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -10,22 +18,341 @@ import electrosphere.main.Globals;
|
|||||||
*/
|
*/
|
||||||
public class NavMeshUtils {
|
public class NavMeshUtils {
|
||||||
|
|
||||||
public static NavMesh createMeshFromChunk(ServerTerrainChunk chunk){
|
static float NAVMESH_PHASE_ONE_DISPARITY_TOLERANCE = 0.5f;
|
||||||
NavMesh rVal = new NavMesh();
|
static float NAVMESH_PHASE_TWO_DISPARITY_TOLERANCE = 0.5f;
|
||||||
|
public static NavMesh createMeshFromChunk(ServerTerrainChunk chunk, NavBlocker navBlocker){
|
||||||
|
NavMesh rVal = Globals.navMeshManager.createNavMesh();
|
||||||
float[][] heightMap = chunk.getHeightMap();
|
float[][] heightMap = chunk.getHeightMap();
|
||||||
for(int x = 0; x < Globals.serverTerrainManager.getChunkWidth(); x++){
|
boolean[][] navMeshGeneratorMask = navBlocker.getHeightfieldBlocker();
|
||||||
for(int y = 0; y < Globals.serverTerrainManager.getChunkWidth(); y++){
|
List<FirstPhaseBox> firstPassBoxes = new LinkedList();
|
||||||
|
int numInCurrent = 0;
|
||||||
|
float currentMin = 0;
|
||||||
|
float currentMax = 0;
|
||||||
|
int startPos = 0;
|
||||||
|
int endPos = 0;
|
||||||
|
for(int x = 0; x < Globals.serverTerrainManager.getAugmentedChunkWidth() - 1; x++){
|
||||||
|
numInCurrent = 0;
|
||||||
|
currentMin = 0;
|
||||||
|
currentMax = 0;
|
||||||
|
for(int y = 0; y < Globals.serverTerrainManager.getAugmentedChunkWidth(); y++){
|
||||||
//create node
|
//create node
|
||||||
|
if(navMeshGeneratorMask[x][y]){
|
||||||
if(x > 0){
|
if(numInCurrent > 0){
|
||||||
//add back neighbor
|
firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax));
|
||||||
|
}
|
||||||
|
numInCurrent = 0;
|
||||||
|
} else {
|
||||||
|
if(numInCurrent == 0){
|
||||||
|
currentMin = heightMap[x][y];
|
||||||
|
currentMax = heightMap[x][y];
|
||||||
|
startPos = y;
|
||||||
|
endPos = y+1;
|
||||||
|
numInCurrent = 1;
|
||||||
|
} else {
|
||||||
|
if(currentMin > heightMap[x][y]){
|
||||||
|
if(currentMax - heightMap[x][y] < NAVMESH_PHASE_ONE_DISPARITY_TOLERANCE){
|
||||||
|
currentMin = heightMap[x][y];
|
||||||
|
endPos = y;
|
||||||
|
numInCurrent++;
|
||||||
|
} else {
|
||||||
|
//expel previous rectangle
|
||||||
|
firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax));
|
||||||
|
//start new one
|
||||||
|
currentMin = heightMap[x][y];
|
||||||
|
currentMax = heightMap[x][y];
|
||||||
|
startPos = y;
|
||||||
|
endPos = y+1;
|
||||||
|
numInCurrent = 1;
|
||||||
|
}
|
||||||
|
} else if(currentMax < heightMap[x][y]){
|
||||||
|
if(heightMap[x][y] - currentMin < NAVMESH_PHASE_ONE_DISPARITY_TOLERANCE){
|
||||||
|
currentMin = heightMap[x][y];
|
||||||
|
endPos = y;
|
||||||
|
numInCurrent++;
|
||||||
|
} else {
|
||||||
|
//expel previous rectangle
|
||||||
|
firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax));
|
||||||
|
//start new one
|
||||||
|
currentMin = heightMap[x][y];
|
||||||
|
currentMax = heightMap[x][y];
|
||||||
|
startPos = y;
|
||||||
|
endPos = y+1;
|
||||||
|
numInCurrent = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
endPos = y;
|
||||||
|
numInCurrent++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(y > 0){
|
// if(x > 0){
|
||||||
//add back neighbor
|
// //add back neighbor
|
||||||
|
// }
|
||||||
|
// if(y > 0){
|
||||||
|
// //add back neighbor
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
//close off last box on row
|
||||||
|
// FirstPhaseBox boxy = new FirstPhaseBox(1, 1, 1, 1, 1);
|
||||||
|
firstPassBoxes.add(new FirstPhaseBox(x,startPos,endPos,currentMin,currentMax));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//phase two
|
||||||
|
//???
|
||||||
|
List<SecondPhaseBox> secondPhaseBoxes = new LinkedList();
|
||||||
|
List<SecondPhaseBox> toRemove = new LinkedList();
|
||||||
|
for(FirstPhaseBox firstPhaseBox : firstPassBoxes){
|
||||||
|
SecondPhaseBox newBox = new SecondPhaseBox(
|
||||||
|
firstPhaseBox.x,firstPhaseBox.yStart,
|
||||||
|
firstPhaseBox.x+1,firstPhaseBox.yEnd,
|
||||||
|
firstPhaseBox.minHeight,firstPhaseBox.maxHeight);
|
||||||
|
// System.out.println(
|
||||||
|
// firstPhaseBox.x + " " +
|
||||||
|
// firstPhaseBox.yStart + " " +
|
||||||
|
// (firstPhaseBox.x+1) + " " +
|
||||||
|
// firstPhaseBox.yEnd + " " +
|
||||||
|
// firstPhaseBox.minHeight + " " +
|
||||||
|
// firstPhaseBox.maxHeight
|
||||||
|
// );
|
||||||
|
// System.out.println(
|
||||||
|
// "(" + (newBox.boundMinX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth()) + ", " +
|
||||||
|
// (newBox.minHeight - 0.5f) + ", " +
|
||||||
|
// (newBox.boundMinY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ") (" +
|
||||||
|
// (newBox.boundMaxX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth()) + ", " +
|
||||||
|
// (newBox.maxHeight + 0.5f) + ", " +
|
||||||
|
// (newBox.boundMaxY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ")"
|
||||||
|
// );
|
||||||
|
toRemove.clear();
|
||||||
|
//TODO: iterate this backwards and check for x adjacency, if no adjacency end loop early
|
||||||
|
for(SecondPhaseBox interim : secondPhaseBoxes){
|
||||||
|
if(firstPhaseBox.yStart == interim.boundMinY && firstPhaseBox.yEnd == interim.boundMaxY && firstPhaseBox.x == interim.boundMaxX){
|
||||||
|
for(SecondPhaseBox neighbor : interim.getNeighbors()){
|
||||||
|
neighbor.removeNeighbor(interim);
|
||||||
|
interim.removeNeighbor(neighbor);
|
||||||
|
neighbor.addNeighbor(newBox);
|
||||||
|
newBox.addNeighbor(neighbor);
|
||||||
|
// System.out.println("ADD NEIGHBOR: " + neighbor.boundMaxX + " " + neighbor.boundMaxY + " " + neighbor.boundMinX + " " + neighbor.boundMinY);
|
||||||
|
}
|
||||||
|
toRemove.add(interim);
|
||||||
|
newBox.setBoundMinX(interim.getBoundMinX());
|
||||||
|
//TODO: calculate new min/max height
|
||||||
|
} else {
|
||||||
|
//because of the way the rectangles are constructed, we can never have a neighbor along y axis
|
||||||
|
//only neighbors will be behind us
|
||||||
|
if(newBox.boundMinX == interim.boundMaxX && !toRemove.contains(interim)){
|
||||||
|
if(
|
||||||
|
(interim.boundMaxY < newBox.boundMaxY && interim.boundMaxY > newBox.boundMinY) ||
|
||||||
|
(interim.boundMinY < newBox.boundMaxY && interim.boundMinY > newBox.boundMinY) ||
|
||||||
|
(newBox.boundMaxY < interim.boundMaxY && newBox.boundMaxY > interim.boundMinY) ||
|
||||||
|
(newBox.boundMinY < interim.boundMaxY && newBox.boundMinY > interim.boundMinY)
|
||||||
|
){
|
||||||
|
// System.out.println("ADD INTERIM: " + interim.boundMaxX + " " + interim.boundMaxY + " " + interim.boundMinX + " " + interim.boundMinY);
|
||||||
|
newBox.addNeighbor(interim);
|
||||||
|
interim.addNeighbor(newBox);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
secondPhaseBoxes.removeAll(toRemove);
|
||||||
|
secondPhaseBoxes.add(newBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int id = 0;
|
||||||
|
for(SecondPhaseBox box : secondPhaseBoxes){
|
||||||
|
box.setId(id);
|
||||||
|
// System.out.println("getId:" + box.getId());
|
||||||
|
id++;
|
||||||
|
// System.out.println(
|
||||||
|
// "(" + (box.boundMinX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth()) + ", " +
|
||||||
|
// (box.minHeight - 0.5f) + ", " +
|
||||||
|
// (box.boundMinY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ") (" +
|
||||||
|
// (box.boundMaxX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth() - 1) + ", " +
|
||||||
|
// (box.maxHeight + 0.5f) + ", " +
|
||||||
|
// (box.boundMaxY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()) + ")"
|
||||||
|
// );
|
||||||
|
// System.out.println(box.neighbors.size());
|
||||||
|
//why the -1? I think the array fiddling above is causing the bounds to be off normally
|
||||||
|
//this fixes that
|
||||||
|
NavCube cube = new NavCube(
|
||||||
|
box.boundMinX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth(),
|
||||||
|
box.minHeight - 0.5f,
|
||||||
|
box.boundMinY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth(),
|
||||||
|
box.boundMaxX + chunk.getWorldX() * Globals.serverTerrainManager.getChunkWidth(),
|
||||||
|
box.maxHeight + 0.5f,
|
||||||
|
box.boundMaxY + chunk.getWorldY() * Globals.serverTerrainManager.getChunkWidth()
|
||||||
|
);
|
||||||
|
rVal.addNode(cube);
|
||||||
|
}
|
||||||
|
|
||||||
|
id = 0;
|
||||||
|
for(NavShape shape : rVal.getNodes()){
|
||||||
|
NavCube cube = (NavCube)shape;
|
||||||
|
|
||||||
|
SecondPhaseBox currentBox = secondPhaseBoxes.get(id);
|
||||||
|
// System.out.println("getId:" + currentBox.getId());
|
||||||
|
id++;
|
||||||
|
for(SecondPhaseBox neighbor : currentBox.getNeighbors()){
|
||||||
|
//TODO: solve bug where items are getting picked up from not in second phase boxes
|
||||||
|
if(!secondPhaseBoxes.contains(neighbor)){
|
||||||
|
LoggerInterface.loggerGameLogic.WARNING("Found bad neighbor adjacency in navmesh generation");
|
||||||
|
for(SecondPhaseBox newNeighbor : secondPhaseBoxes){
|
||||||
|
if(newNeighbor.boundMaxX >= neighbor.boundMaxX &&
|
||||||
|
newNeighbor.boundMaxY >= neighbor.boundMaxY &&
|
||||||
|
newNeighbor.boundMinX <= neighbor.boundMinX &&
|
||||||
|
newNeighbor.boundMinY <= neighbor.boundMinY
|
||||||
|
){
|
||||||
|
cube.addNodeNeighbor(rVal.getNodes().get(newNeighbor.getId()));
|
||||||
|
LoggerInterface.loggerGameLogic.WARNING("Managed to replace bad neighbor");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// System.out.println("ERR!");
|
||||||
|
// System.out.println(neighbor.boundMaxX + " " + neighbor.boundMaxY + " " + neighbor.boundMinX + " " + neighbor.boundMinY);
|
||||||
|
} else {
|
||||||
|
cube.addNodeNeighbor(rVal.getNodes().get(neighbor.getId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// System.out.println(cube.getNodeNeighbors().size());
|
||||||
|
}
|
||||||
|
// System.out.println();
|
||||||
|
// System.out.println();
|
||||||
|
// System.out.println(secondPhaseBoxes.size());
|
||||||
|
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class FirstPhaseBox {
|
||||||
|
int x;
|
||||||
|
int yStart;
|
||||||
|
int yEnd;
|
||||||
|
float minHeight;
|
||||||
|
float maxHeight;
|
||||||
|
|
||||||
|
public FirstPhaseBox(int x, int yStart, int yEnd, float minHeight, float maxHeight) {
|
||||||
|
this.x = x;
|
||||||
|
this.yStart = yStart;
|
||||||
|
this.yEnd = yEnd;
|
||||||
|
this.minHeight = minHeight;
|
||||||
|
this.maxHeight = maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getyStart() {
|
||||||
|
return yStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getyEnd() {
|
||||||
|
return yEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMinHeight() {
|
||||||
|
return minHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getMaxHeight() {
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class SecondPhaseBox {
|
||||||
|
|
||||||
|
float minHeight;
|
||||||
|
float maxHeight;
|
||||||
|
int boundMinX;
|
||||||
|
int boundMinY;
|
||||||
|
int boundMaxX;
|
||||||
|
int boundMaxY;
|
||||||
|
List<SecondPhaseBox> neighbors = new LinkedList();
|
||||||
|
int id = -1;
|
||||||
|
|
||||||
|
SecondPhaseBox(int boundMinX, int boundMinY, int boundMaxX, int boundMaxY, float minHeight, float maxHeight){
|
||||||
|
this.boundMinX = boundMinX;
|
||||||
|
this.boundMinY = boundMinY;
|
||||||
|
|
||||||
|
this.boundMaxX = boundMaxX;
|
||||||
|
this.boundMaxY = boundMaxY;
|
||||||
|
|
||||||
|
this.minHeight = minHeight;
|
||||||
|
this.maxHeight = maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
float getMinHeight(){
|
||||||
|
return minHeight;
|
||||||
|
}
|
||||||
|
float getMaxHeight(){
|
||||||
|
return maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBoundMinX() {
|
||||||
|
return boundMinX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBoundMinY() {
|
||||||
|
return boundMinY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBoundMaxX() {
|
||||||
|
return boundMaxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBoundMaxY() {
|
||||||
|
return boundMaxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinHeight(float minHeight) {
|
||||||
|
this.minHeight = minHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMaxHeight(float maxHeight) {
|
||||||
|
this.maxHeight = maxHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoundMinX(int boundMinX) {
|
||||||
|
this.boundMinX = boundMinX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoundMinY(int boundMinY) {
|
||||||
|
this.boundMinY = boundMinY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoundMaxX(int boundMaxX) {
|
||||||
|
this.boundMaxX = boundMaxX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoundMaxY(int boundMaxY) {
|
||||||
|
this.boundMaxY = boundMaxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SecondPhaseBox> getNeighbors() {
|
||||||
|
return neighbors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNeighbor(SecondPhaseBox neighbor){
|
||||||
|
neighbors.add(neighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeNeighbor(SecondPhaseBox neighbor){
|
||||||
|
neighbors.remove(neighbor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,31 @@
|
|||||||
|
package electrosphere.game.server.pathfinding.blocker;
|
||||||
|
|
||||||
|
import electrosphere.main.Globals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Why it's own class? in case we want to use separate logic for non-heightfield chunks later (dungeons mby)
|
||||||
|
*
|
||||||
|
* @author amaterasu
|
||||||
|
*/
|
||||||
|
public class NavBlocker {
|
||||||
|
|
||||||
|
boolean[][] heightfieldBlocker;
|
||||||
|
|
||||||
|
public NavBlocker(){
|
||||||
|
heightfieldBlocker = new boolean[Globals.serverTerrainManager.getAugmentedChunkWidth()][Globals.serverTerrainManager.getAugmentedChunkWidth()];
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavBlocker(boolean[][] field){
|
||||||
|
heightfieldBlocker = field;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[][] getHeightfieldBlocker(){
|
||||||
|
return heightfieldBlocker;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeightfieldBlockerValue(int x, int y, boolean value){
|
||||||
|
heightfieldBlocker[x][y] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
package electrosphere.game.server.pathfinding.blocker;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author amaterasu
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* A cache of the blocker fields for terrain meshes
|
||||||
|
*/
|
||||||
|
public class NavTerrainBlockerCache {
|
||||||
|
//Basic idea is we associate string that contains chunk x&y with elevation
|
||||||
|
//While we incur a penalty with converting ints -> string, think this will
|
||||||
|
//offset regenerating the array every time we want a new one
|
||||||
|
int cacheSize = 50;
|
||||||
|
HashMap<String, NavBlocker> navBlockerMapCache = new HashMap();
|
||||||
|
ArrayList<String> navBlockerMapCacheContents = new ArrayList();
|
||||||
|
|
||||||
|
|
||||||
|
public String getKey(int x, int y){
|
||||||
|
return x + "-" + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NavBlocker getBlocker(int x, int y){
|
||||||
|
NavBlocker rVal;
|
||||||
|
String key = getKey(x,y);
|
||||||
|
//if in cache
|
||||||
|
if(navBlockerMapCache.containsKey(key)){
|
||||||
|
navBlockerMapCacheContents.remove(key);
|
||||||
|
navBlockerMapCacheContents.add(0, key);
|
||||||
|
rVal = navBlockerMapCache.get(key);
|
||||||
|
return rVal;
|
||||||
|
} else {
|
||||||
|
//else fetch from sql if available
|
||||||
|
|
||||||
|
}
|
||||||
|
//else, create an empty one I guess
|
||||||
|
rVal = new NavBlocker();
|
||||||
|
rVal.setHeightfieldBlockerValue(5,5,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(6,5,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(5,6,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(6,6,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(7,5,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(11,5,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(5,8,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(5,22,true);
|
||||||
|
rVal.setHeightfieldBlockerValue(5,50,true);
|
||||||
|
if(navBlockerMapCache.size() > cacheSize){
|
||||||
|
String oldChunk = navBlockerMapCacheContents.remove(navBlockerMapCacheContents.size() - 1);
|
||||||
|
navBlockerMapCache.remove(oldChunk);
|
||||||
|
}
|
||||||
|
navBlockerMapCacheContents.add(0, key);
|
||||||
|
navBlockerMapCache.put(key, rVal);
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -19,7 +19,7 @@ public class NavCube extends NavShape {
|
|||||||
Vector3d minPoint;
|
Vector3d minPoint;
|
||||||
Vector3d maxPoint;
|
Vector3d maxPoint;
|
||||||
|
|
||||||
List<NavCube> neighbors = new LinkedList();
|
List<NavShape> neighbors = new LinkedList();
|
||||||
|
|
||||||
|
|
||||||
public NavCube(double minX, double minY, double minZ, double maxX, double maxY, double maxZ){
|
public NavCube(double minX, double minY, double minZ, double maxX, double maxY, double maxZ){
|
||||||
@ -28,12 +28,12 @@ public class NavCube extends NavShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addNeighbor(NavCube neighbor){
|
public void addNodeNeighbor(NavShape neighbor){
|
||||||
neighbors.add(neighbor);
|
neighbors.add(neighbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<NavCube> getNeighbors(){
|
public List<NavShape> getNodeNeighbors(){
|
||||||
return neighbors;
|
return neighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +42,13 @@ public class NavCube extends NavShape {
|
|||||||
return x >= minPoint.x && y >= minPoint.y && z >= minPoint.z && x <= maxPoint.x && y <= maxPoint.y && z <= maxPoint.z;
|
return x >= minPoint.x && y >= minPoint.y && z >= minPoint.z && x <= maxPoint.x && y <= maxPoint.y && z <= maxPoint.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Vector3d getMinPoint(){
|
||||||
|
return minPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vector3d getMaxPoint(){
|
||||||
|
return maxPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,14 +13,14 @@ public class NavMesh {
|
|||||||
String method;
|
String method;
|
||||||
|
|
||||||
List<NavShape> navNodes = new LinkedList();
|
List<NavShape> navNodes = new LinkedList();
|
||||||
List<NavMesh> neighbors = new LinkedList();
|
List<NavMesh> meshNeighbors = new LinkedList();
|
||||||
|
|
||||||
public void addNeighbor(NavMesh neighbor){
|
public void addMeshNeighbor(NavMesh neighbor){
|
||||||
neighbors.add(neighbor);
|
meshNeighbors.add(neighbor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<NavMesh> getNeighbors(){
|
public List<NavMesh> getMeshNeighbors(){
|
||||||
return neighbors;
|
return meshNeighbors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addNode(NavShape node){
|
public void addNode(NavShape node){
|
||||||
|
|||||||
@ -8,9 +8,9 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public abstract class NavShape {
|
public abstract class NavShape {
|
||||||
|
|
||||||
public abstract void addNeighbor(NavCube neighbor);
|
public abstract void addNodeNeighbor(NavShape neighbor);
|
||||||
|
|
||||||
public abstract List<NavCube> getNeighbors();
|
public abstract List<NavShape> getNodeNeighbors();
|
||||||
|
|
||||||
public abstract boolean containsPoint(double x, double y, double z);
|
public abstract boolean containsPoint(double x, double y, double z);
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ package electrosphere.game.server.saves;
|
|||||||
import electrosphere.game.server.db.DatabaseUtils;
|
import electrosphere.game.server.db.DatabaseUtils;
|
||||||
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.game.server.world.ServerWorldData;
|
import electrosphere.game.server.world.ServerWorldData;
|
||||||
import electrosphere.game.server.world.datacell.DataCellManager;
|
import electrosphere.game.server.datacell.DataCellManager;
|
||||||
import electrosphere.main.Globals;
|
import electrosphere.main.Globals;
|
||||||
import electrosphere.util.FileUtils;
|
import electrosphere.util.FileUtils;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|||||||
@ -24,11 +24,11 @@ public class ServerTerrainChunk {
|
|||||||
this.randomizer = randomizer;
|
this.randomizer = randomizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServerTerrainChunk getArenaChunk(int width){
|
public static ServerTerrainChunk getArenaChunk(int width, int x, int y){
|
||||||
float[][] macroValues = new float[5][5];
|
float[][] macroValues = new float[5][5];
|
||||||
long[][] randomizer = new long[5][5];
|
long[][] randomizer = new long[5][5];
|
||||||
float[][] heightmap = new float[width + 1][width + 1];
|
float[][] heightmap = new float[width + 1][width + 1];
|
||||||
ServerTerrainChunk rVal = new ServerTerrainChunk(0, 0, heightmap, macroValues, randomizer);
|
ServerTerrainChunk rVal = new ServerTerrainChunk(x, y, heightmap, macroValues, randomizer);
|
||||||
return rVal;
|
return rVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -296,7 +296,7 @@ public class ServerTerrainManager {
|
|||||||
returnedChunk = elevationMapCache.get(key);
|
returnedChunk = elevationMapCache.get(key);
|
||||||
return returnedChunk;
|
return returnedChunk;
|
||||||
} else {
|
} else {
|
||||||
returnedChunk = ServerTerrainChunk.getArenaChunk(dynamicInterpolationRatio + 1);
|
returnedChunk = ServerTerrainChunk.getArenaChunk(dynamicInterpolationRatio + 1, x, y);
|
||||||
elevationMapCache.put(key, returnedChunk);
|
elevationMapCache.put(key, returnedChunk);
|
||||||
elevationMapCacheContents.add(key);
|
elevationMapCacheContents.add(key);
|
||||||
return returnedChunk;
|
return returnedChunk;
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
package electrosphere.game.server.world;
|
package electrosphere.game.server.world;
|
||||||
|
|
||||||
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
||||||
import electrosphere.game.server.world.datacell.ServerDataCell;
|
import electrosphere.game.server.datacell.ServerDataCell;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.joml.Vector3f;
|
import org.joml.Vector3f;
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import electrosphere.game.server.terrain.manager.ServerTerrainManager;
|
|||||||
import electrosphere.game.server.town.Town;
|
import electrosphere.game.server.town.Town;
|
||||||
import electrosphere.game.server.world.ServerWorldData;
|
import electrosphere.game.server.world.ServerWorldData;
|
||||||
import electrosphere.game.server.world.MacroData;
|
import electrosphere.game.server.world.MacroData;
|
||||||
import electrosphere.game.server.world.datacell.DataCellManager;
|
import electrosphere.game.server.datacell.DataCellManager;
|
||||||
import electrosphere.game.state.MicroSimulation;
|
import electrosphere.game.state.MicroSimulation;
|
||||||
import electrosphere.menu.Menu;
|
import electrosphere.menu.Menu;
|
||||||
import electrosphere.net.client.ClientNetworking;
|
import electrosphere.net.client.ClientNetworking;
|
||||||
@ -46,6 +46,7 @@ import electrosphere.renderer.RenderingEngine;
|
|||||||
import electrosphere.renderer.ShaderProgram;
|
import electrosphere.renderer.ShaderProgram;
|
||||||
import electrosphere.engine.assetmanager.AssetDataStrings;
|
import electrosphere.engine.assetmanager.AssetDataStrings;
|
||||||
import electrosphere.engine.assetmanager.AssetManager;
|
import electrosphere.engine.assetmanager.AssetManager;
|
||||||
|
import electrosphere.game.server.pathfinding.NavMeshManager;
|
||||||
import electrosphere.renderer.ui.WidgetManager;
|
import electrosphere.renderer.ui.WidgetManager;
|
||||||
import electrosphere.renderer.ui.WidgetUtils;
|
import electrosphere.renderer.ui.WidgetUtils;
|
||||||
import electrosphere.renderer.ui.font.FontUtils;
|
import electrosphere.renderer.ui.font.FontUtils;
|
||||||
@ -242,6 +243,8 @@ public class Globals {
|
|||||||
//constant for how far in game units you have to move to load chunks
|
//constant for how far in game units you have to move to load chunks
|
||||||
public static DrawCellManager drawCellManager;
|
public static DrawCellManager drawCellManager;
|
||||||
|
|
||||||
|
//navmesh manager
|
||||||
|
public static NavMeshManager navMeshManager;
|
||||||
|
|
||||||
//famous fuckin last words, but temporary solution
|
//famous fuckin last words, but temporary solution
|
||||||
//global arraylist of values for the skybox colors
|
//global arraylist of values for the skybox colors
|
||||||
@ -320,6 +323,8 @@ public class Globals {
|
|||||||
aiManager = new AIManager();
|
aiManager = new AIManager();
|
||||||
//collision engine
|
//collision engine
|
||||||
collisionEngine = new CollisionEngine();
|
collisionEngine = new CollisionEngine();
|
||||||
|
//nav mesh manager
|
||||||
|
navMeshManager = new NavMeshManager();
|
||||||
//game config
|
//game config
|
||||||
gameConfigDefault = electrosphere.game.config.Config.loadDefaultConfig();
|
gameConfigDefault = electrosphere.game.config.Config.loadDefaultConfig();
|
||||||
gameConfigCurrent = gameConfigDefault;
|
gameConfigCurrent = gameConfigDefault;
|
||||||
|
|||||||
@ -7,6 +7,9 @@ import electrosphere.entity.EntityUtils;
|
|||||||
import electrosphere.entity.types.hitbox.HitboxData;
|
import electrosphere.entity.types.hitbox.HitboxData;
|
||||||
import electrosphere.entity.types.hitbox.HitboxUtils;
|
import electrosphere.entity.types.hitbox.HitboxUtils;
|
||||||
import electrosphere.game.config.creature.type.CollidableTemplate;
|
import electrosphere.game.config.creature.type.CollidableTemplate;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavCube;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavMesh;
|
||||||
|
import electrosphere.game.server.pathfinding.navmesh.NavShape;
|
||||||
import electrosphere.logger.LoggerInterface;
|
import electrosphere.logger.LoggerInterface;
|
||||||
import electrosphere.main.Globals;
|
import electrosphere.main.Globals;
|
||||||
import static electrosphere.main.Main.deltaTime;
|
import static electrosphere.main.Main.deltaTime;
|
||||||
@ -545,6 +548,31 @@ public class RenderingEngine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(Globals.userSettings.graphicsDebugDrawNavmesh()){
|
||||||
|
Model shapeGraphicsModel;
|
||||||
|
for(NavMesh mesh : Globals.navMeshManager.getMeshes()){
|
||||||
|
for(NavShape shape : mesh.getNodes()){
|
||||||
|
if(shape instanceof NavCube){
|
||||||
|
if((shapeGraphicsModel = Globals.assetManager.fetchModel("Models/unitcube.fbx")) != null){
|
||||||
|
NavCube cube = (NavCube)shape;
|
||||||
|
Vector3d position = new Vector3d(cube.getMinPoint()).add(cube.getMaxPoint()).mul(0.5);
|
||||||
|
Vector3f scale = new Vector3f((float)(cube.getMaxPoint().x-cube.getMinPoint().x)/2,(float)(cube.getMaxPoint().y-cube.getMinPoint().y)/2,(float)(cube.getMaxPoint().z-cube.getMinPoint().z)/2);
|
||||||
|
Quaternionf rotation = new Quaternionf();
|
||||||
|
//calculate camera-modified vector3f
|
||||||
|
Vector3f cameraModifiedPosition = new Vector3f((float)position.x,(float)position.y,(float)position.z).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera));
|
||||||
|
modelTransformMatrix.identity();
|
||||||
|
modelTransformMatrix.translate(cameraModifiedPosition);
|
||||||
|
modelTransformMatrix.rotate(rotation);
|
||||||
|
// modelTransformMatrix.translate(template.getOffsetX(),template.getOffsetY(),template.getOffsetZ()); //center sphere
|
||||||
|
modelTransformMatrix.scale(scale);
|
||||||
|
shapeGraphicsModel.modelMatrix = modelTransformMatrix;
|
||||||
|
shapeGraphicsModel.draw(true, true, false, true, true, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// glBindVertexArray(0);
|
// glBindVertexArray(0);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user