Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master—' into master—
Browse files Browse the repository at this point in the history
  • Loading branch information
Lithewings committed Aug 4, 2024
1 parent c79f9d0 commit 5011f70
Show file tree
Hide file tree
Showing 10 changed files with 685 additions and 147 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.equilibrium.entity.goal;

import java.util.EnumSet;
import java.util.function.Predicate;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.ai.goal.TrackTargetGoal;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.math.Box;
import org.jetbrains.annotations.Nullable;

/**
* A target goal that finds a target by entity class when the goal starts.
*/
public class AdvanceActiveTargetGoal<T extends LivingEntity> extends TrackTargetGoal {
private static final int DEFAULT_RECIPROCAL_CHANCE = 10;
protected final Class<T> targetClass;
/**
* The reciprocal of chance to actually search for a target on every tick
* when this goal is not started. This is also the average number of ticks
* between each search (as in a poisson distribution).
*/
protected final int reciprocalChance;
@Nullable
protected LivingEntity targetEntity;
protected AdvanceTargetPredicate targetPredicate;

public AdvanceActiveTargetGoal(MobEntity mob, Class<T> targetClass, boolean checkVisibility) {
this(mob, targetClass, 10, checkVisibility, false, null);
}

public AdvanceActiveTargetGoal(MobEntity mob, Class<T> targetClass, boolean checkVisibility, Predicate<LivingEntity> targetPredicate) {
this(mob, targetClass, 10, checkVisibility, false, targetPredicate);
}

public AdvanceActiveTargetGoal(MobEntity mob, Class<T> targetClass, boolean checkVisibility, boolean checkCanNavigate) {
this(mob, targetClass, 10, checkVisibility, checkCanNavigate, null);
}

public AdvanceActiveTargetGoal(
MobEntity mob,
Class<T> targetClass,
int reciprocalChance,
boolean checkVisibility,
boolean checkCanNavigate,
@Nullable Predicate<LivingEntity> targetPredicate
) {
super(mob, checkVisibility, checkCanNavigate);
this.targetClass = targetClass;
this.reciprocalChance = toGoalTicks(reciprocalChance);
this.setControls(EnumSet.of(Goal.Control.TARGET));
this.targetPredicate = AdvanceTargetPredicate.createAttackable().setBaseMaxDistance(this.getFollowRange()).setPredicate(targetPredicate);
}

@Override
public boolean canStart() {
if (this.reciprocalChance > 0 && this.mob.getRandom().nextInt(this.reciprocalChance) != 0) {
return false;
} else {
this.findClosestTarget();
return this.targetEntity != null;
}
}

protected Box getSearchBox(double distance) {
return this.mob.getBoundingBox().expand(distance, 4.0, distance);
}

protected void findClosestTarget() {
if (this.targetClass != PlayerEntity.class && this.targetClass != ServerPlayerEntity.class) {
this.targetEntity = this.mob
.getWorld()
.getClosestEntity(
this.mob.getWorld().getEntitiesByClass(this.targetClass, this.getSearchBox(this.getFollowRange()), livingEntity -> true),
this.targetPredicate,
this.mob,
this.mob.getX(),
this.mob.getEyeY(),
this.mob.getZ()
);
} else {
this.targetEntity = this.mob.getWorld().getClosestPlayer(this.targetPredicate, this.mob, this.mob.getX(), this.mob.getEyeY(), this.mob.getZ());
}
}

@Override
public void start() {
this.mob.setTarget(this.targetEntity);
super.start();
}

public void setTargetEntity(@Nullable LivingEntity targetEntity) {
this.targetEntity = targetEntity;
}
}
133 changes: 133 additions & 0 deletions src/main/java/com/equilibrium/entity/goal/AdvanceTargetPredicate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package com.equilibrium.entity.goal;

import java.util.function.Predicate;

import com.equilibrium.tags.ModBlockTags;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.Difficulty;
import net.minecraft.world.RaycastContext;
import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable;

public class AdvanceTargetPredicate extends TargetPredicate {
public static final AdvanceTargetPredicate DEFAULT = createAttackable();
private static final double MIN_DISTANCE = 2.0;
private final boolean attackable;
private double baseMaxDistance = -1.0;
private boolean respectsVisibility = true;
private boolean useDistanceScalingFactor = true;
@Nullable
private Predicate<LivingEntity> predicate;

private AdvanceTargetPredicate(boolean attackable) {
super(attackable);
this.attackable = attackable;
}

public static AdvanceTargetPredicate createAttackable() {
return new AdvanceTargetPredicate(true);
}

public static AdvanceTargetPredicate createNonAttackable() {
return new AdvanceTargetPredicate(false);
}

public AdvanceTargetPredicate copy() {

AdvanceTargetPredicate advanceTargetPredicate = this.attackable ? createAttackable() : createNonAttackable();
advanceTargetPredicate.baseMaxDistance = this.baseMaxDistance;
advanceTargetPredicate.respectsVisibility = this.respectsVisibility;
advanceTargetPredicate.useDistanceScalingFactor = this.useDistanceScalingFactor;
advanceTargetPredicate.predicate = this.predicate;
return advanceTargetPredicate;
}

public AdvanceTargetPredicate setBaseMaxDistance(double baseMaxDistance) {
this.baseMaxDistance = baseMaxDistance;
return this;
}

public AdvanceTargetPredicate ignoreVisibility() {
this.respectsVisibility = false;
return this;
}

public AdvanceTargetPredicate ignoreDistanceScalingFactor() {
this.useDistanceScalingFactor = false;
return this;
}

public AdvanceTargetPredicate setPredicate(@Nullable Predicate<LivingEntity> predicate) {
this.predicate = predicate;
return this;
}

public boolean test(@Nullable LivingEntity baseEntity, LivingEntity targetEntity) {
if (baseEntity == targetEntity) {
return false;
} else if (!targetEntity.isPartOfGame()) {
return false;
} else if (this.predicate != null && !this.predicate.test(targetEntity)) {
return false;
} else {
if (baseEntity == null) {
if (this.attackable && (!targetEntity.canTakeDamage() || targetEntity.getWorld().getDifficulty() == Difficulty.PEACEFUL)) {
return false;
}
} else {
if (this.attackable && (!baseEntity.canTarget(targetEntity) || !baseEntity.canTarget(targetEntity.getType()) || baseEntity.isTeammate(targetEntity))) {
return false;
}

if (this.baseMaxDistance > 0.0) {
double d = this.useDistanceScalingFactor ? targetEntity.getAttackDistanceScalingFactor(baseEntity) : 1.0;
double e = Math.max(this.baseMaxDistance * d, 2.0);
double f = baseEntity.squaredDistanceTo(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ());
if (f > e * e) {
return false;
}
}

if (this.respectsVisibility && baseEntity instanceof MobEntity mobEntity && !canSeeThroughTransparentBlocks(mobEntity, targetEntity)) {
return false;
}
}

return true;
}
}
private boolean canSeeThroughTransparentBlocks(MobEntity mobEntity, LivingEntity targetEntity) {
World world = mobEntity.getWorld();
Vec3d startPos = new Vec3d(mobEntity.getX(), mobEntity.getEyeY(), mobEntity.getZ());
Vec3d endPos = new Vec3d(targetEntity.getX(), targetEntity.getEyeY(), targetEntity.getZ());

double followRange = mobEntity.getAttributeValue(EntityAttributes.GENERIC_FOLLOW_RANGE);
double distance = startPos.distanceTo(endPos);

// If the distance exceeds the follow range, return false
if (distance > followRange) {
return false;
}






BlockHitResult hitResult = world.raycast(new RaycastContext(startPos, endPos, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, mobEntity));

BlockPos hitPos = hitResult.getBlockPos();
BlockState blockState = world.getBlockState(hitPos);

// Check if the block is transparent
return blockState.isTransparent(world,hitPos) || blockState.isAir()||blockState.isIn(ModBlockTags.TRANSPARENT_FOR_ZOMBIE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.equilibrium.entity.goal;

import java.util.EnumSet;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.ai.goal.TrackTargetGoal;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.PassiveEntity;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.util.math.Box;
import org.jetbrains.annotations.Nullable;

/**
* A target goal that finds a passive entity as the target.
*/
public class AttackPassiveEntitiesGoal<T extends LivingEntity> extends TrackTargetGoal {
private final Class<T> targetClass;
@Nullable
private LivingEntity targetEntity;
private final TargetPredicate targetPredicate;

public AttackPassiveEntitiesGoal(MobEntity mob, Class<T> targetClass, boolean checkVisibility, boolean checkCanNavigate) {
super(mob, checkVisibility, checkCanNavigate);
this.targetClass = targetClass;
this.targetPredicate = TargetPredicate.createAttackable().setBaseMaxDistance(this.getFollowRange());
this.setControls(EnumSet.of(Goal.Control.TARGET));
}
protected Box getSearchBox(double distance) {
return this.mob.getBoundingBox().expand(distance, 4.0, distance);
}
@Override
public boolean canStart() {
this.findClosestTarget();
return this.targetEntity != null;
}

private void findClosestTarget() {
this.targetEntity = this.mob.getWorld().getClosestEntity(
this.mob.getWorld().getEntitiesByClass(this.targetClass, this.getSearchBox(this.getFollowRange()), (entity) -> entity instanceof PassiveEntity),
this.targetPredicate,
this.mob,
this.mob.getX(),
this.mob.getEyeY(),
this.mob.getZ()
);
}

@Override
public void start() {
this.mob.setTarget(this.targetEntity);
super.start();
}
}
Loading

0 comments on commit 5011f70

Please sign in to comment.