Commit 2379b5f8 by Jonathan Thomas

Limit waypoint locations to 45 degree angle from current direction. Remove…

Limit waypoint locations to 45 degree angle from current direction. Remove FuzzyTargeting (since it finds things too close to the entity to be useful). Fixed non path aware to use custom LookControls.
parent 7fc533f6
Pipeline #12709 passed with stages
in 1 minute 49 seconds
...@@ -10,8 +10,10 @@ All notable changes to **CreatureChat** are documented in this file. The format ...@@ -10,8 +10,10 @@ All notable changes to **CreatureChat** are documented in this file. The format
- New LEAD behavior, to guide a player to a random location (and show message when destination is reached) - New LEAD behavior, to guide a player to a random location (and show message when destination is reached)
### Changed ### Changed
- Updated README.md to include HTML inside spoiler instructions, and whitelist/blacklist commands - Updated LookControls to support PhantomEntity and made it more generalized (look in any direction)
- Updated FLEE behavior Y movement speed
- Updated unit tests to add new LEAD tests - Updated unit tests to add new LEAD tests
- Updated README.md to include HTML inside spoiler instructions, and whitelist/blacklist commands
## [1.0.8] - 2024-07-16 ## [1.0.8] - 2024-07-16
......
package com.owlmaddie.controls; package com.owlmaddie.controls;
import net.minecraft.entity.boss.dragon.EnderDragonEntity;
import net.minecraft.entity.mob.*; import net.minecraft.entity.mob.*;
import net.minecraft.entity.passive.SquidEntity; import net.minecraft.entity.passive.SquidEntity;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
...@@ -13,27 +12,31 @@ import net.minecraft.util.math.Vec3d; ...@@ -13,27 +12,31 @@ import net.minecraft.util.math.Vec3d;
*/ */
public class LookControls { public class LookControls {
public static void lookAtPlayer(ServerPlayerEntity player, MobEntity entity) { public static void lookAtPlayer(ServerPlayerEntity player, MobEntity entity) {
lookAtPosition(player.getPos(), entity);
}
public static void lookAtPosition(Vec3d targetPos, MobEntity entity) {
if (entity instanceof SlimeEntity) { if (entity instanceof SlimeEntity) {
handleSlimeLook((SlimeEntity) entity, player); handleSlimeLook((SlimeEntity) entity, targetPos);
} else if (entity instanceof SquidEntity) { } else if (entity instanceof SquidEntity) {
handleSquidLook((SquidEntity) entity, player); handleSquidLook((SquidEntity) entity, targetPos);
} else if (entity instanceof GhastEntity) { } else if (entity instanceof GhastEntity) {
handleFlyingEntity(entity, player, 10F); handleFlyingEntity(entity, targetPos, 10F);
} else if (entity instanceof FlyingEntity || entity instanceof VexEntity) { } else if (entity instanceof FlyingEntity || entity instanceof VexEntity) {
handleFlyingEntity(entity, player, 4F); handleFlyingEntity(entity, targetPos, 4F);
} else { } else {
// Make the entity look at the player // Make the entity look at the player
entity.getLookControl().lookAt(player, 10.0F, (float)entity.getMaxLookPitchChange()); entity.getLookControl().lookAt(targetPos.x, targetPos.y, targetPos.z, 10.0F, (float)entity.getMaxLookPitchChange());
} }
} }
private static void handleSlimeLook(SlimeEntity slime, ServerPlayerEntity player) { private static void handleSlimeLook(SlimeEntity slime, Vec3d targetPos) {
float yawChange = calculateYawChangeToPlayer(slime, player); float yawChange = calculateYawChange(slime, targetPos);
((SlimeEntity.SlimeMoveControl) slime.getMoveControl()).look(slime.getYaw() + yawChange, false); ((SlimeEntity.SlimeMoveControl) slime.getMoveControl()).look(slime.getYaw() + yawChange, false);
} }
private static void handleSquidLook(SquidEntity squid, ServerPlayerEntity player) { private static void handleSquidLook(SquidEntity squid, Vec3d targetPos) {
Vec3d toPlayer = calculateNormalizedDirection(squid, player); Vec3d toPlayer = calculateNormalizedDirection(squid, targetPos);
float initialSwimStrength = 0.15f; float initialSwimStrength = 0.15f;
squid.setSwimmingVector( squid.setSwimmingVector(
(float) toPlayer.x * initialSwimStrength, (float) toPlayer.x * initialSwimStrength,
...@@ -41,7 +44,7 @@ public class LookControls { ...@@ -41,7 +44,7 @@ public class LookControls {
(float) toPlayer.z * initialSwimStrength (float) toPlayer.z * initialSwimStrength
); );
double distanceToPlayer = squid.getPos().distanceTo(player.getPos()); double distanceToPlayer = squid.getPos().distanceTo(targetPos);
if (distanceToPlayer < 3.5F) { if (distanceToPlayer < 3.5F) {
// Stop motion when close // Stop motion when close
squid.setVelocity(0,0,0); squid.setVelocity(0,0,0);
...@@ -49,17 +52,16 @@ public class LookControls { ...@@ -49,17 +52,16 @@ public class LookControls {
} }
// Ghast, Phantom, etc... // Ghast, Phantom, etc...
private static void handleFlyingEntity(MobEntity flyingEntity, ServerPlayerEntity player, float stopDistance) { private static void handleFlyingEntity(MobEntity flyingEntity, Vec3d targetPos, float stopDistance) {
Vec3d playerPosition = player.getPos();
Vec3d flyingPosition = flyingEntity.getPos(); Vec3d flyingPosition = flyingEntity.getPos();
Vec3d toPlayer = playerPosition.subtract(flyingPosition).normalize(); Vec3d toPlayer = targetPos.subtract(flyingPosition).normalize();
// Calculate the yaw to align the flyingEntity's facing direction with the movement direction // Calculate the yaw to align the flyingEntity's facing direction with the movement direction
float targetYaw = (float)(MathHelper.atan2(toPlayer.z, toPlayer.x) * (180 / Math.PI) - 90); float targetYaw = (float)(MathHelper.atan2(toPlayer.z, toPlayer.x) * (180 / Math.PI) - 90);
flyingEntity.setYaw(targetYaw); flyingEntity.setYaw(targetYaw);
// Look at player while adjusting yaw // Look at player while adjusting yaw
flyingEntity.getLookControl().lookAt(player, 10.0F, (float)flyingEntity.getMaxLookPitchChange()); flyingEntity.getLookControl().lookAt(targetPos.x, targetPos.y, targetPos.z, 10.0F, (float)flyingEntity.getMaxLookPitchChange());
float initialSpeed = 0.15F; float initialSpeed = 0.15F;
flyingEntity.setVelocity( flyingEntity.setVelocity(
...@@ -68,23 +70,22 @@ public class LookControls { ...@@ -68,23 +70,22 @@ public class LookControls {
(float) toPlayer.z * initialSpeed (float) toPlayer.z * initialSpeed
); );
double distanceToPlayer = flyingEntity.getPos().distanceTo(player.getPos()); double distanceToPlayer = flyingEntity.getPos().distanceTo(targetPos);
if (distanceToPlayer < stopDistance) { if (distanceToPlayer < stopDistance) {
// Stop motion when close // Stop motion when close
flyingEntity.setVelocity(0, 0, 0); flyingEntity.setVelocity(0, 0, 0);
} }
} }
public static float calculateYawChangeToPlayer(MobEntity entity, ServerPlayerEntity player) { public static float calculateYawChange(MobEntity entity, Vec3d targetPos) {
Vec3d toPlayer = calculateNormalizedDirection(entity, player); Vec3d toPlayer = calculateNormalizedDirection(entity, targetPos);
float targetYaw = (float) Math.toDegrees(Math.atan2(toPlayer.z, toPlayer.x)) - 90.0F; float targetYaw = (float) Math.toDegrees(Math.atan2(toPlayer.z, toPlayer.x)) - 90.0F;
float yawDifference = MathHelper.wrapDegrees(targetYaw - entity.getYaw()); float yawDifference = MathHelper.wrapDegrees(targetYaw - entity.getYaw());
return MathHelper.clamp(yawDifference, -10.0F, 10.0F); return MathHelper.clamp(yawDifference, -10.0F, 10.0F);
} }
public static Vec3d calculateNormalizedDirection(MobEntity entity, ServerPlayerEntity player) { public static Vec3d calculateNormalizedDirection(MobEntity entity, Vec3d targetPos) {
Vec3d playerPos = player.getPos();
Vec3d entityPos = entity.getPos(); Vec3d entityPos = entity.getPos();
return playerPos.subtract(entityPos).normalize(); return targetPos.subtract(entityPos).normalize();
} }
} }
\ No newline at end of file
...@@ -34,6 +34,8 @@ public class SpeedControls { ...@@ -34,6 +34,8 @@ public class SpeedControls {
speed = 2F; speed = 2F;
} else if (entity instanceof RabbitEntity) { } else if (entity instanceof RabbitEntity) {
speed = 1.5F; speed = 1.5F;
} else if (entity instanceof PhantomEntity) {
speed = 0.2F;
} }
return speed; return speed;
......
...@@ -64,7 +64,7 @@ public class FleePlayerGoal extends PlayerBaseGoal { ...@@ -64,7 +64,7 @@ public class FleePlayerGoal extends PlayerBaseGoal {
Vec3d fleeDirection = entityPos.subtract(playerPos).normalize(); Vec3d fleeDirection = entityPos.subtract(playerPos).normalize();
// Apply movement with the entity's speed in the opposite direction // Apply movement with the entity's speed in the opposite direction
this.entity.setVelocity(fleeDirection.x * this.speed, this.entity.getVelocity().y, fleeDirection.z * this.speed); this.entity.setVelocity(fleeDirection.x * this.speed, fleeDirection.y * this.speed, fleeDirection.z * this.speed);
this.entity.velocityModified = true; this.entity.velocityModified = true;
} }
} }
......
package com.owlmaddie.goals; package com.owlmaddie.goals;
import com.owlmaddie.chat.ChatDataManager; import com.owlmaddie.chat.ChatDataManager;
import com.owlmaddie.controls.LookControls;
import com.owlmaddie.network.ServerPackets; import com.owlmaddie.network.ServerPackets;
import net.minecraft.entity.ai.FuzzyTargeting;
import net.minecraft.entity.ai.pathing.Path; import net.minecraft.entity.ai.pathing.Path;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.mob.PathAwareEntity; import net.minecraft.entity.mob.PathAwareEntity;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.particle.ParticleTypes;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -59,7 +63,7 @@ public class LeadPlayerGoal extends PlayerBaseGoal { ...@@ -59,7 +63,7 @@ public class LeadPlayerGoal extends PlayerBaseGoal {
// Are we there yet? // Are we there yet?
if (currentWaypoint >= totalWaypoints && !foundWaypoint) { if (currentWaypoint >= totalWaypoints && !foundWaypoint) {
foundWaypoint = true; foundWaypoint = true;
LOGGER.info("destination reached"); LOGGER.info("Tick: You have ARRIVED at your destination");
ServerPackets.scheduler.scheduleTask(() -> { ServerPackets.scheduler.scheduleTask(() -> {
// Prepare a message about the interaction // Prepare a message about the interaction
...@@ -80,65 +84,86 @@ public class LeadPlayerGoal extends PlayerBaseGoal { ...@@ -80,65 +84,86 @@ public class LeadPlayerGoal extends PlayerBaseGoal {
setNewTarget(); setNewTarget();
moveToTarget(); moveToTarget();
ticksSinceLastWaypoint = 0; ticksSinceLastWaypoint = 0;
}
}
private void setNewTarget() {
boolean targetFound = false;
if (this.entity instanceof PathAwareEntity) { } else if (!(this.entity instanceof PathAwareEntity)) {
int attempts = 0; moveToTarget();
while (attempts < 3 && !targetFound) {
Vec3d target = FuzzyTargeting.findFrom((PathAwareEntity) this.entity, 16, 6, this.entity.getPos());
if (target != null) {
currentWaypoint++;
this.currentTarget = target;
LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
targetFound = true;
}
attempts++;
}
}
if (!targetFound) {
// Fallback if no target found after 3 attempts
currentWaypoint++;
LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
double distance = 20 + random.nextDouble() * 80;
double angle = random.nextDouble() * 2 * Math.PI;
double x = this.targetEntity.getX() + distance * Math.cos(angle);
double y = this.targetEntity.getY() + (random.nextDouble() * 10 - 5); // Similar y-coordinate depth
double z = this.targetEntity.getZ() + distance * Math.sin(angle);
this.currentTarget = new Vec3d(x, y, z);
} }
} }
private void moveToTarget() { private void moveToTarget() {
if (this.currentTarget != null) { if (this.currentTarget != null) {
if (this.entity instanceof PathAwareEntity) { // Make the entity look at the player without moving towards them
int attempts = 0; LookControls.lookAtPosition(this.currentTarget, this.entity);
while (attempts < 3) { Path path = this.entity.getNavigation().findPathTo(this.currentTarget.x, this.currentTarget.y, this.currentTarget.z, 2);
Path path = this.entity.getNavigation().findPathTo(this.currentTarget.x, this.currentTarget.y, this.currentTarget.z, 1);
if (path != null) { if (path != null) {
LOGGER.info("Start moving towards waypoint PATH");
this.entity.getNavigation().startMovingAlong(path, this.speed); this.entity.getNavigation().startMovingAlong(path, this.speed);
return;
}
attempts++;
}
} else { } else {
// Move directly towards the target for non-path aware entities // Move towards the target for non-path aware entities
Vec3d entityPos = this.entity.getPos(); Vec3d entityPos = this.entity.getPos();
Vec3d moveDirection = this.currentTarget.subtract(entityPos).normalize(); Vec3d moveDirection = this.currentTarget.subtract(entityPos).normalize();
this.entity.setVelocity(moveDirection.x * this.speed, this.entity.getVelocity().y, moveDirection.z * this.speed);
// Calculate current speed from the entity's current velocity
double currentSpeed = this.entity.getVelocity().horizontalLength();
// Gradually adjust speed towards the target speed
currentSpeed = MathHelper.stepTowards((float)currentSpeed, (float)this.speed, (float) (0.005 * (this.speed / Math.max(currentSpeed, 0.1))));
// Apply movement with the adjusted speed towards the target
Vec3d newVelocity = new Vec3d(moveDirection.x * currentSpeed, this.entity.getVelocity().y, moveDirection.z * currentSpeed);
this.entity.setVelocity(newVelocity);
this.entity.velocityModified = true; this.entity.velocityModified = true;
} }
} }
} }
@Override private void setNewTarget() {
public void start() { // Increment waypoint
moveToTarget(); currentWaypoint++;
LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
this.currentTarget = findNextWaypoint();
emitParticleAt(this.currentTarget, ParticleTypes.FLAME);
}
private Vec3d findNextWaypoint() {
LOGGER.info("Create waypoint position");
Vec3d entityPos = this.entity.getPos();
Vec3d currentDirection;
// Check if currentTarget is null
if (this.currentTarget == null) {
// If currentTarget is null, use the entity's facing direction
double yaw = this.entity.getYaw() * (Math.PI / 180); // Convert to radians
currentDirection = new Vec3d(Math.cos(yaw), 0, Math.sin(yaw));
} else {
// Calculate the current direction vector
currentDirection = this.currentTarget.subtract(entityPos).normalize();
}
// Calculate the angle of the current direction
double currentAngle = Math.atan2(currentDirection.z, currentDirection.x);
// Generate a random angle within ±45 degrees of the current direction
double randomAngleOffset = (random.nextDouble() * (Math.PI / 4)) - (Math.PI / 8); // ±45 degrees
double angle = currentAngle + randomAngleOffset;
// Calculate the random distance
double distance = 16 + random.nextDouble() * 2;
// Calculate new coordinates based on the limited angle
double x = entityPos.x + distance * Math.cos(angle);
double y = entityPos.y + (random.nextDouble() * 10 - 5); // Similar y-coordinate depth
double z = entityPos.z + distance * Math.sin(angle);
return new Vec3d(x, y, z);
}
private void emitParticleAt(Vec3d position, ParticleEffect particleType) {
ServerWorld serverWorld = (ServerWorld) this.entity.getWorld();
serverWorld.spawnParticles(particleType, position.x, position.y, position.z, 3, 0, 0, 0, 0);
} }
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment