001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *    http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package net.tridentsdk.server.entity.ai.pathfind;
019
020import net.tridentsdk.util.Vector;
021
022import javax.annotation.concurrent.NotThreadSafe;
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.LinkedList;
026import java.util.List;
027
028@NotThreadSafe
029public class Path {
030    private final List<Node> pathPoints;
031    private int index;
032    private double step;
033
034    public Path(Node end) {
035        LinkedList<Node> trace = new LinkedList<>();
036
037        while(end != null) {
038            trace.add(end);
039            end = end.parent();
040        }
041
042        Collections.reverse(trace); // Reverse list so that it isn't backwards
043        this.pathPoints = new ArrayList<>(trace);
044    }
045
046    /**
047     * Get the movement for the enxt tick based on the speed of the entity.
048     *
049     * @param speed of entity (blocks per tick).
050     * @return Movement for entity in current tick
051     */
052    public Vector pollMovement(double speed) {
053        if(speed > 1.0) {
054            throw new IllegalArgumentException("Cannot move more than 1X/tick!");
055        }
056
057        Vector movement = new Vector(0, 0, 0);
058        Node current = pathPoints.get(index);
059        Node next = pathPoints.get(index + 1);
060        double dx = next.x() - current.x();
061        double dz = next.z() - current.z();
062
063        if(speed + step >= 1.0) {
064            movement.add(1 - step, 0, 1 - step);
065
066            // Find next node
067            index += 1;
068
069            if(!finished()) {
070                movement.setY(next.y() - current.y());
071
072                // Recalculate values
073                current = next;
074                next = pathPoints.get(index + 1);
075                dx = next.x() - current.x();
076                dz = next.z() - current.z();
077                this.step = 0.0;
078            }
079        }
080
081        step += speed;
082        movement.add(dx * speed, 0, dz * speed);
083        return movement;
084    }
085
086    public boolean finished() {
087        return index >= pathPoints.size() - 1;
088    }
089}