/// This script is a replacement for the <see cref="AIPath"/> and <see cref="RichAI"/> scripts.
///
/// This script is a movement script. It takes care of moving an agent along a path, updating the path, and so on.
///
/// \section followerentity-contents Contents
/// \toc
///
/// \section followerentity-intro Introduction
///
/// The intended way to use this script is to use these two components:
/// - <see cref="FollowerEntity"/>
/// - <see cref="AIDestinationSetter"/> (optional, you can instead set the <see cref="destination"/> property manually)
///
/// Of note is that this component shouldn't be used with a <see cref="Seeker"/> component.
/// It has its own settings for pathfinding instead, which are stored in the <see cref="pathfindingSettings"/> field.
///
/// When used with local avoidance, it also has its own settings for local avoidance which are stored in the <see cref="rvoSettings"/> field,
/// instead of using a separate <see cref="RVOController"/> component.
///
/// Other than that, you can use it just like the other movement scripts in this package.
///
/// \section followerentity-features Features
///
/// - Uses Unity's ECS (Entity Component System) to move the agent. This means it is highly-performant and is able to utilize multiple threads.
/// You do not need to know anything about ECS to be able to use it.
/// - Supports local avoidance (see local-avoidance) (view in online documentation for working links).
/// - Supports movement in both 2D and 3D games.
/// - Supports movement on spherical on non-planar worlds (see spherical) (view in online documentation for working links).
/// - Supports movement on grid graphs as well as navmesh/recast graphs.
/// - Not recommended on hexagonal graphs at the moment (though it does mostly work).
/// - Does <b>not</b> support movement on point graphs at the moment. This may be added in a future update.
/// - Supports time-scales greater than 1. The agent will automatically run multiple simulation steps per frame if the time-scale is greater than 1, to ensure stability.
/// - Supports off-mesh links. See offmeshlinks (view in online documentation for working links) for more info.
/// - Knows which node it is traversing at all times (see <see cref="currentNode)"/>.
/// - Automatically stops when trying to reach a crowded destination when using local avoidance.
/// - Clamps the agent to the navmesh at all times.
/// - Follows paths very smoothly.
/// - Can keep a desired distance to walls.
/// - Can approach its destination with a desired facing direction.
/// This script uses Unity's ECS (Entity Component System) to move the agent. This means it is highly-performant and is able to utilize multiple threads.
/// Internally, an entity is created for the agent with the following components:
///
/// - LocalTransform
/// - <see cref="MovementState"/>
/// - <see cref="MovementSettings"/>
/// - <see cref="MovementControl"/>
/// - <see cref="ManagedState"/>
/// - <see cref="SearchState"/>
/// - <see cref="MovementStatistics"/>
/// - <see cref="AgentCylinderShape"/>
/// - <see cref="ResolvedMovement"/>
/// - <see cref="GravityState"/>
/// - <see cref="DestinationPoint"/>
/// - <see cref="AgentMovementPlane"/>
/// - <see cref="SimulateMovement"/> - tag component (if <see cref="canMove"/> is enabled)
/// - <see cref="SimulateMovementRepair"/> - tag component
/// - <see cref="SimulateMovementControl"/> - tag component
/// - <see cref="SimulateMovementFinalize"/> - tag component
/// - <see cref="SyncPositionWithTransform"/> - tag component (if <see cref="updatePosition"/> is enabled)
/// - <see cref="SyncRotationWithTransform"/> - tag component (if <see cref="updateRotation"/> is enabled)
/// - <see cref="OrientationYAxisForward"/> - tag component (if <see cref="orientation"/> is <see cref="OrientationMode"/>.YAxisForward)
/// - <see cref="ECS.RVO.RVOAgent"/> (if local avoidance is enabled)
/// Then this script barely does anything by itself. It is a thin wrapper around the ECS components.
/// Instead, actual movement calculations are carried out by the following systems:
///
/// - <see cref="SyncTransformsToEntitiesSystem"/> - Updates the entity's transform from the GameObject.
/// - <see cref="MovementPlaneFromGraphSystem"/> - Updates the agent's movement plane.
/// - <see cref="SyncDestinationTransformSystem"/> - Updates the destination point if the destination transform moves.
/// - <see cref="RepairPathSystem"/> - Keeps the agent's path up to date.
/// - <see cref="FollowerControlSystem"/> - Calculates how the agent wants to move.
/// - <see cref="RVOSystem"/> - Local avoidance calculations.
/// - <see cref="FallbackResolveMovementSystem"/> - NOOP system for if local avoidance is disabled.
/// - <see cref="AIMoveSystem"/> - Performs the actual movement.
///
/// In fact, as long as you create the appropriate ECS components, you do not even need this script. You can use the systems directly.
///
/// This is <b>not</b> a baked component. That is, this script will continue to work even in standalone games. It is designed to be easily used
/// without having to care too much about the underlying ECS implementation.
///
/// \section followerentity-differences Differences compared to AIPath and RichAI
///
/// This movement script has been written to remedy several inconsistency issues with other movement scrips, to provide very smooth movement,
/// and "just work" for most games.
///
/// For example, it goes to great lengths to ensure
/// that the <see cref="reachedDestination"/> and <see cref="reachedEndOfPath"/> properties are as accurate as possible at all times, even before it has had time to recalculate its path to account for a new <see cref="destination"/>.
/// It does this by locally repairing the path (if possible) immediately when the destination changes instead of waiting for a path recalculation.
/// This also has a bonus effect that the agent can often work just fine with moving targets, even if it almost never recalculates its path (though the repaired path may not always be optimal),
/// and it leads to very responsive movement.
///
/// In contrast to other movement scripts, this movement script does not use path modifiers at all.
/// Instead, this script contains its own internal <see cref="FunnelModifier"/> which it uses to simplify the path before it follows it.
/// In also doesn't use a separate <see cref="RVOController"/> component for local avoidance, but instead it stores local avoidance settings in <see cref="rvoSettings"/>.
///
/// \section followerentity-bestpractices Best practices for good performance
///
/// Here are some tips for how to improve performance when using this script.
/// As always, make sure to profile your game first, to see what is actually causing performance problems.
///
/// <b>Disable unused features</b>
/// This script has some optional parts. Local avoidance, for example. Local avoidance is used to make sure that agents do not overlap with each other.
/// However, if you do not need it, you can disable it to improve performance.
///
/// <b>Don't change the destination unnecessarily</b>
/// Repairing the path each frame can be a significant part of the movement calculation time. The FollowerEntity will perform better
/// if the <see cref="destination"/> is static, or moves seldom. For example, updating the destination every 10 frames will be faster than updating it every frame,
/// but to the player, both will look basically the same.
///
/// Note: Repairing the path is different from recalculating it from scratch. The agent will recalculate the path from scratch relatively seldom,
/// but it will repair it every frame, if necessary, to account for small changes in the agent's position and destination.
///
/// <b>Disable debug rendering</b>
/// Debug rendering has some performance costs in the Unity Editor. Disable all <see cref="debugFlags"/> and <see cref="rvoSettings.debug"/> to improve performance.
/// However, in standalone builds, these are automatically disabled and have no cost.
///
/// <b>Be aware of property access costs</b>
/// Using ECS components has some downsides. Accessing properties on this script is significantly slower compared to accessing properties on other movement scripts.
/// This is because on each property access, the script has to make sure no jobs are running concurrently, which is a relatively expensive operation.
/// Slow is a relative term, though. This only starts to matter if you have lots of agents, maybe a hundred or so. So don't be scared of using it.
///
/// But if you have a lot of agents, it is recommended to not access properties on this script more often than required. Avoid setting fields to the same value over and over again every frame, for example.
/// If you have a moving target, try to use the <see cref="AIDestinationSetter"/> component instead of setting the <see cref="destination"/> property manually, as that is faster than setting the <see cref="destination"/> property every frame.
///
/// You can instead write custom ECS systems to access the properties on the ECS components directly. This is much faster.
/// For example, if you want to make the agent follow a particular entity, you could create a new DestinationEntity component which just holds an entity reference,
/// and then create a system that every frame copies that entity's position to the <see cref="DestinationPoint.destination"/> field (a component that this entity will always have).
///
/// \section followerentity-timescale Time scaling
/// This component will automatically run multiple simulation steps per frame if the time scale is greater than 1.
/// This is done to ensure that the movement remains stable even at high time scales.
/// One case when this happens is when fast-forwarding games, which is common in some types of city builders and other types of simulation games.
/// This will impact performance at high time scales, but it is necessary to ensure that the movement remains stable.
/// This is visualized in the scene view as a yellow cylinder around the character.
///
/// This value is used for various heuristics, and for visualization purposes.
/// For example, the destination is only considered reached if the destination is not above the agent's head, and it's not more than half the agent's height below its feet.
///
/// If local lavoidance is enabled, this is also used to filter out collisions with agents and obstacles that are too far above or below the agent.
/// The off-mesh link that the agent is currently traversing.
///
/// This will be a default <see cref="OffMeshLinks.OffMeshLinkTracer"/> if the agent is not traversing an off-mesh link (the <see cref="OffMeshLinks.OffMeshLinkTracer.link"/> field will be null).
///
/// Note: If the off-mesh link is destroyed while the agent is traversing it, this property will still return the link.
/// But be careful about accessing properties like <see cref="OffMeshLinkSource.gameObject"/>, as that may refer to a destroyed gameObject.
///
/// See: offmeshlinks (view in online documentation for working links)
/// Warning: Off-mesh links can be destroyed or disabled at any moment. The built-in code will attempt to make the agent continue following the link even if it is destroyed,
/// but if you write your own traversal code, you should be aware of this.
///
/// You can alternatively set the corresponding property property on the off-mesh link (<see cref="NodeLink2.onTraverseOffMeshLink"/>) to specify a callback for a specific off-mesh link.
///
/// Note: The agent's off-mesh link handler takes precedence over the link's off-mesh link handler, if both are set.
///
/// See: offmeshlinks (view in online documentation for working links) for more details and example code
Debug.LogWarning("Cannot set agent rotation because updateRotation is false and the FollowerEntity component has not been enabled yet. Therefore, the internal entity does not exist, and there's no rotation to set.",this);
}
}
}
}
/// <summary>
/// How to calculate which direction is "up" for the agent.
///
/// In almost all cases, you should use the Graph option. This will make the agent use the graph's natural "up" direction.
/// However, if you are using a spherical world, or a world with some other strange shape, then you may want to use the NavmeshNormal or Raycast options.
///
/// See: spherical (view in online documentation for working links)
/// Actual velocity that the agent is moving with.
/// In world units per second.
///
/// This is useful for, for example, selecting which animations to play, and at what speeds.
///
/// Note: Any value set here will be overriden during the next simulation step. Nevertheless, it can be useful to set this value if you have disabled the agent's movement logic using e.g. <see cref="canMove"/>.
/// This value is only an output statistic. It is not used to control the agent's movement.
set=>thrownewNotImplementedException("The FollowerEntity does not support setting this property. If you want to override the movement, you'll need to write a custom entity component system.");
}
/// <summary>
/// Approximate remaining distance along the current path to the end of the path.
///
/// The agent does not know the true distance at all times, so this is an approximation.
/// It tends to be a bit lower than the true distance.
///
/// Note: This is the distance to the end of the path, which may or may not be the same as the destination.
/// If the character cannot reach the destination it will try to move as close as possible to it.
///
/// This value will update immediately if the <see cref="destination"/> property is changed, or if the agent is moved using the <see cref="position"/> property or the <see cref="Teleport"/> method.
///
/// If the agent has no path, or if the current path is stale (e.g. if the graph has been updated close to the agent, and it hasn't had time to recalculate its path), this will return positive infinity.
/// True if the ai has reached the <see cref="destination"/>.
///
/// The agent considers the destination reached when it is within <see cref="stopDistance"/> world units from the <see cref="destination"/>.
/// Additionally, the destination must not be above the agent's head, and it must not be more than half the agent's height below its feet.
///
/// If a facing direction was specified when setting the destination, this will only return true once the agent is approximately facing the correct orientation.
///
/// This value will be updated immediately when the <see cref="destination"/> is changed.
///
/// <code>
/// IEnumerator Start () {
/// ai.destination = somePoint;
/// // Start to search for a path to the destination immediately
/// ai.SearchPath();
/// // Wait until the agent has reached the destination
/// while (!ai.reachedDestination) {
/// yield return null;
/// }
/// // The agent has reached the destination now
/// }
/// </code>
///
/// Note: The agent may not be able to reach the destination. In that case this property may never become true. Sometimes <see cref="reachedEndOfPath"/> is more appropriate.
/// True if the agent has reached the end of the current path.
///
/// The agent considers the end of the path reached when it is within <see cref="stopDistance"/> world units from the end of the path.
/// Additionally, the end of the path must not be above the agent's head, and it must not be more than half the agent's height below its feet.
///
/// If a facing direction was specified when setting the destination, this will only return true once the agent is approximately facing the correct orientation.
///
/// This value will be updated immediately when the <see cref="destination"/> is changed.
///
/// Note: Reaching the end of the path does not imply that it has reached its desired destination, as the destination may not even be possible to reach.
/// Sometimes <see cref="reachedDestination"/> is more appropriate.
/// Like <see cref="reachedEndOfPath"/>, but will also return true if the end of the path is crowded, and this agent has stopped because it cannot get closer.
///
/// This is only relevant if the agent is using local avoidance. Otherwise, this will be identical to <see cref="reachedEndOfPath"/>.
///
/// If the agent has a stale path (e.g. because the destination changed significantly, or a graph update happened near the agent), false will be returned
/// until the path has been recalculated (typically in the next one or two frames).
///
/// You can see a visualization of this state by enabling "Reached State" in the <see cref="rvoSettings.debug;Local Avoidance Debug Rendering"/> field.
///
/// Note: The agent may not be completely stopped when this is true. It knows that there are other agents in the way, but it might still be able to slowly make some progress.
/// Check the <see cref="velocity"/> property to see if the agent is actually moving.
///
/// In the video below, the agents will get a red ring around them when this property is true.
///
/// [Open online documentation to see videos]
///
/// See: local-avoidance (view in online documentation for working links).
/// Position in the world that this agent should move to.
///
/// If no destination has been set yet, then (+infinity, +infinity, +infinity) will be returned.
///
/// Setting this property will immediately try to repair the path if the agent already has a path.
/// This will also immediately update properties like <see cref="reachedDestination"/>, <see cref="reachedEndOfPath"/> and <see cref="remainingDistance"/>.
///
/// The agent may do a full path recalculation if the local repair was not sufficient,
/// but this will at earliest happen in the next simulation step.
///
/// <code>
/// IEnumerator Start () {
/// ai.destination = somePoint;
/// // Wait until the AI has reached the destination
/// while (!ai.reachedEndOfPath) {
/// yield return null;
/// }
/// // The agent has reached the destination now
/// }
/// </code>
///
/// See: <see cref="SetDestination"/>, which also allows you to set a facing direction for the agent.
/// Direction the agent will try to face when it reaches the destination.
///
/// If this is zero, the agent will not try to face any particular direction.
///
/// The following video shows three agents, one with no facing direction set, and then two agents with varying values of the <see cref="PIDMovement.leadInRadiusWhenApproachingDestination;lead in radius"/>.
/// Set the position in the world that this agent should move to.
///
/// This method will immediately try to repair the path if the agent already has a path.
/// This will also immediately update properties like <see cref="reachedDestination"/>, <see cref="reachedEndOfPath"/> and <see cref="remainingDistance"/>.
/// The agent may do a full path recalculation if the local repair was not sufficient,
/// but this will at earliest happen in the next simulation step.
///
/// If you are setting a destination and want to know when the agent has reached that destination,
/// then you could use either <see cref="reachedDestination"/> or <see cref="reachedEndOfPath"/>.
///
/// You may also set a facing direction for the agent. If set, the agent will try to approach the destination point
/// with the given heading. <see cref="reachedDestination"/> and <see cref="reachedEndOfPath"/> will only return true once the agent is approximately facing the correct direction.
/// The <see cref="MovementSettings.follower.leadInRadiusWhenApproachingDestination"/> field controls how wide an arc the agent will try to use when approaching the destination.
///
/// The following video shows three agents, one with no facing direction set, and then two agents with varying values of the <see cref="PIDMovement.leadInRadiusWhenApproachingDestination;lead in radius"/>.
/// [Open online documentation to see videos]
///
/// <code>
/// IEnumerator Start () {
/// ai.SetDestination(somePoint, Vector3.right);
/// // Wait until the AI has reached the destination and is rotated to the right in world space
/// Determines if the character's rotation should be coupled to the Transform's rotation.
/// If false then all movement calculations will happen as usual, but the GameObject that this component is attached to will not rotate.
/// Instead, only the <see cref="rotation"/> property and the internal entity's rotation will change.
///
/// This is particularly useful for 2D games where you want the Transform to stay in the same orientation, and instead swap out the displayed
/// sprite to indicate the direction the character is facing.
///
/// You can enable <see cref="PIDMovement.DebugFlags"/>.Rotation in <see cref="debugFlags"/> to draw a gizmos arrow in the scene view to indicate the agent's internal rotation.
/// Some of these settings are exposed on the FollowerEntity directly. For example <see cref="maxSpeed"/>.
///
/// Note: The return value is a struct. If you want to change some settings, you'll need to modify the returned struct and then assign it back to this property.
/// There are a few different phases that you can register callbacks for:
///
/// - BeforeControl: Called before the agent's movement is calculated. At this point, the agent has a valid path, and the next corner that is moving towards has been calculated.
/// - AfterControl: Called after the agent's desired movement is calculated. The agent has stored its desired movement in the <see cref="MovementControl"/> component. Local avoidance has not yet run.
/// - BeforeMovement: Called right before the agent's movement is applied. At this point the agent's final movement (including local avoidance) is stored in the <see cref="ResolvedMovement"/> component, which you may modify.
///
/// Warning: If any agent has a callback registered here, a sync point will be created for all agents when the callback runs.
/// This can make the simulation not able to utilize multiple threads as effectively. If you have a lot of agents, consider using a custom entity component system instead.
/// But as always, profile first to see if this is actually a problem for your game.
///
/// The callbacks may be called multiple times per frame, if the fps is low, or if the time scale is high.
/// It may also be called less than once per frame if the fps is very high.
/// Each callback is provided with a dt parameter, which is the time in seconds since the last simulation step. You should prefer using this instead of Time.deltaTime.
///
/// See: <see cref="canMove"/>
/// See: <see cref="updatePosition"/>
/// See: <see cref="updateRotation"/>
///
/// Note: This API is unstable. It may change in future versions.
thrownewInvalidOperationException("The FollowerEntity component does not support FinalizeMovement. Use an ECS system to override movement instead, or use the movementOverrides property. If you just want to move the agent to a position, set ai.position or call ai.Teleport.");
}
/// <summary>
/// Fills buffer with the remaining path.
///
/// If the agent traverses off-mesh links, the buffer will still contain the whole path. Off-mesh links will be represented by a single line segment.
/// You can use the <see cref="GetRemainingPath(List<Vector3>,List<PathPartWithLinkInfo>,bool)"/> overload to get more detailed information about the different parts of the path.
/// <param name="buffer">The buffer will be cleared and replaced with the path. The first point is the current position of the agent.</param>
/// <param name="stale">May be true if the path is invalid in some way. For example if the agent has no path or if the agent has detected that some nodes in the path have been destroyed.</param>
/// Note: The <see cref="FollowerEntity"/> simplifies its path continuously as it moves along it. This means that the agent may not follow this exact path, if it manages to simplify the path later.
/// Furthermore, the agent will apply a steering behavior on top of this path, to make its movement smoother.
/// </summary>
/// <param name="buffer">The buffer will be cleared and replaced with the path. The first point is the current position of the agent.</param>
/// <param name="partsBuffer">If not null, this list will be filled with information about the different parts of the path. A part is a sequence of nodes or an off-mesh link.</param>
/// <param name="stale">May be true if the path is invalid in some way. For example if the agent has no path or if the agent has detected that some nodes in the path have been destroyed.</param>
thrownewInvalidOperationException("The FollowerEntity component does not support MovementUpdate. Use an ECS system to override movement instead, or use the movementOverrides property");
if(World.DefaultGameObjectInjectionWorld==null||!World.DefaultGameObjectInjectionWorld.EntityManager.Exists(entity))thrownewSystem.InvalidOperationException("Entity does not exist. You can only access this if the component is active and enabled.");
}
/// <summary>
/// True if this component's entity exists.
///
/// This is typically true if the component is active and enabled and the game is running.
/// In case the path has not been calculated, the script will schedule the path to be calculated.
/// This means the AI may not actually start to follow the path until in a few frames when the path has been calculated.
/// The <see cref="pathPending"/> field will, as usual, return true while the path is being calculated.
///
/// In case the path has already been calculated, it will immediately replace the current path the AI is following.
///
/// If you pass null path, then the current path will be cleared and the agent will stop moving.
/// Note than unless you have also disabled <see cref="canSearch"/>, then the agent will soon recalculate its path and start moving again.
///
/// Note: Stopping the agent by passing a null path works. But this will stop the agent instantly, and it will not be able to use local avoidance or know its place on the navmesh.
/// Usually it's better to set <see cref="isStopped"/> to false, which will make the agent slow down smoothly.
///
/// You can disable the automatic path recalculation by setting the <see cref="canSearch"/> field to false.
///
/// Note: This call will be ignored if the agent is currently traversing an off-mesh link.
/// Furthermore, when an agent starts traversing an off-mesh link, the current path request will be canceled (if one is currently in progress).
///
/// <code>
/// IEnumerator Start () {
/// var pointToAvoid = enemy.position;
/// // Make the AI flee from an enemy.
/// // The path will be about 20 world units long (the default cost of moving 1 world unit is 1000).
/// var path = FleePath.Construct(ai.position, pointToAvoid, 1000 * 20);
///
/// // Make the path use the same traversable tags and other pathfinding settings as set in the FollowerEntity inspector
/// path.UseSettings(ai.pathfindingSettings);
///
/// ai.SetPath(path);
///
/// while (!ai.reachedEndOfPath) {
/// yield return null;
/// }
/// }
/// </code>
///
/// See: calling-pathfinding (view in online documentation for working links)
/// See: example_path_types (view in online documentation for working links)
/// </summary>
/// <param name="path">The path to follow.</param>
/// <param name="updateDestinationFromPath">If true, the \reflink{destination} property will be set to the end point of the path. If false, the previous destination value will be kept.
/// If you pass a path which has no well defined destination before it is calculated (e.g. a MultiTargetPath or RandomPath), then the destination will be first be cleared, but once the path has been calculated, it will be set to the end point of the path.</param>
/// Note: This static method is used if you only have an entity reference. If you are working with a GameObject, you can use the instance method instead.
if(!entityManager.Exists(entity))thrownewSystem.InvalidOperationException("Entity does not exist. You can only assign a path if the component is active and enabled.");
/// This method is preferred for long distance teleports. If you only move the agent a very small distance (so that it is reasonable that it can keep its current path),
/// then setting the <see cref="position"/> property is preferred.
/// Setting the <see cref="position"/> property very far away from the agent could cause the agent to fail to move the full distance, as it can get blocked by the navmesh.
///
/// See: Works similarly to Unity's NavmeshAgent.Warp.
UnityEngine.Debug.LogError("The FollowerEntity component requires at least version 1.0 of the 'Entities' package to be installed. You can install it using the Unity package manager.");