minecraft-src/net/minecraft/advancements/critereon/EntityPredicate.java
2025-07-04 03:45:38 +03:00

338 lines
14 KiB
Java

package net.minecraft.advancements.critereon;
import com.mojang.serialization.Codec;
import com.mojang.serialization.MapCodec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.component.DataComponentGetter;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.tags.TagKey;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
import net.minecraft.world.level.storage.loot.predicates.LootItemEntityPropertyCondition;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.scores.Team;
import org.jetbrains.annotations.Nullable;
public record EntityPredicate(
Optional<EntityTypePredicate> entityType,
Optional<DistancePredicate> distanceToPlayer,
Optional<MovementPredicate> movement,
EntityPredicate.LocationWrapper location,
Optional<MobEffectsPredicate> effects,
Optional<NbtPredicate> nbt,
Optional<EntityFlagsPredicate> flags,
Optional<EntityEquipmentPredicate> equipment,
Optional<EntitySubPredicate> subPredicate,
Optional<Integer> periodicTick,
Optional<EntityPredicate> vehicle,
Optional<EntityPredicate> passenger,
Optional<EntityPredicate> targetedEntity,
Optional<String> team,
Optional<SlotsPredicate> slots,
DataComponentMatchers components
) {
public static final Codec<EntityPredicate> CODEC = Codec.recursive(
"EntityPredicate",
codec -> RecordCodecBuilder.create(
instance -> instance.group(
EntityTypePredicate.CODEC.optionalFieldOf("type").forGetter(EntityPredicate::entityType),
DistancePredicate.CODEC.optionalFieldOf("distance").forGetter(EntityPredicate::distanceToPlayer),
MovementPredicate.CODEC.optionalFieldOf("movement").forGetter(EntityPredicate::movement),
EntityPredicate.LocationWrapper.CODEC.forGetter(EntityPredicate::location),
MobEffectsPredicate.CODEC.optionalFieldOf("effects").forGetter(EntityPredicate::effects),
NbtPredicate.CODEC.optionalFieldOf("nbt").forGetter(EntityPredicate::nbt),
EntityFlagsPredicate.CODEC.optionalFieldOf("flags").forGetter(EntityPredicate::flags),
EntityEquipmentPredicate.CODEC.optionalFieldOf("equipment").forGetter(EntityPredicate::equipment),
EntitySubPredicate.CODEC.optionalFieldOf("type_specific").forGetter(EntityPredicate::subPredicate),
ExtraCodecs.POSITIVE_INT.optionalFieldOf("periodic_tick").forGetter(EntityPredicate::periodicTick),
codec.optionalFieldOf("vehicle").forGetter(EntityPredicate::vehicle),
codec.optionalFieldOf("passenger").forGetter(EntityPredicate::passenger),
codec.optionalFieldOf("targeted_entity").forGetter(EntityPredicate::targetedEntity),
Codec.STRING.optionalFieldOf("team").forGetter(EntityPredicate::team),
SlotsPredicate.CODEC.optionalFieldOf("slots").forGetter(EntityPredicate::slots),
DataComponentMatchers.CODEC.forGetter(EntityPredicate::components)
)
.apply(instance, EntityPredicate::new)
)
);
public static final Codec<ContextAwarePredicate> ADVANCEMENT_CODEC = Codec.withAlternative(ContextAwarePredicate.CODEC, CODEC, EntityPredicate::wrap);
public static ContextAwarePredicate wrap(EntityPredicate.Builder builder) {
return wrap(builder.build());
}
public static Optional<ContextAwarePredicate> wrap(Optional<EntityPredicate> predicate) {
return predicate.map(EntityPredicate::wrap);
}
public static List<ContextAwarePredicate> wrap(EntityPredicate.Builder... builders) {
return Stream.of(builders).map(EntityPredicate::wrap).toList();
}
public static ContextAwarePredicate wrap(EntityPredicate predicate) {
LootItemCondition lootItemCondition = LootItemEntityPropertyCondition.hasProperties(LootContext.EntityTarget.THIS, predicate).build();
return new ContextAwarePredicate(List.of(lootItemCondition));
}
public boolean matches(ServerPlayer player, @Nullable Entity entity) {
return this.matches(player.serverLevel(), player.position(), entity);
}
public boolean matches(ServerLevel level, @Nullable Vec3 position, @Nullable Entity entity) {
if (entity == null) {
return false;
} else if (this.entityType.isPresent() && !((EntityTypePredicate)this.entityType.get()).matches(entity.getType())) {
return false;
} else {
if (position == null) {
if (this.distanceToPlayer.isPresent()) {
return false;
}
} else if (this.distanceToPlayer.isPresent()
&& !((DistancePredicate)this.distanceToPlayer.get()).matches(position.x, position.y, position.z, entity.getX(), entity.getY(), entity.getZ())) {
return false;
}
if (this.movement.isPresent()) {
Vec3 vec3 = entity.getKnownMovement();
Vec3 vec32 = vec3.scale(20.0);
if (!((MovementPredicate)this.movement.get()).matches(vec32.x, vec32.y, vec32.z, entity.fallDistance)) {
return false;
}
}
if (this.location.located.isPresent() && !((LocationPredicate)this.location.located.get()).matches(level, entity.getX(), entity.getY(), entity.getZ())) {
return false;
} else {
if (this.location.steppingOn.isPresent()) {
Vec3 vec3 = Vec3.atCenterOf(entity.getOnPos());
if (!entity.onGround() || !((LocationPredicate)this.location.steppingOn.get()).matches(level, vec3.x(), vec3.y(), vec3.z())) {
return false;
}
}
if (this.location.affectsMovement.isPresent()) {
Vec3 vec3 = Vec3.atCenterOf(entity.getBlockPosBelowThatAffectsMyMovement());
if (!((LocationPredicate)this.location.affectsMovement.get()).matches(level, vec3.x(), vec3.y(), vec3.z())) {
return false;
}
}
if (this.effects.isPresent() && !((MobEffectsPredicate)this.effects.get()).matches(entity)) {
return false;
} else if (this.flags.isPresent() && !((EntityFlagsPredicate)this.flags.get()).matches(entity)) {
return false;
} else if (this.equipment.isPresent() && !((EntityEquipmentPredicate)this.equipment.get()).matches(entity)) {
return false;
} else if (this.subPredicate.isPresent() && !((EntitySubPredicate)this.subPredicate.get()).matches(entity, level, position)) {
return false;
} else if (this.vehicle.isPresent() && !((EntityPredicate)this.vehicle.get()).matches(level, position, entity.getVehicle())) {
return false;
} else if (this.passenger.isPresent()
&& entity.getPassengers().stream().noneMatch(entityx -> ((EntityPredicate)this.passenger.get()).matches(level, position, entityx))) {
return false;
} else if (this.targetedEntity.isPresent()
&& !((EntityPredicate)this.targetedEntity.get()).matches(level, position, entity instanceof Mob ? ((Mob)entity).getTarget() : null)) {
return false;
} else if (this.periodicTick.isPresent() && entity.tickCount % (Integer)this.periodicTick.get() != 0) {
return false;
} else {
if (this.team.isPresent()) {
Team team = entity.getTeam();
if (team == null || !((String)this.team.get()).equals(team.getName())) {
return false;
}
}
if (this.slots.isPresent() && !((SlotsPredicate)this.slots.get()).matches(entity)) {
return false;
} else {
return !this.components.test((DataComponentGetter)entity) ? false : this.nbt.isEmpty() || ((NbtPredicate)this.nbt.get()).matches(entity);
}
}
}
}
}
public static LootContext createContext(ServerPlayer player, Entity entity) {
LootParams lootParams = new LootParams.Builder(player.serverLevel())
.withParameter(LootContextParams.THIS_ENTITY, entity)
.withParameter(LootContextParams.ORIGIN, player.position())
.create(LootContextParamSets.ADVANCEMENT_ENTITY);
return new LootContext.Builder(lootParams).create(Optional.empty());
}
public static class Builder {
private Optional<EntityTypePredicate> entityType = Optional.empty();
private Optional<DistancePredicate> distanceToPlayer = Optional.empty();
private Optional<MovementPredicate> movement = Optional.empty();
private Optional<LocationPredicate> located = Optional.empty();
private Optional<LocationPredicate> steppingOnLocation = Optional.empty();
private Optional<LocationPredicate> movementAffectedBy = Optional.empty();
private Optional<MobEffectsPredicate> effects = Optional.empty();
private Optional<NbtPredicate> nbt = Optional.empty();
private Optional<EntityFlagsPredicate> flags = Optional.empty();
private Optional<EntityEquipmentPredicate> equipment = Optional.empty();
private Optional<EntitySubPredicate> subPredicate = Optional.empty();
private Optional<Integer> periodicTick = Optional.empty();
private Optional<EntityPredicate> vehicle = Optional.empty();
private Optional<EntityPredicate> passenger = Optional.empty();
private Optional<EntityPredicate> targetedEntity = Optional.empty();
private Optional<String> team = Optional.empty();
private Optional<SlotsPredicate> slots = Optional.empty();
private DataComponentMatchers components = DataComponentMatchers.ANY;
public static EntityPredicate.Builder entity() {
return new EntityPredicate.Builder();
}
public EntityPredicate.Builder of(HolderGetter<EntityType<?>> entityTypeRegistry, EntityType<?> entityType) {
this.entityType = Optional.of(EntityTypePredicate.of(entityTypeRegistry, entityType));
return this;
}
public EntityPredicate.Builder of(HolderGetter<EntityType<?>> entityTypeRegistry, TagKey<EntityType<?>> entityTypeTag) {
this.entityType = Optional.of(EntityTypePredicate.of(entityTypeRegistry, entityTypeTag));
return this;
}
public EntityPredicate.Builder entityType(EntityTypePredicate entityType) {
this.entityType = Optional.of(entityType);
return this;
}
public EntityPredicate.Builder distance(DistancePredicate distanceToPlayer) {
this.distanceToPlayer = Optional.of(distanceToPlayer);
return this;
}
public EntityPredicate.Builder moving(MovementPredicate movement) {
this.movement = Optional.of(movement);
return this;
}
public EntityPredicate.Builder located(LocationPredicate.Builder location) {
this.located = Optional.of(location.build());
return this;
}
public EntityPredicate.Builder steppingOn(LocationPredicate.Builder steppingOnLocation) {
this.steppingOnLocation = Optional.of(steppingOnLocation.build());
return this;
}
public EntityPredicate.Builder movementAffectedBy(LocationPredicate.Builder movementAffectedBy) {
this.movementAffectedBy = Optional.of(movementAffectedBy.build());
return this;
}
public EntityPredicate.Builder effects(MobEffectsPredicate.Builder effects) {
this.effects = effects.build();
return this;
}
public EntityPredicate.Builder nbt(NbtPredicate nbt) {
this.nbt = Optional.of(nbt);
return this;
}
public EntityPredicate.Builder flags(EntityFlagsPredicate.Builder flags) {
this.flags = Optional.of(flags.build());
return this;
}
public EntityPredicate.Builder equipment(EntityEquipmentPredicate.Builder equipment) {
this.equipment = Optional.of(equipment.build());
return this;
}
public EntityPredicate.Builder equipment(EntityEquipmentPredicate equipment) {
this.equipment = Optional.of(equipment);
return this;
}
public EntityPredicate.Builder subPredicate(EntitySubPredicate subPredicate) {
this.subPredicate = Optional.of(subPredicate);
return this;
}
public EntityPredicate.Builder periodicTick(int periodicTick) {
this.periodicTick = Optional.of(periodicTick);
return this;
}
public EntityPredicate.Builder vehicle(EntityPredicate.Builder vehicle) {
this.vehicle = Optional.of(vehicle.build());
return this;
}
public EntityPredicate.Builder passenger(EntityPredicate.Builder passenger) {
this.passenger = Optional.of(passenger.build());
return this;
}
public EntityPredicate.Builder targetedEntity(EntityPredicate.Builder targetedEntity) {
this.targetedEntity = Optional.of(targetedEntity.build());
return this;
}
public EntityPredicate.Builder team(String team) {
this.team = Optional.of(team);
return this;
}
public EntityPredicate.Builder slots(SlotsPredicate slots) {
this.slots = Optional.of(slots);
return this;
}
public EntityPredicate.Builder components(DataComponentMatchers components) {
this.components = components;
return this;
}
public EntityPredicate build() {
return new EntityPredicate(
this.entityType,
this.distanceToPlayer,
this.movement,
new EntityPredicate.LocationWrapper(this.located, this.steppingOnLocation, this.movementAffectedBy),
this.effects,
this.nbt,
this.flags,
this.equipment,
this.subPredicate,
this.periodicTick,
this.vehicle,
this.passenger,
this.targetedEntity,
this.team,
this.slots,
this.components
);
}
}
public record LocationWrapper(Optional<LocationPredicate> located, Optional<LocationPredicate> steppingOn, Optional<LocationPredicate> affectsMovement) {
public static final MapCodec<EntityPredicate.LocationWrapper> CODEC = RecordCodecBuilder.mapCodec(
instance -> instance.group(
LocationPredicate.CODEC.optionalFieldOf("location").forGetter(EntityPredicate.LocationWrapper::located),
LocationPredicate.CODEC.optionalFieldOf("stepping_on").forGetter(EntityPredicate.LocationWrapper::steppingOn),
LocationPredicate.CODEC.optionalFieldOf("movement_affected_by").forGetter(EntityPredicate.LocationWrapper::affectsMovement)
)
.apply(instance, EntityPredicate.LocationWrapper::new)
);
}
}