@ -13,21 +13,27 @@ import engine.Enum;
@@ -13,21 +13,27 @@ import engine.Enum;
import engine.Enum.GameObjectType ;
import engine.Enum.ModType ;
import engine.Enum.SourceType ;
import engine.InterestManagement.WorldGrid ;
import engine.exception.MsgSendException ;
import engine.gameManager.BuildingManager ;
import engine.gameManager.ChatManager ;
import engine.gameManager.MovementManager ;
import engine.math.Bounds ;
import engine.math.Vector3fImmutable ;
import engine.mobileAI.Threads.MobAIThread ;
import engine.net.client.msg.MoveToPointMsg ;
import engine.objects.* ;
import engine.server.MBServerStatics ;
import org.pmw.tinylog.Logger ;
import java.util.ArrayList ;
import java.util.concurrent.ThreadLocalRandom ;
import static engine.math.FastMath.sqr ;
import static engine.math.FastMath.sqrt ;
public class MovementUtilities {
private static final int cellGap = 4 ;
public static boolean inRangeOfBindLocation ( Mob agent ) {
@ -291,5 +297,129 @@ public class MovementUtilities {
@@ -291,5 +297,129 @@ public class MovementUtilities {
return false ;
}
public static void pathfind ( AbstractCharacter character , Vector3fImmutable goal ) {
try {
ArrayList < Vector3fImmutable > path = getOptimizedPath ( getPath ( character . loc , goal ) , getPath ( goal , character . loc ) ) ;
if ( path . isEmpty ( ) ) {
( ( Mob ) character ) . setDestination ( character . loc ) ;
return ; //no points to walk to
}
( ( Mob ) character ) . destination = path . get ( 0 ) ;
} catch ( Exception e ) {
//something failed
}
}
public static ArrayList < Vector3fImmutable > getOptimizedPath ( ArrayList < Vector3fImmutable > startToGoal , ArrayList < Vector3fImmutable > goalToStart ) {
ArrayList < Vector3fImmutable > optimalPath = new ArrayList < > ( ) ;
optimalPath . add ( startToGoal . get ( 0 ) ) ;
for ( Vector3fImmutable point : startToGoal )
{
if ( ! goalToStart . contains ( point ) )
{
continue ;
}
optimalPath . add ( point ) ;
}
return optimalPath ;
}
private static ArrayList < Vector3fImmutable > getPath ( Vector3fImmutable start , Vector3fImmutable goal ) {
ArrayList < Vector3fImmutable > path = new ArrayList < > ( ) ;
path . add ( start ) ;
Vector3fImmutable current = start ;
boolean obstructed = false ;
while ( current . distanceSquared ( goal ) > 9 )
{
//gather the 8 cells around the player
ArrayList < Vector3fImmutable > surroundingCells = new ArrayList < > ( ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( cellGap , 0 , 0 ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( cellGap , 0 , cellGap ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( 0 , 0 , cellGap ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( - cellGap , 0 , 0 ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( - cellGap , 0 , - cellGap ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( 0 , 0 , - cellGap ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( - cellGap , 0 , cellGap ) ) ) ;
surroundingCells . add ( current . add ( new Vector3fImmutable ( cellGap , 0 , - cellGap ) ) ) ;
Vector3fImmutable cheapest = new Vector3fImmutable ( - 10000 , 0 , - 10000 ) ;
for ( Vector3fImmutable point : surroundingCells )
{
if ( path . contains ( point ) )
continue ;
Regions region = Regions . getRegionAtLocation ( point ) ;
if ( region ! = null ) {
//if (!region.stairs)
// point.setY(region.center.y);
//else
// point.setY(region.lerpY(point));
path . add ( new Vector3fImmutable ( region . center . x , region . center . y , region . center . z ) ) ; //only use center points when travelling through regions
continue ;
}
if ( pointIsBlocked ( point ) ) {
obstructed = true ;
continue ;
}
if ( getCost ( cheapest , current , goal ) > getCost ( point , current , goal ) )
cheapest = point ;
}
current = cheapest ;
path . add ( cheapest ) ;
}
if ( obstructed ) {
return path ;
} else {
ArrayList < Vector3fImmutable > goalPath = new ArrayList < > ( ) ;
goalPath . add ( goal ) ;
goalPath . add ( start ) ;
return goalPath ; //if the path isn't obstructed we can walk directly from start to the goal
}
}
public static float getCost ( Vector3fImmutable point , Vector3fImmutable start , Vector3fImmutable goal ) {
float gCost = start . distanceSquared ( point ) ;
float hCost = goal . distanceSquared ( point ) ;
return gCost + hCost ;
}
public static boolean pointIsBlocked ( Vector3fImmutable point ) {
//TODO figure out best way to decide if a walking point intersects a mesh collider from a building
Building building = BuildingManager . getBuildingAtLocation ( point ) ;
if ( building = = null ) {
printToPlayers ( point , "No Building Found At: " + point ) ;
return false ; //no building at this location means nothing obstructing the walking path
}
if ( ! collidesWithBuilding ( building , point ) ) {
printToPlayers ( point , "No Building Collision At: " + point ) ;
return false ;
}
if ( Regions . getRegionAtLocation ( point ) ! = null ) {
printToPlayers ( point , "Region Found At: " + point ) ;
return false ;
}
printToPlayers ( point , "Path Blocked At: " + point ) ;
return true ;
}
private static boolean collidesWithBuilding ( Building building , Vector3fImmutable end ) {
MeshBounds mb = Bounds . meshBoundsCache . get ( building . meshUUID ) ;
return ( end . x > mb . minX & & end . x < mb . maxX & & end . z > mb . minZ & & end . z < mb . maxZ ) ;
}
private static void printToPlayers ( Vector3fImmutable loc , String message ) {
for ( AbstractWorldObject awo : WorldGrid . getObjectsInRangePartial ( loc , MBServerStatics . CHARACTER_LOAD_RANGE , MBServerStatics . MASK_PLAYER ) ) {
PlayerCharacter pc = ( PlayerCharacter ) awo ;
ChatManager . chatSystemInfo ( pc , message ) ;
}
}
}