This commit is contained in:
Felix Cravic 2020-07-24 02:49:55 +02:00
parent 7b5107f59d
commit b54599a1f1
12 changed files with 22 additions and 236 deletions

View File

@ -69,9 +69,6 @@ public class MinecraftServer {
public static final String THREAD_NAME_BLOCK_BATCH = "Ms-BlockBatchPool";
public static final int THREAD_COUNT_BLOCK_BATCH = 2;
public static final String THREAD_NAME_ENTITIES_PATHFINDING = "Ms-EntitiesPathFinding";
public static final int THREAD_COUNT_ENTITIES_PATHFINDING = 2;
public static final String THREAD_NAME_SCHEDULER = "Ms-SchedulerPool";
public static final int THREAD_COUNT_SCHEDULER = 1;

View File

@ -5,7 +5,7 @@ public enum Attribute {
MAX_HEALTH("generic.max_health", 20, 1024),
FOLLOW_RANGE("generic.follow_range", 32, 2048),
KNOCKBACK_RESISTANCE("generic.knockback_resistance", 0, 1),
MOVEMENT_SPEED("generic.movement_speed", 0.7f, 1024),
MOVEMENT_SPEED("generic.movement_speed", 0.2f, 1024),
ATTACK_DAMAGE("generic.attack_damage", 2, 2048),
ATTACK_SPEED("generic.attack_speed", 4, 1024),
FLYING_SPEED("generic.flying_speed", 0.4f, 1024),

View File

@ -24,7 +24,6 @@ public class BenchmarkManager {
threads.add(THREAD_NAME_MAIN_UPDATE);
threads.add(THREAD_NAME_PACKET_WRITER);
threads.add(THREAD_NAME_BLOCK_BATCH);
threads.add(THREAD_NAME_ENTITIES_PATHFINDING);
threads.add(THREAD_NAME_SCHEDULER);
threads.add(THREAD_NAME_TICK);
}

View File

@ -3,7 +3,7 @@ package net.minestom.server.entity;
import com.extollit.gaming.ai.path.HydrazinePathFinder;
import com.extollit.gaming.ai.path.model.PathObject;
import net.minestom.server.collision.CollisionUtils;
import net.minestom.server.entity.pathfinding.hydrazine.PFPathingEntity;
import net.minestom.server.entity.pathfinding.PFPathingEntity;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.event.item.ArmorEquipEvent;
import net.minestom.server.instance.Instance;
@ -52,8 +52,12 @@ public abstract class EntityCreature extends LivingEntity {
// Path finding
path = pathFinder.update();
if (path != null)
if (path != null) {
path.update(pathingEntity);
if (path.done()) {
pathFinder.reset();
}
}
}
@Override
@ -261,6 +265,14 @@ public abstract class EntityCreature extends LivingEntity {
setVelocity(velocity);
}
/**
* Retrieve the path to {@code position} and ask the entity to follow the path
* <p>
* The position is cloned, if you want the entity to continually follow this position object
* you need to call this when you want the path to update
*
* @param position the position to find the path to
*/
public void setPathTo(Position position) {
position = position.clone();
this.path = pathFinder.initiatePathTo(position.getX(), position.getY(), position.getZ());

View File

@ -1,187 +0,0 @@
package net.minestom.server.entity.pathfinding;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.block.Block;
import net.minestom.server.utils.BlockPosition;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class AStarPathfinder {
// TODO ladder, jump, etc...
// TODO include BoundingBox support
private boolean canClimbLadder;
private boolean canSwim;
private boolean canJump;
public static LinkedList<BlockPosition> getPath(Instance instance,
BlockPosition start, BlockPosition end,
int maxCheck) {
long time = System.nanoTime();
List<Node> open = new ArrayList<>();
List<Node> closed = new ArrayList<>();
Node startNode = Node.fromBlockPosition(start);
Node endNode = Node.fromBlockPosition(end);
open.add(startNode);
int checkCount = 0;
while (!open.isEmpty()) {
Node current = getCurrentNode(open);
open.remove(current);
closed.add(current);
if (isTargetNode(end, current)) {
System.out.println("found in: " + (System.nanoTime() - time) + " ns");
return buildPath(current);
}
for (Node neighbor : getNeighbors(instance, current)) {
if (isInList(closed, neighbor))
continue;
boolean isInOpen = isInList(open, neighbor);
if (isShorter(neighbor, current) || !isInOpen) {
neighbor.parent = current;
neighbor.g = getTentativeGScore(neighbor, current);
neighbor.f = neighbor.g + getDistance(neighbor, endNode);
if (!isInOpen) {
open.add(neighbor);
}
}
}
// To do not check the whole world
checkCount++;
if (checkCount >= maxCheck)
break;
}
return null;
}
private static List<Node> getNeighbors(Instance instance, Node current) {
List<Node> result = new ArrayList<>();
BlockPosition currentBlockPosition = current.getBlockPosition();
for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; y++) {
for (int z = -1; z < 2; z++) {
if (x == 0 && y == 0 && z == 0)
continue;
BlockPosition neighbor = currentBlockPosition.clone().add(x, y, z);
if (canAccessBlock(instance, currentBlockPosition, neighbor)) {
Node node = Node.fromBlockPosition(neighbor);
result.add(node);
}
}
}
}
return result;
}
private static Node getCurrentNode(List<Node> open) {
Node closest = null;
for (Node node : open) {
if (closest == null || node.f < closest.f) {
closest = node;
}
}
return closest;
}
private static boolean isTargetNode(BlockPosition target, Node node) {
return target.getX() == node.getX() &&
target.getY() == node.getY() &&
target.getZ() == node.getZ();
}
private static boolean canAccessBlock(Instance instance, BlockPosition current, BlockPosition target) {
if (instance.getChunkAt(target) == null)
return false;
Block targetBlock = Block.fromId(instance.getBlockId(target));
Block belowBlock = Block.fromId(instance.getBlockId(target.clone().add(0, -1, 0)));
boolean result = !targetBlock.isSolid() && belowBlock.isSolid();
return result;
}
private static boolean isInList(List<Node> list, Node node) {
for (Node close : list) {
if (close.getX() == node.getX() &&
close.getY() == node.getY() &&
close.getZ() == node.getZ())
return true;
}
return false;
}
private static int getDistance(Node node1, Node node2) {
return node1.blockPosition.getDistance(node2.blockPosition);
}
private static int getTentativeGScore(Node neighbor, Node current) {
return neighbor.g + getDistance(neighbor, current);
}
private static boolean isShorter(Node neighbor, Node current) {
return getTentativeGScore(neighbor, current) < neighbor.g;
}
private static LinkedList<BlockPosition> buildPath(Node finalNode) {
LinkedList<BlockPosition> result = new LinkedList<>();
Node cache = finalNode;
while (cache != null) {
result.add(cache.blockPosition);
cache = cache.parent;
}
// Make the list start->end
Collections.reverse(result);
return result;
}
private static class Node {
public int g, f;
public Node parent;
private int x, y, z;
private BlockPosition blockPosition;
public Node(BlockPosition blockPosition) {
this.x = blockPosition.getX();
this.y = blockPosition.getY();
this.z = blockPosition.getZ();
this.blockPosition = blockPosition.clone();
}
public static Node fromBlockPosition(BlockPosition blockPosition) {
Node node = new Node(blockPosition);
return node;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
public BlockPosition getBlockPosition() {
return blockPosition;
}
}
}

View File

@ -1,35 +0,0 @@
package net.minestom.server.entity.pathfinding;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Entity;
import net.minestom.server.instance.Instance;
import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.Position;
import net.minestom.server.utils.thread.MinestomThread;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
public class EntityPathFinder {
private static ExecutorService pathfindingPool = new MinestomThread(MinecraftServer.THREAD_COUNT_ENTITIES_PATHFINDING, MinecraftServer.THREAD_NAME_ENTITIES_PATHFINDING);
private Entity entity;
public EntityPathFinder(Entity entity) {
this.entity = entity;
}
public void getPath(Position target, int maxCheck, Consumer<LinkedList<BlockPosition>> consumer) {
pathfindingPool.execute(() -> {
Instance instance = entity.getInstance();
BlockPosition start = entity.getPosition().toBlockPosition();
BlockPosition end = target.toBlockPosition();
consumer.accept(AStarPathfinder.getPath(instance, start, end, maxCheck));
});
}
}

View File

@ -1,4 +1,4 @@
package net.minestom.server.entity.pathfinding.hydrazine;
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockDescription;
import net.minestom.server.instance.block.Block;

View File

@ -1,4 +1,4 @@
package net.minestom.server.entity.pathfinding.hydrazine;
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockObject;
import com.extollit.linalg.immutable.AxisAlignedBBox;

View File

@ -1,4 +1,4 @@
package net.minestom.server.entity.pathfinding.hydrazine;
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.ColumnarOcclusionFieldList;
import com.extollit.gaming.ai.path.model.IBlockDescription;

View File

@ -1,4 +1,4 @@
package net.minestom.server.entity.pathfinding.hydrazine;
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IBlockObject;
import com.extollit.gaming.ai.path.model.IColumnarSpace;

View File

@ -1,4 +1,4 @@
package net.minestom.server.entity.pathfinding.hydrazine;
package net.minestom.server.entity.pathfinding;
import com.extollit.gaming.ai.path.model.IPathingEntity;
import com.extollit.linalg.immutable.Vec3d;
@ -75,7 +75,7 @@ public class PFPathingEntity implements IPathingEntity {
public void moveTo(Vec3d position) {
final Position entityPosition = entity.getPosition();
final float entityY = entityPosition.getY();
final float speed = entity.getAttributeValue(Attribute.MOVEMENT_SPEED) / 5;
final float speed = entity.getAttributeValue(Attribute.MOVEMENT_SPEED);
final float x = (float) position.x;
final float y = (float) position.y;
final float z = (float) position.z;

View File

@ -5,7 +5,7 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.data.Data;
import net.minestom.server.data.DataContainer;
import net.minestom.server.entity.*;
import net.minestom.server.entity.pathfinding.hydrazine.PFInstanceSpace;
import net.minestom.server.entity.pathfinding.PFInstanceSpace;
import net.minestom.server.event.Event;
import net.minestom.server.event.EventCallback;
import net.minestom.server.event.handler.EventHandler;