LeadPlayerGoal.java 7.38 KB
Newer Older
1 2 3
package com.owlmaddie.goals;

import com.owlmaddie.chat.ChatDataManager;
4
import com.owlmaddie.chat.EntityChatData;
5
import com.owlmaddie.controls.LookControls;
6
import com.owlmaddie.network.ServerPackets;
7
import com.owlmaddie.particle.LeadParticleEffect;
8
import com.owlmaddie.utils.RandomTargetFinder;
9 10
import net.minecraft.entity.ai.pathing.Path;
import net.minecraft.entity.mob.MobEntity;
11
import net.minecraft.entity.mob.PathAwareEntity;
12
import net.minecraft.server.network.ServerPlayerEntity;
13 14
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.MathHelper;
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
import net.minecraft.util.math.Vec3d;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.EnumSet;
import java.util.Random;

/**
 * The {@code LeadPlayerGoal} class instructs a Mob Entity to lead the player to a random location, consisting
 * of many random waypoints. It supports PathAware and NonPathAware entities.
 */
public class LeadPlayerGoal extends PlayerBaseGoal {
    public static final Logger LOGGER = LoggerFactory.getLogger("creaturechat");
    private final MobEntity entity;
    private final double speed;
    private final Random random = new Random();
    private int currentWaypoint = 0;
    private int totalWaypoints;
    private Vec3d currentTarget = null;
    private boolean foundWaypoint = false;
    private int ticksSinceLastWaypoint = 0;

    public LeadPlayerGoal(ServerPlayerEntity player, MobEntity entity, double speed) {
        super(player);
        this.entity = entity;
        this.speed = speed;
        this.setControls(EnumSet.of(Control.MOVE, Control.LOOK));
42
        this.totalWaypoints = random.nextInt(14) + 6;
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
    }

    @Override
    public boolean canStart() {
        return super.canStart() && !foundWaypoint && this.entity.squaredDistanceTo(this.targetEntity) <= 16 * 16 && !foundWaypoint;
    }

    @Override
    public boolean shouldContinue() {
        return super.canStart() && !foundWaypoint && this.entity.squaredDistanceTo(this.targetEntity) <= 16 * 16 && !foundWaypoint;
    }

    @Override
    public void tick() {
        ticksSinceLastWaypoint++;

        if (this.entity.squaredDistanceTo(this.targetEntity) > 16 * 16) {
            this.entity.getNavigation().stop();
            return;
        }

        // Are we there yet?
        if (currentWaypoint >= totalWaypoints && !foundWaypoint) {
            foundWaypoint = true;
67
            LOGGER.info("Tick: You have ARRIVED at your destination");
68

69 70 71
            ServerPackets.scheduler.scheduleTask(() -> {
                // Prepare a message about the interaction
                String arrivedMessage = "<You have arrived at your destination>";
72

73
                ChatDataManager chatDataManager = ChatDataManager.getServerInstance();
74
                EntityChatData chatData = chatDataManager.getOrCreateChatData(this.entity.getUuidAsString());
75 76 77 78
                if (!chatData.characterSheet.isEmpty() && chatData.auto_generated < chatDataManager.MAX_AUTOGENERATE_RESPONSES) {
                    ServerPackets.generate_chat("N/A", chatData, (ServerPlayerEntity) this.targetEntity, this.entity, arrivedMessage, true);
                }
            });
79 80 81 82

            // Stop navigation
            this.entity.getNavigation().stop();

83
        } else if (this.currentTarget == null || this.entity.squaredDistanceTo(this.currentTarget) < 2 * 2 || ticksSinceLastWaypoint >= 20 * 10) {
84 85 86 87 88
            // Set next waypoint
            setNewTarget();
            moveToTarget();
            ticksSinceLastWaypoint = 0;

89
        } else {
90
            moveToTarget();
91 92 93 94 95
        }
    }

    private void moveToTarget() {
        if (this.currentTarget != null) {
96 97 98 99
            if (this.entity instanceof PathAwareEntity) {
                 if (!this.entity.getNavigation().isFollowingPath()) {
                     Path path = this.entity.getNavigation().findPathTo(this.currentTarget.x, this.currentTarget.y, this.currentTarget.z, 1);
                     if (path != null) {
100
                         LOGGER.debug("Start moving along path");
101 102 103
                         this.entity.getNavigation().startMovingAlong(path, this.speed);
                     }
                 }
104
            } else {
105 106 107
                // Make the entity look at the player without moving towards them
                LookControls.lookAtPosition(this.currentTarget, this.entity);

108
                // Move towards the target for non-path aware entities
109 110
                Vec3d entityPos = this.entity.getPos();
                Vec3d moveDirection = this.currentTarget.subtract(entityPos).normalize();
111 112 113 114 115

                // Calculate current speed from the entity's current velocity
                double currentSpeed = this.entity.getVelocity().horizontalLength();

                // Gradually adjust speed towards the target speed
116
                currentSpeed = MathHelper.stepTowards((float) currentSpeed, (float) this.speed, (float) (0.005 * (this.speed / Math.max(currentSpeed, 0.1))));
117 118

                // Apply movement with the adjusted speed towards the target
119
                Vec3d newVelocity = new Vec3d(moveDirection.x * currentSpeed, moveDirection.y * currentSpeed, moveDirection.z * currentSpeed);
120 121

                this.entity.setVelocity(newVelocity);
122 123 124 125 126
                this.entity.velocityModified = true;
            }
        }
    }

127 128 129 130
    private void setNewTarget() {
        // Increment waypoint
        currentWaypoint++;
        LOGGER.info("Waypoint " + currentWaypoint + " / " + this.totalWaypoints);
131
        this.currentTarget = RandomTargetFinder.findRandomTarget(this.entity, 30, 24, 36);
132
        if (this.currentTarget != null) {
133
            emitParticlesAlongRaycast(this.entity.getPos(), this.currentTarget);
134
        }
135 136 137

        // Stop following current path (if any)
        this.entity.getNavigation().stop();
138 139
    }

140
    private void emitParticleAt(Vec3d position, double angle) {
141 142
        if (this.entity.getWorld() instanceof ServerWorld) {
            ServerWorld serverWorld = (ServerWorld) this.entity.getWorld();
143 144 145

            // Pass the angle using the "speed" argument, with deltaX, deltaY, deltaZ set to 0
            LeadParticleEffect effect = new LeadParticleEffect(angle);
146
            serverWorld.spawnParticles(effect, position.x, position.y + 0.05, position.z, 1, 0, 0, 0, 0);
147 148 149
        }
    }

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    private void emitParticlesAlongRaycast(Vec3d start, Vec3d end) {
        // Calculate the direction vector from the entity (start) to the target (end)
        Vec3d direction = end.subtract(start);

        // Calculate the angle in the XZ-plane using atan2 (this is in radians)
        double angleRadians = Math.atan2(direction.z, direction.x);

        // Convert from radians to degrees
        double angleDegrees = Math.toDegrees(angleRadians);

        // Convert the calculated angle to Minecraft's yaw system:
        double minecraftYaw = (360 - (angleDegrees + 90)) % 360;

        // Correct the 180-degree flip
        minecraftYaw = (minecraftYaw + 180) % 360;
        if (minecraftYaw < 0) {
            minecraftYaw += 360;
        }

169
        // Emit particles along the ray from startRange to endRange
170
        double distance = start.distanceTo(end);
171 172 173
        double startRange = Math.min(5, distance);;
        double endRange = Math.min(startRange + 10, distance);
        for (double d = startRange; d <= endRange; d += 5) {
174 175
            Vec3d pos = start.add(direction.normalize().multiply(d));
            emitParticleAt(pos, Math.toRadians(minecraftYaw));  // Convert back to radians for rendering
176
        }
177 178
    }
}