const int MaxPathAge = 50; /* x 40ms ticks */ public List <CPos> FindUnitPath(CPos from, CPos target, Actor self) { using (new PerfSample("Pathfinder")) { var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self); if (cached != null) { Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.FrameNumber - cached.tick); if (world.FrameNumber - cached.tick > MaxPathAge) { CachedPaths.Remove(cached); } return(new List <CPos>(cached.result)); } var mi = self.Info.Traits.Get <MobileInfo>(); var pb = FindBidiPath( PathSearch.FromPoint(world, mi, self, target, from, true), PathSearch.FromPoint(world, mi, self, from, target, true).InReverse() ); CheckSanePath2(pb, from, target); CachedPaths.RemoveAll(p => world.FrameNumber - p.tick > MaxPathAge); CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = world.FrameNumber }); return(new List <CPos>(pb)); } }
// Scriptable move order // Ignores lane bias and nearby units public Move(CPos destination) { this.getPath = (self, mobile) => self.World.WorldActor.Trait <PathFinder>().FindPath( PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false) .WithoutLaneBias()); this.destination = destination; this.nearEnough = WRange.Zero; }
public Move(CPos destination, Actor ignoreBuilding) { this.getPath = (self, mobile) => self.World.WorldActor.Trait <PathFinder>().FindPath( PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false) .WithIgnoredBuilding(ignoreBuilding)); this.destination = destination; this.nearEnough = WRange.Zero; this.ignoreBuilding = ignoreBuilding; }
// Scriptable move order // Ignores lane bias and nearby units public Move(Actor self, CPos destination) { mobile = self.Trait <Mobile>(); moveDisablers = self.TraitsImplementing <IDisableMove>(); getPath = () => self.World.WorldActor.Trait <PathFinder>().FindPath( PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, destination, false) .WithoutLaneBias()); this.destination = destination; this.nearEnough = WRange.Zero; }
public List <CPos> FindUnitPathToRange(CPos src, CPos target, int range, Actor self) { using (new PerfSample("Pathfinder")) { var mi = self.Info.Traits.Get <MobileInfo>(); var tilesInRange = world.FindTilesInCircle(target, range) .Where(t => mi.CanEnterCell(self.World, self, t, null, true, true)); var path = FindBidiPath( PathSearch.FromPoints(world, mi, self, tilesInRange, src, true), PathSearch.FromPoint(world, mi, self, src, target, true).InReverse() ); return(path); } }
const int MaxPathAge = 50; /* x 40ms ticks */ public List <CPos> FindUnitPath(CPos from, CPos target, Actor self) { using (new PerfSample("Pathfinder")) { var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self); if (cached != null) { Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.WorldTick - cached.tick); if (world.WorldTick - cached.tick > MaxPathAge) { CachedPaths.Remove(cached); } return(new List <CPos>(cached.result)); } var mi = self.Info.Traits.Get <MobileInfo>(); // If a water-land transition is required, bail early var domainIndex = self.World.WorldActor.TraitOrDefault <DomainIndex>(); if (domainIndex != null) { var passable = mi.GetMovementClass(world.TileSet); if (!domainIndex.IsPassable(from, target, (uint)passable)) { return(emptyPath); } } var pb = FindBidiPath( PathSearch.FromPoint(world, mi, self, target, from, true), PathSearch.FromPoint(world, mi, self, from, target, true).Reverse() ); CheckSanePath2(pb, from, target); CachedPaths.RemoveAll(p => world.WorldTick - p.tick > MaxPathAge); CachedPaths.Add(new CachedPath { from = from, to = target, actor = self, result = pb, tick = world.WorldTick }); return(new List <CPos>(pb)); } }
public List <CPos> FindUnitPathToRange(CPos src, SubCell srcSub, WPos target, WRange range, Actor self) { using (new PerfSample("Pathfinder")) { var mi = self.Info.Traits.Get <MobileInfo>(); var targetCell = self.World.Map.CellContaining(target); var rangeSquared = range.Range * range.Range; // Correct for SubCell offset target -= MobileInfo.SubCellOffsets[srcSub]; // Select only the tiles that are within range from the requested SubCell // This assumes that the SubCell does not change during the path traversal var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Range / 1024 + 1) .Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= rangeSquared && mi.CanEnterCell(self.World, self, t, null, true, true)); // See if there is any cell within range that does not involve a cross-domain request // Really, we only need to check the circle perimeter, but it's not clear that would be a performance win var domainIndex = self.World.WorldActor.TraitOrDefault <DomainIndex>(); if (domainIndex != null) { var passable = mi.GetMovementClass(world.TileSet); tilesInRange = new List <CPos>(tilesInRange.Where(t => domainIndex.IsPassable(src, t, (uint)passable))); if (!tilesInRange.Any()) { return(emptyPath); } } var path = FindBidiPath( PathSearch.FromPoints(world, mi, self, tilesInRange, src, true), PathSearch.FromPoint(world, mi, self, src, targetCell, true).Reverse() ); return(path); } }