PlayerPredicate.java

net.minecraft.advancements.criterion.PlayerPredicate

信息

  • 全限定名:net.minecraft.advancements.criterion.PlayerPredicate
  • 类型:public record
  • 包:net.minecraft.advancements.criterion
  • 源码路径:src/main/java/net/minecraft/advancements/criterion/PlayerPredicate.java
  • 起始行号:L46
  • 实现:EntitySubPredicate
  • 职责:

    TODO

字段/常量

  • LOOKING_AT_RANGE

    • 类型: int
    • 修饰符: public static final
    • 源码定位: L56
    • 说明:

      TODO

  • CODEC

    • 类型: MapCodec<PlayerPredicate>
    • 修饰符: public static final
    • 源码定位: L57
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.advancements.criterion.PlayerPredicate.AdvancementCriterionsPredicate

    • 类型: record
    • 修饰符: private
    • 源码定位: L138
    • 说明:

      TODO

  • net.minecraft.advancements.criterion.PlayerPredicate.AdvancementDonePredicate

    • 类型: record
    • 修饰符: private
    • 源码定位: L154
    • 说明:

      TODO

  • net.minecraft.advancements.criterion.PlayerPredicate.AdvancementPredicate

    • 类型: interface
    • 修饰符: private
    • 源码定位: L163
    • 说明:

      TODO

  • net.minecraft.advancements.criterion.PlayerPredicate.Builder

    • 类型: class
    • 修饰符: public static
    • 源码定位: L178
    • 说明:

      TODO

  • net.minecraft.advancements.criterion.PlayerPredicate.StatMatcher

    • 类型: record
    • 修饰符: private
    • 源码定位: L242
    • 说明:

      TODO

构造器

方法

下面的方法块按源码顺序生成。

public boolean matches(Entity entity, ServerLevel level, Vec3 position) @ L73

  • 方法名:matches
  • 源码定位:L73
  • 返回类型:boolean
  • 修饰符:public

参数:

  • entity: Entity
  • level: ServerLevel
  • position: Vec3

说明:

TODO

public MapCodec<PlayerPredicate> codec() @ L133

  • 方法名:codec
  • 源码定位:L133
  • 返回类型:MapCodec
  • 修饰符:public

参数:

说明:

TODO

代码

public record PlayerPredicate(
    MinMaxBounds.Ints level,
    FoodPredicate food,
    GameTypePredicate gameType,
    List<PlayerPredicate.StatMatcher<?>> stats,
    Object2BooleanMap<ResourceKey<Recipe<?>>> recipes,
    Map<Identifier, PlayerPredicate.AdvancementPredicate> advancements,
    Optional<EntityPredicate> lookingAt,
    Optional<InputPredicate> input
) implements EntitySubPredicate {
    public static final int LOOKING_AT_RANGE = 100;
    public static final MapCodec<PlayerPredicate> CODEC = RecordCodecBuilder.mapCodec(
        i -> i.group(
                MinMaxBounds.Ints.CODEC.optionalFieldOf("level", MinMaxBounds.Ints.ANY).forGetter(PlayerPredicate::level),
                FoodPredicate.CODEC.optionalFieldOf("food", FoodPredicate.ANY).forGetter(PlayerPredicate::food),
                GameTypePredicate.CODEC.optionalFieldOf("gamemode", GameTypePredicate.ANY).forGetter(PlayerPredicate::gameType),
                PlayerPredicate.StatMatcher.CODEC.listOf().optionalFieldOf("stats", List.of()).forGetter(PlayerPredicate::stats),
                ExtraCodecs.object2BooleanMap(Recipe.KEY_CODEC).optionalFieldOf("recipes", Object2BooleanMaps.emptyMap()).forGetter(PlayerPredicate::recipes),
                Codec.unboundedMap(Identifier.CODEC, PlayerPredicate.AdvancementPredicate.CODEC)
                    .optionalFieldOf("advancements", Map.of())
                    .forGetter(PlayerPredicate::advancements),
                EntityPredicate.CODEC.optionalFieldOf("looking_at").forGetter(PlayerPredicate::lookingAt),
                InputPredicate.CODEC.optionalFieldOf("input").forGetter(PlayerPredicate::input)
            )
            .apply(i, PlayerPredicate::new)
    );
 
    @Override
    public boolean matches(Entity entity, ServerLevel level, @Nullable Vec3 position) {
        if (!(entity instanceof ServerPlayer player)) {
            return false;
        } else if (!this.level.matches(player.experienceLevel)) {
            return false;
        } else if (!this.food.matches(player.getFoodData())) {
            return false;
        } else if (!this.gameType.matches(player.gameMode())) {
            return false;
        } else {
            StatsCounter stats = player.getStats();
 
            for (PlayerPredicate.StatMatcher<?> stat : this.stats) {
                if (!stat.matches(stats)) {
                    return false;
                }
            }
 
            ServerRecipeBook recipes = player.getRecipeBook();
 
            for (Entry<ResourceKey<Recipe<?>>> e : this.recipes.object2BooleanEntrySet()) {
                if (recipes.contains(e.getKey()) != e.getBooleanValue()) {
                    return false;
                }
            }
 
            if (!this.advancements.isEmpty()) {
                PlayerAdvancements advancements = player.getAdvancements();
                ServerAdvancementManager serverAdvancements = player.level().getServer().getAdvancements();
 
                for (java.util.Map.Entry<Identifier, PlayerPredicate.AdvancementPredicate> entry : this.advancements.entrySet()) {
                    AdvancementHolder advancement = serverAdvancements.get(entry.getKey());
                    if (advancement == null || !entry.getValue().test(advancements.getOrStartProgress(advancement))) {
                        return false;
                    }
                }
            }
 
            if (this.lookingAt.isPresent()) {
                Vec3 from = player.getEyePosition();
                Vec3 viewVec = player.getViewVector(1.0F);
                Vec3 to = from.add(viewVec.x * 100.0, viewVec.y * 100.0, viewVec.z * 100.0);
                EntityHitResult lookingAtResult = ProjectileUtil.getEntityHitResult(
                    player.level(), player, from, to, new AABB(from, to).inflate(1.0), ex -> !ex.isSpectator(), 0.0F
                );
                if (lookingAtResult == null || lookingAtResult.getType() != HitResult.Type.ENTITY) {
                    return false;
                }
 
                Entity lookingAtEntity = lookingAtResult.getEntity();
                if (!this.lookingAt.get().matches(player, lookingAtEntity) || !player.hasLineOfSight(lookingAtEntity)) {
                    return false;
                }
            }
 
            return !this.input.isPresent() || this.input.get().matches(player.getLastClientInput());
        }
    }
 
    @Override
    public MapCodec<PlayerPredicate> codec() {
        return EntitySubPredicates.PLAYER;
    }
 
    private record AdvancementCriterionsPredicate(Object2BooleanMap<String> criterions) implements PlayerPredicate.AdvancementPredicate {
        public static final Codec<PlayerPredicate.AdvancementCriterionsPredicate> CODEC = ExtraCodecs.object2BooleanMap(Codec.STRING)
            .xmap(PlayerPredicate.AdvancementCriterionsPredicate::new, PlayerPredicate.AdvancementCriterionsPredicate::criterions);
 
        public boolean test(AdvancementProgress progress) {
            for (Entry<String> e : this.criterions.object2BooleanEntrySet()) {
                CriterionProgress criterion = progress.getCriterion(e.getKey());
                if (criterion == null || criterion.isDone() != e.getBooleanValue()) {
                    return false;
                }
            }
 
            return true;
        }
    }
 
    private record AdvancementDonePredicate(boolean state) implements PlayerPredicate.AdvancementPredicate {
        public static final Codec<PlayerPredicate.AdvancementDonePredicate> CODEC = Codec.BOOL
            .xmap(PlayerPredicate.AdvancementDonePredicate::new, PlayerPredicate.AdvancementDonePredicate::state);
 
        public boolean test(AdvancementProgress progress) {
            return progress.isDone() == this.state;
        }
    }
 
    private interface AdvancementPredicate extends Predicate<AdvancementProgress> {
        Codec<PlayerPredicate.AdvancementPredicate> CODEC = Codec.either(
                PlayerPredicate.AdvancementDonePredicate.CODEC, PlayerPredicate.AdvancementCriterionsPredicate.CODEC
            )
            .xmap(Either::unwrap, predicate -> {
                if (predicate instanceof PlayerPredicate.AdvancementDonePredicate done) {
                    return Either.left(done);
                } else if (predicate instanceof PlayerPredicate.AdvancementCriterionsPredicate criterions) {
                    return Either.right(criterions);
                } else {
                    throw new UnsupportedOperationException();
                }
            });
    }
 
    public static class Builder {
        private MinMaxBounds.Ints level = MinMaxBounds.Ints.ANY;
        private FoodPredicate food = FoodPredicate.ANY;
        private GameTypePredicate gameType = GameTypePredicate.ANY;
        private final ImmutableList.Builder<PlayerPredicate.StatMatcher<?>> stats = ImmutableList.builder();
        private final Object2BooleanMap<ResourceKey<Recipe<?>>> recipes = new Object2BooleanOpenHashMap<>();
        private final Map<Identifier, PlayerPredicate.AdvancementPredicate> advancements = Maps.newHashMap();
        private Optional<EntityPredicate> lookingAt = Optional.empty();
        private Optional<InputPredicate> input = Optional.empty();
 
        public static PlayerPredicate.Builder player() {
            return new PlayerPredicate.Builder();
        }
 
        public PlayerPredicate.Builder setLevel(MinMaxBounds.Ints level) {
            this.level = level;
            return this;
        }
 
        public PlayerPredicate.Builder setFood(FoodPredicate food) {
            this.food = food;
            return this;
        }
 
        public <T> PlayerPredicate.Builder addStat(StatType<T> type, Holder.Reference<T> value, MinMaxBounds.Ints range) {
            this.stats.add(new PlayerPredicate.StatMatcher<>(type, value, range));
            return this;
        }
 
        public PlayerPredicate.Builder addRecipe(ResourceKey<Recipe<?>> recipe, boolean present) {
            this.recipes.put(recipe, present);
            return this;
        }
 
        public PlayerPredicate.Builder setGameType(GameTypePredicate gameType) {
            this.gameType = gameType;
            return this;
        }
 
        public PlayerPredicate.Builder setLookingAt(EntityPredicate.Builder lookingAt) {
            this.lookingAt = Optional.of(lookingAt.build());
            return this;
        }
 
        public PlayerPredicate.Builder checkAdvancementDone(Identifier advancement, boolean isDone) {
            this.advancements.put(advancement, new PlayerPredicate.AdvancementDonePredicate(isDone));
            return this;
        }
 
        public PlayerPredicate.Builder checkAdvancementCriterions(Identifier advancement, Map<String, Boolean> criterions) {
            this.advancements.put(advancement, new PlayerPredicate.AdvancementCriterionsPredicate(new Object2BooleanOpenHashMap<>(criterions)));
            return this;
        }
 
        public PlayerPredicate.Builder hasInput(InputPredicate input) {
            this.input = Optional.of(input);
            return this;
        }
 
        public PlayerPredicate build() {
            return new PlayerPredicate(this.level, this.food, this.gameType, this.stats.build(), this.recipes, this.advancements, this.lookingAt, this.input);
        }
    }
 
    private record StatMatcher<T>(StatType<T> type, Holder<T> value, MinMaxBounds.Ints range, Supplier<Stat<T>> stat) {
        public static final Codec<PlayerPredicate.StatMatcher<?>> CODEC = BuiltInRegistries.STAT_TYPE
            .byNameCodec()
            .dispatch(PlayerPredicate.StatMatcher::type, PlayerPredicate.StatMatcher::createTypedCodec);
 
        public StatMatcher(StatType<T> type, Holder<T> value, MinMaxBounds.Ints range) {
            this(type, value, range, Suppliers.memoize(() -> type.get(value.value())));
        }
 
        private static <T> MapCodec<PlayerPredicate.StatMatcher<T>> createTypedCodec(StatType<T> type) {
            return RecordCodecBuilder.mapCodec(
                i -> i.group(
                        type.getRegistry()
                            .holderByNameCodec()
                            .fieldOf("stat")
                            .forGetter(PlayerPredicate.StatMatcher::value),
                        MinMaxBounds.Ints.CODEC
                            .optionalFieldOf("value", MinMaxBounds.Ints.ANY)
                            .forGetter(PlayerPredicate.StatMatcher::range)
                    )
                    .apply(i, (value, range) -> new PlayerPredicate.StatMatcher<>(type, value, range))
            );
        }
 
        public boolean matches(StatsCounter counter) {
            return this.range.matches(counter.getValue(this.stat.get()));
        }
    }
}

引用的其他类

  • EntitySubPredicate

    • 引用位置: 实现
  • ServerLevel

    • 引用位置: 参数
  • ExtraCodecs

    • 引用位置: 方法调用
    • 关联成员: ExtraCodecs.object2BooleanMap()
  • Entity

    • 引用位置: 参数
  • ProjectileUtil

    • 引用位置: 方法调用
    • 关联成员: ProjectileUtil.getEntityHitResult()
  • AABB

    • 引用位置: 构造调用
    • 关联成员: AABB()
  • Vec3

    • 引用位置: 参数