mirror of
https://github.com/Minestom/Minestom.git
synced 2025-03-02 11:21:15 +01:00
WIP EntityFinder
This commit is contained in:
parent
8fef648221
commit
ef1afb9cd9
@ -388,9 +388,9 @@ public final class CommandManager {
|
||||
nodes.add(literalNode);
|
||||
|
||||
// Contains the arguments of the already-parsed syntaxes
|
||||
List<Argument[]> syntaxesArguments = new ArrayList<>();
|
||||
List<Argument<?>[]> syntaxesArguments = new ArrayList<>();
|
||||
// Contains the nodes of an argument
|
||||
Map<Argument, List<DeclareCommandsPacket.Node>> storedArgumentsNodes = new HashMap<>();
|
||||
Map<Argument<?>, List<DeclareCommandsPacket.Node>> storedArgumentsNodes = new HashMap<>();
|
||||
|
||||
for (CommandSyntax syntax : syntaxes) {
|
||||
final CommandCondition commandCondition = syntax.getCommandCondition();
|
||||
@ -406,16 +406,17 @@ public final class CommandManager {
|
||||
// Represent the children of the last node
|
||||
IntList argChildren = null;
|
||||
|
||||
final Argument[] arguments = syntax.getArguments();
|
||||
final Argument<?>[] arguments = syntax.getArguments();
|
||||
for (int i = 0; i < arguments.length; i++) {
|
||||
final Argument argument = arguments[i];
|
||||
final Argument<?> argument = arguments[i];
|
||||
final boolean isFirst = i == 0;
|
||||
final boolean isLast = i == arguments.length - 1;
|
||||
|
||||
// Find shared part
|
||||
boolean foundSharedPart = false;
|
||||
for (Argument[] parsedArguments : syntaxesArguments) {
|
||||
for (Argument<?>[] parsedArguments : syntaxesArguments) {
|
||||
if (ArrayUtils.sameStart(arguments, parsedArguments, i + 1)) {
|
||||
final Argument sharedArgument = parsedArguments[i];
|
||||
final Argument<?> sharedArgument = parsedArguments[i];
|
||||
|
||||
argChildren = new IntArrayList();
|
||||
lastNodes = storedArgumentsNodes.get(sharedArgument);
|
||||
@ -442,9 +443,10 @@ public final class CommandManager {
|
||||
|
||||
if (lastNodes != null) {
|
||||
final int[] children = ArrayUtils.toArray(argChildren);
|
||||
lastNodes.forEach(n -> n.children = n.children == null ?
|
||||
children :
|
||||
ArrayUtils.concatenateIntArrays(n.children, children));
|
||||
lastNodes.forEach(n ->
|
||||
n.children = n.children == null ?
|
||||
children :
|
||||
ArrayUtils.concatenateIntArrays(n.children, children));
|
||||
}
|
||||
|
||||
nodes.add(node);
|
||||
|
@ -59,6 +59,14 @@ public final class MathUtils {
|
||||
return number >= min && number <= max;
|
||||
}
|
||||
|
||||
public static boolean isBetweenUnordered(float number, float compare1, float compare2) {
|
||||
if (compare1 > compare2) {
|
||||
return isBetween(number, compare2, compare1);
|
||||
} else {
|
||||
return isBetween(number, compare1, compare2);
|
||||
}
|
||||
}
|
||||
|
||||
public static int clamp(int value, int min, int max) {
|
||||
if (value < min) {
|
||||
return min;
|
||||
|
@ -1,11 +1,20 @@
|
||||
package net.minestom.server.utils.entity;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2BooleanOpenHashMap;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.utils.MathUtils;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.math.IntRange;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
// TODO
|
||||
|
||||
@ -15,49 +24,223 @@ import java.util.List;
|
||||
*/
|
||||
public class EntityFinder {
|
||||
|
||||
// Commands option
|
||||
private boolean onlySingleEntity;
|
||||
private boolean onlyPlayers;
|
||||
private TargetSelector targetSelector;
|
||||
|
||||
// Simple float
|
||||
private float x, y, z;
|
||||
private float dx, dy, dz;
|
||||
private EntitySort entitySort = EntitySort.ARBITRARY;
|
||||
|
||||
// Range
|
||||
// Position
|
||||
private Position startPosition = new Position();
|
||||
private OptionalDouble dx, dy, dz;
|
||||
private IntRange distance;
|
||||
private IntRange level;
|
||||
|
||||
// By traits
|
||||
private int limit;
|
||||
private EntitySort entitySort;
|
||||
private EntityType entityType;
|
||||
private OptionalInt limit;
|
||||
private ToggleableMap<EntityType> entityTypes;
|
||||
|
||||
public boolean isOnlySingleEntity() {
|
||||
return onlySingleEntity;
|
||||
// Players specific
|
||||
private ToggleableMap<GameMode> gameModes;
|
||||
private IntRange level;
|
||||
|
||||
public EntityFinder setTargetSelector(@NotNull TargetSelector targetSelector) {
|
||||
this.targetSelector = targetSelector;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setOnlySingleEntity(boolean onlySingleEntity) {
|
||||
this.onlySingleEntity = onlySingleEntity;
|
||||
public EntityFinder setEntitySort(@NotNull EntitySort entitySort) {
|
||||
this.entitySort = entitySort;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isOnlyPlayers() {
|
||||
return onlyPlayers;
|
||||
public EntityFinder setStartPosition(@NotNull Position startPosition) {
|
||||
this.startPosition = startPosition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setOnlyPlayers(boolean onlyPlayers) {
|
||||
this.onlyPlayers = onlyPlayers;
|
||||
public EntityFinder setDistance(@NotNull IntRange distance) {
|
||||
this.distance = distance;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityFinder setLimit(int limit) {
|
||||
this.limit = OptionalInt.of(limit);
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityFinder setLevel(@NotNull IntRange level) {
|
||||
this.level = level;
|
||||
return this;
|
||||
}
|
||||
|
||||
public EntityFinder setDifference(double dx, double dy, double dz) {
|
||||
this.dx = OptionalDouble.of(dx);
|
||||
this.dy = OptionalDouble.of(dy);
|
||||
this.dz = OptionalDouble.of(dz);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a list of entities (could be empty) based on the conditions
|
||||
*
|
||||
* @return all entities validating the conditions
|
||||
* @return all entities validating the conditions, can be empty
|
||||
*/
|
||||
public List<Entity> find() {
|
||||
return new ArrayList<>();
|
||||
@NotNull
|
||||
public List<Entity> find(@NotNull Instance instance, @Nullable Entity self) {
|
||||
List<Entity> result = findTarget(instance, targetSelector, startPosition, self);
|
||||
|
||||
// Fast exist if there is nothing to process
|
||||
if (result.isEmpty())
|
||||
return result;
|
||||
|
||||
// Distance argument
|
||||
if (distance != null) {
|
||||
final int minDistance = distance.getMinimum();
|
||||
final int maxDistance = distance.getMaximum();
|
||||
result = result.stream().filter(entity -> {
|
||||
final int distance = (int) entity.getDistance(self);
|
||||
return MathUtils.isBetween(distance, minDistance, maxDistance);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Diff X/Y/Z
|
||||
if (dx.isPresent() || dy.isPresent() || dz.isPresent()) {
|
||||
result = result.stream().filter(entity -> {
|
||||
final Position entityPosition = entity.getPosition();
|
||||
if (dx.isPresent() && !MathUtils.isBetweenUnordered(
|
||||
entityPosition.getX(),
|
||||
startPosition.getX(), (float) dx.getAsDouble()))
|
||||
return false;
|
||||
|
||||
if (dy.isPresent() && !MathUtils.isBetweenUnordered(
|
||||
entityPosition.getY(),
|
||||
startPosition.getY(), (float) dy.getAsDouble()))
|
||||
return false;
|
||||
|
||||
if (dz.isPresent() && !MathUtils.isBetweenUnordered(
|
||||
entityPosition.getZ(),
|
||||
startPosition.getZ(), (float) dz.getAsDouble()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Entity type
|
||||
if (entityTypes != null && !entityTypes.isEmpty()) {
|
||||
final EntityType requirement = entityTypes.requirement;
|
||||
result = result.stream().filter(entity -> {
|
||||
final EntityType entityType = entity.getEntityType();
|
||||
// true if the entity type has not been mentioned or if is accepted
|
||||
return (!entityTypes.containsKey(entityType) && requirement == null) ||
|
||||
Objects.equals(requirement, entityType) ||
|
||||
entityTypes.getBoolean(entityType);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// GameMode
|
||||
if (gameModes != null && !gameModes.isEmpty()) {
|
||||
final GameMode requirement = gameModes.requirement;
|
||||
result = result.stream().filter(entity -> {
|
||||
if (!(entity instanceof Player))
|
||||
return false;
|
||||
|
||||
final GameMode gameMode = ((Player) entity).getGameMode();
|
||||
// true if the entity type has not been mentioned or if is accepted
|
||||
return (!gameModes.containsKey(gameMode) && requirement == null) ||
|
||||
Objects.equals(requirement, gameMode) ||
|
||||
gameModes.getBoolean(gameMode);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// Level
|
||||
if (level != null) {
|
||||
final int minLevel = level.getMinimum();
|
||||
final int maxLevel = level.getMaximum();
|
||||
result = result.stream().filter(entity -> {
|
||||
if (!(entity instanceof Player))
|
||||
return false;
|
||||
|
||||
final int level = ((Player) entity).getLevel();
|
||||
return MathUtils.isBetween(level, minLevel, maxLevel);
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
||||
// Sort & limit
|
||||
if (entitySort != EntitySort.ARBITRARY || limit.isPresent()) {
|
||||
result = result.stream()
|
||||
.sorted((ent1, ent2) -> {
|
||||
switch (entitySort) {
|
||||
case ARBITRARY:
|
||||
case RANDOM:
|
||||
// RANDOM is handled below
|
||||
return 1;
|
||||
case FURTHEST:
|
||||
return startPosition.getDistance(ent1.getPosition()) >
|
||||
startPosition.getDistance(ent2.getPosition()) ?
|
||||
1 : 0;
|
||||
case NEAREST:
|
||||
return startPosition.getDistance(ent1.getPosition()) <
|
||||
startPosition.getDistance(ent2.getPosition()) ?
|
||||
1 : 0;
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
.limit(limit.isPresent() ? limit.getAsInt() : Integer.MAX_VALUE)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (entitySort == EntitySort.RANDOM) {
|
||||
Collections.shuffle(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public enum TargetSelector {
|
||||
NEAREST_PLAYER, RANDOM_PLAYER, ALL_PLAYERS, ALL_ENTITIES, SELF
|
||||
}
|
||||
|
||||
public enum EntitySort {
|
||||
ARBITRARY, FURTHEST, NEAREST, RANDOM
|
||||
}
|
||||
|
||||
private static class ToggleableMap<T> extends Object2BooleanOpenHashMap<T> {
|
||||
|
||||
@Nullable
|
||||
private T requirement;
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<Entity> findTarget(@NotNull Instance instance, @NotNull TargetSelector targetSelector,
|
||||
@NotNull Position startPosition, @Nullable Entity self) {
|
||||
|
||||
if (targetSelector == TargetSelector.NEAREST_PLAYER) {
|
||||
Entity entity = null;
|
||||
float closestDistance = Float.MAX_VALUE;
|
||||
|
||||
Set<Player> instancePlayers = instance.getPlayers();
|
||||
for (Player player : instancePlayers) {
|
||||
final float distance = player.getPosition().getDistance(startPosition);
|
||||
if (distance < closestDistance) {
|
||||
entity = player;
|
||||
closestDistance = distance;
|
||||
}
|
||||
}
|
||||
return Arrays.asList(entity);
|
||||
} else if (targetSelector == TargetSelector.RANDOM_PLAYER) {
|
||||
Set<Player> instancePlayers = instance.getPlayers();
|
||||
final int index = ThreadLocalRandom.current().nextInt(instancePlayers.size());
|
||||
final Player player = instancePlayers.stream().skip(index).findFirst().orElseThrow();
|
||||
return Arrays.asList(player);
|
||||
} else if (targetSelector == TargetSelector.ALL_PLAYERS) {
|
||||
return new ArrayList<>(instance.getPlayers());
|
||||
} else if (targetSelector == TargetSelector.ALL_ENTITIES) {
|
||||
return new ArrayList<>(instance.getEntities());
|
||||
} else if (targetSelector == TargetSelector.SELF) {
|
||||
return Arrays.asList(self);
|
||||
}
|
||||
throw new IllegalStateException("Weird thing happened");
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user