diff options
Diffstat (limited to 'src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelector.java')
-rw-r--r-- | src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelector.java | 405 |
1 files changed, 275 insertions, 130 deletions
diff --git a/src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelector.java b/src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelector.java index 8bfa233..9d41880 100644 --- a/src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelector.java +++ b/src/main/java/org/chrisoft/trashyaddon/commands/CEntitySelector.java @@ -1,25 +1,28 @@ package org.chrisoft.trashyaddon.commands; -import com.google.common.collect.Lists; import com.mojang.brigadier.exceptions.CommandSyntaxException; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.Predicate; -import net.minecraft.client.MinecraftClient; import net.minecraft.client.world.ClientWorld; import net.minecraft.command.argument.EntityArgumentType; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.predicate.NumberRange; +import net.minecraft.resource.featuretoggle.FeatureSet; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; import net.minecraft.text.Texts; import net.minecraft.util.TypeFilter; +import net.minecraft.util.Util; import net.minecraft.util.function.LazyIterationConsumer; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; @@ -27,131 +30,273 @@ import org.chrisoft.trashyaddon.mixin.ClientWorldMixin; import org.jetbrains.annotations.Nullable; public class CEntitySelector { - public static final int MAX_VALUE = Integer.MAX_VALUE; - public static final BiConsumer<Vec3d, List<? extends Entity>> ARBITRARY = (pos, entities) -> { - }; - private static final TypeFilter<Entity, ?> PASSTHROUGH_FILTER = new TypeFilter<Entity, Entity>() { - public Entity downcast(Entity arg) { - return arg; - } - - @Override - public Class<? extends Entity> getBaseClass() { - return Entity.class; - } - }; - private final int limit; - private final boolean includesNonPlayers; - private final boolean localWorldOnly; - private final Predicate<Entity> basePredicate; - private final NumberRange.DoubleRange distance; - private final Function<Vec3d, Vec3d> positionOffset; - @Nullable - private final Box box; - private final BiConsumer<Vec3d, List<? extends Entity>> sorter; - private final boolean senderOnly; - @Nullable - private final String playerName; - @Nullable - private final UUID uuid; - private final TypeFilter<Entity, ?> entityFilter; - private final boolean usesAt; - - public CEntitySelector( - int count, - boolean includesNonPlayers, - boolean localWorldOnly, - Predicate<Entity> basePredicate, - NumberRange.DoubleRange distance, - Function<Vec3d, Vec3d> positionOffset, - @Nullable Box box, - BiConsumer<Vec3d, List<? extends Entity>> sorter, - boolean senderOnly, - @Nullable String playerName, - @Nullable UUID uuid, - @Nullable EntityType<?> type, - boolean usesAt - ) { - this.limit = count; - this.includesNonPlayers = includesNonPlayers; - this.localWorldOnly = localWorldOnly; - this.basePredicate = basePredicate; - this.distance = distance; - this.positionOffset = positionOffset; - this.box = box; - this.sorter = sorter; - this.senderOnly = senderOnly; - this.playerName = playerName; - this.uuid = uuid; - this.entityFilter = (TypeFilter<Entity, ?>)(type == null ? PASSTHROUGH_FILTER : type); - this.usesAt = usesAt; - } - - public int getLimit() { - return this.limit; - } - - public boolean includesNonPlayers() { - return this.includesNonPlayers; - } - - public boolean isSenderOnly() { - return this.senderOnly; - } - - public boolean isLocalWorldOnly() { - return this.localWorldOnly; - } - - public boolean usesAt() { - return this.usesAt; - } - - private int getAppendLimit() { - return this.sorter == ARBITRARY ? this.limit : Integer.MAX_VALUE; - } - - private Predicate<Entity> getPositionPredicate(Vec3d pos) { - Predicate<Entity> predicate = this.basePredicate; - if (this.box != null) { - Box lv = this.box.offset(pos); - predicate = predicate.and(entity -> lv.intersects(entity.getBoundingBox())); - } - - if (!this.distance.isDummy()) { - predicate = predicate.and(entity -> this.distance.testSqrt(entity.squaredDistanceTo(pos))); - } - - return predicate; - } - public List<? extends Entity> getClientSideEntityMatches(ClientWorld cw, Vec3d sourcePos) throws CommandSyntaxException { - Predicate<Entity> p = this.getPositionPredicate(sourcePos); - List<Entity> ret = new ArrayList<>(); - int limit = this.getAppendLimit(); - if (this.box != null) - cw.collectEntitiesByType(this.entityFilter, this.box.offset(sourcePos), p, ret, limit); - else { - ((ClientWorldMixin)cw).invokeGetEntityLookup().forEach(this.entityFilter, (e) -> { - if (p.test(e)) { - ret.add(e); - if (ret.size() >= limit) - return LazyIterationConsumer.NextIteration.ABORT; - } - return LazyIterationConsumer.NextIteration.CONTINUE; - }); - } - return ret; - } - - private <T extends Entity> List<T> getEntities(Vec3d pos, List<T> entities) { - if (entities.size() > 1) { - this.sorter.accept(pos, entities); - } - - return entities.subList(0, Math.min(this.limit, entities.size())); - } - - public static Text getNames(List<? extends Entity> entities) { - return Texts.join(entities, Entity::getDisplayName); - } + public static final int MAX_VALUE = Integer.MAX_VALUE; + public static final BiConsumer<Vec3d, List<? extends Entity>> ARBITRARY = (pos, entities) -> { + }; + private static final TypeFilter<Entity, ?> PASSTHROUGH_FILTER = new TypeFilter<Entity, Entity>() { + public Entity downcast(Entity arg) { + return arg; + } + + @Override + public Class<? extends Entity> getBaseClass() { + return Entity.class; + } + }; + private final int limit; + private final boolean includesNonPlayers; + private final boolean localWorldOnly; + private final List<Predicate<Entity>> predicates; + private final NumberRange.DoubleRange distance; + private final Function<Vec3d, Vec3d> positionOffset; + @Nullable + private final Box box; + private final BiConsumer<Vec3d, List<? extends Entity>> sorter; + private final boolean senderOnly; + @Nullable + private final String playerName; + @Nullable + private final UUID uuid; + private final TypeFilter<Entity, ?> entityFilter; + private final boolean usesAt; + + public CEntitySelector( + int count, + boolean includesNonPlayers, + boolean localWorldOnly, + List<Predicate<Entity>> predicates, + NumberRange.DoubleRange distance, + Function<Vec3d, Vec3d> positionOffset, + @Nullable Box box, + BiConsumer<Vec3d, List<? extends Entity>> sorter, + boolean senderOnly, + @Nullable String playerName, + @Nullable UUID uuid, + @Nullable EntityType<?> type, + boolean usesAt + ) { + this.limit = count; + this.includesNonPlayers = includesNonPlayers; + this.localWorldOnly = localWorldOnly; + this.predicates = predicates; + this.distance = distance; + this.positionOffset = positionOffset; + this.box = box; + this.sorter = sorter; + this.senderOnly = senderOnly; + this.playerName = playerName; + this.uuid = uuid; + this.entityFilter = (TypeFilter<Entity, ?>)(type == null ? PASSTHROUGH_FILTER : type); + this.usesAt = usesAt; + } + + public int getLimit() { + return this.limit; + } + + public boolean includesNonPlayers() { + return this.includesNonPlayers; + } + + public boolean isSenderOnly() { + return this.senderOnly; + } + + public boolean isLocalWorldOnly() { + return this.localWorldOnly; + } + + public boolean usesAt() { + return this.usesAt; + } + + private void checkSourcePermission(ServerCommandSource source) throws CommandSyntaxException { + if (this.usesAt && !source.hasPermissionLevel(2)) { + throw EntityArgumentType.NOT_ALLOWED_EXCEPTION.create(); + } + } + + public Entity getEntity(ServerCommandSource source) throws CommandSyntaxException { + this.checkSourcePermission(source); + List<? extends Entity> list = this.getEntities(source); + if (list.isEmpty()) { + throw EntityArgumentType.ENTITY_NOT_FOUND_EXCEPTION.create(); + } else if (list.size() > 1) { + throw EntityArgumentType.TOO_MANY_ENTITIES_EXCEPTION.create(); + } else { + return list.get(0); + } + } + + public List<? extends Entity> getEntities(ServerCommandSource source) throws CommandSyntaxException { + this.checkSourcePermission(source); + if (!this.includesNonPlayers) { + return this.getPlayers(source); + } else if (this.playerName != null) { + ServerPlayerEntity lv = source.getServer().getPlayerManager().getPlayer(this.playerName); + return lv == null ? List.of() : List.of(lv); + } else if (this.uuid != null) { + for (ServerWorld lv2 : source.getServer().getWorlds()) { + Entity lv3 = lv2.getEntity(this.uuid); + if (lv3 != null) { + if (lv3.getType().isEnabled(source.getEnabledFeatures())) { + return List.of(lv3); + } + break; + } + } + + return List.of(); + } else { + Vec3d lv4 = this.positionOffset.apply(source.getPosition()); + Box lv5 = this.getOffsetBox(lv4); + if (this.senderOnly) { + Predicate<Entity> predicate = this.getPositionPredicate(lv4, lv5, null); + return source.getEntity() != null && predicate.test(source.getEntity()) ? List.of(source.getEntity()) : List.of(); + } else { + Predicate<Entity> predicate = this.getPositionPredicate(lv4, lv5, source.getEnabledFeatures()); + List<Entity> list = new ObjectArrayList(); + if (this.isLocalWorldOnly()) { + this.appendEntitiesFromWorld(list, source.getWorld(), lv5, predicate); + } else { + for (ServerWorld lv6 : source.getServer().getWorlds()) { + this.appendEntitiesFromWorld(list, lv6, lv5, predicate); + } + } + + return this.getEntities(lv4, list); + } + } + } + + private void appendEntitiesFromWorld(List<Entity> entities, ServerWorld world, @Nullable Box box, Predicate<Entity> predicate) { + int i = this.getAppendLimit(); + if (entities.size() < i) { + if (box != null) { + world.collectEntitiesByType(this.entityFilter, box, predicate, entities, i); + } else { + world.collectEntitiesByType(this.entityFilter, predicate, entities, i); + } + } + } + + private int getAppendLimit() { + return this.sorter == ARBITRARY ? this.limit : Integer.MAX_VALUE; + } + + public ServerPlayerEntity getPlayer(ServerCommandSource source) throws CommandSyntaxException { + this.checkSourcePermission(source); + List<ServerPlayerEntity> list = this.getPlayers(source); + if (list.size() != 1) { + throw EntityArgumentType.PLAYER_NOT_FOUND_EXCEPTION.create(); + } else { + return list.get(0); + } + } + + public List<ServerPlayerEntity> getPlayers(ServerCommandSource source) throws CommandSyntaxException { + this.checkSourcePermission(source); + if (this.playerName != null) { + ServerPlayerEntity lv = source.getServer().getPlayerManager().getPlayer(this.playerName); + return lv == null ? List.of() : List.of(lv); + } else if (this.uuid != null) { + ServerPlayerEntity lv = source.getServer().getPlayerManager().getPlayer(this.uuid); + return lv == null ? List.of() : List.of(lv); + } else { + Vec3d lv2 = this.positionOffset.apply(source.getPosition()); + Box lv3 = this.getOffsetBox(lv2); + Predicate<Entity> predicate = this.getPositionPredicate(lv2, lv3, null); + if (this.senderOnly) { + if (source.getEntity() instanceof ServerPlayerEntity lv4 && predicate.test(lv4)) { + return List.of(lv4); + } + + return List.of(); + } else { + int i = this.getAppendLimit(); + List<ServerPlayerEntity> list; + if (this.isLocalWorldOnly()) { + list = source.getWorld().getPlayers(predicate, i); + } else { + list = new ObjectArrayList(); + + for (ServerPlayerEntity lv5 : source.getServer().getPlayerManager().getPlayerList()) { + if (predicate.test(lv5)) { + list.add(lv5); + if (list.size() >= i) { + return list; + } + } + } + } + + return this.getEntities(lv2, list); + } + } + } + + @Nullable + private Box getOffsetBox(Vec3d offset) { + return this.box != null ? this.box.offset(offset) : null; + } + + private Predicate<Entity> getPositionPredicate(Vec3d pos, @Nullable Box box, @Nullable FeatureSet enabledFeatures) { + boolean bl = enabledFeatures != null; + boolean bl2 = box != null; + boolean bl3 = !this.distance.isDummy(); + int i = (bl ? 1 : 0) + (bl2 ? 1 : 0) + (bl3 ? 1 : 0); + List<Predicate<Entity>> list; + if (i == 0) { + list = this.predicates; + } else { + List<Predicate<Entity>> list2 = new ObjectArrayList(this.predicates.size() + i); + list2.addAll(this.predicates); + if (bl) { + list2.add(entity -> entity.getType().isEnabled(enabledFeatures)); + } + + if (bl2) { + list2.add(entity -> box.intersects(entity.getBoundingBox())); + } + + if (bl3) { + list2.add(entity -> this.distance.testSqrt(entity.squaredDistanceTo(pos))); + } + + list = list2; + } + + return Util.allOf(list); + } + + public List<? extends Entity> getClientSideEntityMatches(ClientWorld cw, Vec3d sourcePos) throws CommandSyntaxException { + Predicate<Entity> p = this.getPositionPredicate(sourcePos, null, null); + List<Entity> ret = new ArrayList<>(); + int limit = this.getAppendLimit(); + if (this.box != null) + cw.collectEntitiesByType(this.entityFilter, this.box.offset(sourcePos), p, ret, limit); + else { + ((ClientWorldMixin)cw).invokeGetEntityLookup().forEach(this.entityFilter, (e) -> { + if (p.test(e)) { + ret.add(e); + if (ret.size() >= limit) + return LazyIterationConsumer.NextIteration.ABORT; + } + return LazyIterationConsumer.NextIteration.CONTINUE; + }); + } + return ret; + } + + private <T extends Entity> List<T> getEntities(Vec3d pos, List<T> entities) { + if (entities.size() > 1) { + this.sorter.accept(pos, entities); + } + + return entities.subList(0, Math.min(this.limit, entities.size())); + } + + public static Text getNames(List<? extends Entity> entities) { + return Texts.join(entities, Entity::getDisplayName); + } } |