From 8722a9920c1f6119bf6e769cba270e63097f8e25 Mon Sep 17 00:00:00 2001 From: chai <215380520@qq.com> Date: Thu, 23 May 2024 10:08:29 +0800 Subject: + astar project --- .../Graphs/Grid/Rules/GridGraphRules.cs | 293 +++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/Rules/GridGraphRules.cs (limited to 'Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/Rules/GridGraphRules.cs') diff --git a/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/Rules/GridGraphRules.cs b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/Rules/GridGraphRules.cs new file mode 100644 index 0000000..174b7d2 --- /dev/null +++ b/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Graphs/Grid/Rules/GridGraphRules.cs @@ -0,0 +1,293 @@ +using System.Collections.Generic; + +namespace Pathfinding.Graphs.Grid.Rules { + using Pathfinding.Serialization; + using Pathfinding.Jobs; + using Unity.Jobs; + using Unity.Collections; + using Unity.Mathematics; + + public class CustomGridGraphRuleEditorAttribute : System.Attribute { + public System.Type type; + public string name; + public CustomGridGraphRuleEditorAttribute(System.Type type, string name) { + this.type = type; + this.name = name; + } + } + + /// + /// Container for all rules in a grid graph. + /// + /// + /// // Get the first grid graph in the scene + /// var gridGraph = AstarPath.active.data.gridGraph; + /// + /// gridGraph.rules.AddRule(new Pathfinding.Graphs.Grid.Rules.RuleAnglePenalty { + /// penaltyScale = 10000, + /// curve = AnimationCurve.Linear(0, 0, 90, 1), + /// }); + /// + /// + /// See: + /// See: grid-rules (view in online documentation for working links) + /// + [JsonOptIn] + public class GridGraphRules { + List >[] jobSystemCallbacks; + List >[] mainThreadCallbacks; + + /// List of all rules + [JsonMember] + List rules = new List(); + + long lastHash; + + /// Context for when scanning or updating a graph + public class Context { + /// Graph which is being scanned or updated + public GridGraph graph; + /// Data for all the nodes as NativeArrays + public GridGraphScanData data; + /// + /// Tracks dependencies between jobs to allow parallelism without tediously specifying dependencies manually. + /// Always use when scheduling jobs. + /// + public JobDependencyTracker tracker => data.dependencyTracker; + } + + public void AddRule (GridGraphRule rule) { + rules.Add(rule); + lastHash = -1; + } + + public void RemoveRule (GridGraphRule rule) { + rules.Remove(rule); + lastHash = -1; + } + + public IReadOnlyList GetRules () { + if (rules == null) rules = new List(); + return rules.AsReadOnly(); + } + + long Hash () { + long hash = 196613; + + for (int i = 0; i < rules.Count; i++) { + if (rules[i] != null && rules[i].enabled) hash = hash * 1572869 ^ (long)rules[i].Hash; + } + return hash; + } + + public void RebuildIfNecessary () { + var newHash = Hash(); + + if (newHash == lastHash && jobSystemCallbacks != null && mainThreadCallbacks != null) return; + lastHash = newHash; + Rebuild(); + } + + public void Rebuild () { + rules = rules ?? new List(); + jobSystemCallbacks = jobSystemCallbacks ?? new List >[6]; + for (int i = 0; i < jobSystemCallbacks.Length; i++) { + if (jobSystemCallbacks[i] != null) jobSystemCallbacks[i].Clear(); + } + mainThreadCallbacks = mainThreadCallbacks ?? new List >[6]; + for (int i = 0; i < mainThreadCallbacks.Length; i++) { + if (mainThreadCallbacks[i] != null) mainThreadCallbacks[i].Clear(); + } + for (int i = 0; i < rules.Count; i++) { + if (rules[i].enabled) rules[i].Register(this); + } + } + + public void DisposeUnmanagedData () { + if (rules != null) { + for (int i = 0; i < rules.Count; i++) { + if (rules[i] != null) { + rules[i].DisposeUnmanagedData(); + rules[i].SetDirty(); + } + } + } + } + + static void CallActions (List > actions, Context context) { + if (actions != null) { + try { + for (int i = 0; i < actions.Count; i++) actions[i](context); + } catch (System.Exception e) { + UnityEngine.Debug.LogException(e); + } + } + } + + /// + /// Executes the rules for the given pass. + /// Call handle.Complete on, or wait for, all yielded job handles. + /// + public IEnumerator ExecuteRule (GridGraphRule.Pass rule, Context context) { + if (jobSystemCallbacks == null) Rebuild(); + CallActions(jobSystemCallbacks[(int)rule], context); + + if (mainThreadCallbacks[(int)rule] != null && mainThreadCallbacks[(int)rule].Count > 0) { + if (!context.tracker.forceLinearDependencies) yield return context.tracker.AllWritesDependency; + CallActions(mainThreadCallbacks[(int)rule], context); + } + } + + public void ExecuteRuleMainThread (GridGraphRule.Pass rule, Context context) { + if (jobSystemCallbacks[(int)rule] != null && jobSystemCallbacks[(int)rule].Count > 0) throw new System.Exception("A job system pass has been added for the " + rule + " pass. " + rule + " only supports main thread callbacks."); + if (context.tracker != null) context.tracker.AllWritesDependency.Complete(); + CallActions(mainThreadCallbacks[(int)rule], context); + } + + /// + /// Adds a pass callback that uses the job system. + /// This rule should only schedule jobs using the `Context.tracker` dependency tracker. Data is not safe to access directly in the callback + /// + /// This method should only be called from rules in their Register method. + /// + public void AddJobSystemPass (GridGraphRule.Pass pass, System.Action action) { + var index = (int)pass; + + if (jobSystemCallbacks[index] == null) { + jobSystemCallbacks[index] = new List >(); + } + jobSystemCallbacks[index].Add(action); + } + + /// + /// Adds a pass callback that runs in the main thread. + /// The callback may access and modify any data in the context. + /// You do not need to schedule jobs in order to access the data. + /// + /// Warning: Not all data in the Context is valid for every pass. For example you cannot access node connections in the BeforeConnections pass + /// since they haven't been calculated yet. + /// + /// This is a bit slower than since parallelism and the burst compiler cannot be used. + /// But if you need to use non-thread-safe APIs or data then this is a good choice. + /// + /// This method should only be called from rules in their Register method. + /// + public void AddMainThreadPass (GridGraphRule.Pass pass, System.Action action) { + var index = (int)pass; + + if (mainThreadCallbacks[index] == null) { + mainThreadCallbacks[index] = new List >(); + } + mainThreadCallbacks[index].Add(action); + } + + /// Deprecated: Use AddJobSystemPass or AddMainThreadPass instead + [System.Obsolete("Use AddJobSystemPass or AddMainThreadPass instead")] + public void Add (GridGraphRule.Pass pass, System.Action action) { + AddJobSystemPass(pass, action); + } + } + + /// + /// Custom rule for a grid graph. + /// See: + /// See: grid-rules (view in online documentation for working links) + /// + [JsonDynamicType] + // Compatibility with old versions + [JsonDynamicTypeAlias("Pathfinding.RuleTexture", typeof(RuleTexture))] + [JsonDynamicTypeAlias("Pathfinding.RuleAnglePenalty", typeof(RuleAnglePenalty))] + [JsonDynamicTypeAlias("Pathfinding.RuleElevationPenalty", typeof(RuleElevationPenalty))] + [JsonDynamicTypeAlias("Pathfinding.RulePerLayerModifications", typeof(RulePerLayerModifications))] + public abstract class GridGraphRule { + /// Only enabled rules are executed + [JsonMember] + public bool enabled = true; + int dirty = 1; + + /// + /// Where in the scanning process a rule will be executed. + /// Check the documentation for to see which data fields are valid in which passes. + /// + public enum Pass { + /// + /// Before the collision testing phase but after height testing. + /// This is very early. Most data is not valid by this point. + /// + /// You can use this if you want to modify the node positions and still have it picked up by the collision testing code. + /// + BeforeCollision, + /// + /// Before connections are calculated. + /// At this point height testing and collision testing has been done (if they are enabled). + /// + /// This is the most common pass to use. + /// If you are modifying walkability here then connections and erosion will be calculated properly. + /// + BeforeConnections, + /// + /// After connections are calculated. + /// + /// If you are modifying connections directly you should do that in this pass. + /// + /// Note: If erosion is used then this pass will be executed twice. One time before erosion and one time after erosion + /// when the connections are calculated again. + /// + AfterConnections, + /// + /// After erosion is calculated but before connections have been recalculated. + /// + /// If no erosion is used then this pass will not be executed. + /// + AfterErosion, + /// + /// After everything else. + /// This pass is executed after everything else is done. + /// You should not modify walkability in this pass because then the node connections will not be up to date. + /// + PostProcess, + /// + /// After the graph update has been applied to the graph. + /// + /// This pass can only be added as a main-thread pass. + /// + /// Warning: No native data in the context is valid at this point. It has all been disposed. + /// You cannot modify any data in this pass. + /// + AfterApplied, + } + + /// + /// Hash of the settings for this rule. + /// The method will be called again whenever the hash changes. + /// If the hash does not change it is assumed that the method does not need to be called again. + /// + public virtual int Hash => dirty; + + /// + /// Call if you have changed any setting of the rule. + /// This will ensure that any cached data the rule uses is rebuilt. + /// If you do not do this then any settings changes may not affect the graph when it is rescanned or updated. + /// + /// The purpose of this method call is to cause the property to change. If your custom rule overrides the Hash property to + /// return a hash of some settings, then you do not need to call this method for the changes the hash function already accounts for. + /// + public virtual void SetDirty () { + dirty++; + } + + /// + /// Called when the rule is removed or the graph is destroyed. + /// Use this to e.g. clean up any NativeArrays that the rule uses. + /// + /// Note: The rule should remain valid after this method has been called. + /// However the method is guaranteed to be called before the rule is executed again. + /// + public virtual void DisposeUnmanagedData () { + } + + /// Does preprocessing and adds callbacks to the object + public virtual void Register (GridGraphRules rules) { + } + } +} -- cgit v1.1-26-g67d0