Remove obsolete LocomotorInfo caching.

This commit is contained in:
Paul Chote
2020-10-10 21:01:30 +01:00
committed by Matthias Mailänder
parent 49e7a33db0
commit 5a7dc385a3
10 changed files with 35 additions and 94 deletions

View File

@@ -24,7 +24,6 @@ namespace OpenRA.Mods.Common.Activities
readonly Harvester harv;
readonly HarvesterInfo harvInfo;
readonly Mobile mobile;
readonly LocomotorInfo locomotorInfo;
readonly ResourceClaimLayer claimLayer;
readonly IPathFinder pathFinder;
readonly DomainIndex domainIndex;
@@ -43,7 +42,6 @@ namespace OpenRA.Mods.Common.Activities
harv = self.Trait<Harvester>();
harvInfo = self.Info.TraitInfo<HarvesterInfo>();
mobile = self.Trait<Mobile>();
locomotorInfo = mobile.Info.LocomotorInfo;
claimLayer = self.World.WorldActor.Trait<ResourceClaimLayer>();
pathFinder = self.World.WorldActor.Trait<IPathFinder>();
domainIndex = self.World.WorldActor.Trait<DomainIndex>();
@@ -195,7 +193,7 @@ namespace OpenRA.Mods.Common.Activities
// Find any harvestable resources:
List<CPos> path;
using (var search = PathSearch.Search(self.World, mobile.Locomotor, self, BlockedByActor.Stationary, loc =>
domainIndex.IsPassable(self.Location, loc, locomotorInfo) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
domainIndex.IsPassable(self.Location, loc, mobile.Locomotor) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
.WithCustomCost(loc =>
{
if ((loc - searchFromLoc.Value).LengthSquared > searchRadiusSquared)

View File

@@ -133,7 +133,7 @@ namespace OpenRA.Mods.Common.Activities
searchCells.Clear();
searchCellsTick = self.World.WorldTick;
foreach (var cell in CandidateMovementCells(self))
if (domainIndex.IsPassable(loc, cell, Mobile.Info.LocomotorInfo) && Mobile.CanEnterCell(cell))
if (domainIndex.IsPassable(loc, cell, Mobile.Locomotor) && Mobile.CanEnterCell(cell))
searchCells.Add(cell);
}

View File

@@ -87,7 +87,6 @@ namespace OpenRA.Mods.Common.Pathfinder
readonly BlockedByActor checkConditions;
readonly Locomotor locomotor;
readonly LocomotorInfo.WorldMovementInfo worldMovementInfo;
readonly CellInfoLayerPool.PooledCellInfoLayer pooledLayer;
readonly bool checkTerrainHeight;
CellLayer<CellInfo> groundInfo;
@@ -108,7 +107,6 @@ namespace OpenRA.Mods.Common.Pathfinder
customLayerInfo[cml.Index] = (cml, pooledLayer.GetLayer());
World = world;
worldMovementInfo = locomotorInfo.GetWorldMovementInfo(world);
Actor = actor;
LaneBias = 1;
checkConditions = check;

View File

@@ -145,7 +145,7 @@ namespace OpenRA.Mods.Common.Traits
Target FindNextResource(Actor actor, HarvesterTraitWrapper harv)
{
Func<CPos, bool> isValidResource = cell =>
domainIndex.IsPassable(actor.Location, cell, harv.Locomotor.Info) &&
domainIndex.IsPassable(actor.Location, cell, harv.Locomotor) &&
harv.Harvester.CanHarvestCell(actor, cell) &&
claimLayer.CanClaimCell(actor, cell);

View File

@@ -29,11 +29,11 @@ namespace OpenRA.Mods.Common.Traits.BotModules.Squads
// (Way better than finding a nearest target which is likely to be on Ground)
// You might be tempted to move these lookups into Activate() but that causes null reference exception.
var domainIndex = first.World.WorldActor.Trait<DomainIndex>();
var locomotorInfo = first.Info.TraitInfo<MobileInfo>().LocomotorInfo;
var locomotor = first.Trait<Mobile>().Locomotor;
var navalProductions = owner.World.ActorsHavingTrait<Building>().Where(a
=> owner.SquadManager.Info.NavalProductionTypes.Contains(a.Info.Name)
&& domainIndex.IsPassable(first.Location, a.Location, locomotorInfo)
&& domainIndex.IsPassable(first.Location, a.Location, locomotor)
&& a.AppearsHostileTo(first));
if (navalProductions.Any())

View File

@@ -725,16 +725,7 @@ namespace OpenRA.Mods.Common.Traits
public int MovementSpeedForCell(Actor self, CPos cell)
{
var index = cell.Layer == 0 ? self.World.Map.GetTerrainIndex(cell) :
self.World.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell);
if (index == byte.MaxValue)
return 0;
var terrainSpeed = Info.LocomotorInfo.TilesetTerrainInfo[self.World.Map.Rules.TileSet][index].Speed;
if (terrainSpeed == 0)
return 0;
var terrainSpeed = Locomotor.MovementSpeedForCell(cell);
var modifiers = speedModifiers.Value.Append(terrainSpeed);
return Util.ApplyPercentageModifiers(Info.Speed, modifiers);

View File

@@ -10,6 +10,7 @@
#endregion
using System.Collections.Generic;
using System.Linq;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -62,9 +63,9 @@ namespace OpenRA.Mods.Common.Traits
if (mobileInfo != null)
{
var locomotorInfo = mobileInfo.LocomotorInfo;
var locomotor = self.World.WorldActor.TraitsImplementing<Locomotor>().First(l => l.Info.Name == mobileInfo.Locomotor);
location = self.World.Map.ChooseClosestMatchingEdgeCell(self.Location,
c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotorInfo));
c => mobileInfo.CanEnterCell(self.World, null, c) && domainIndex.IsPassable(c, destinations[0], locomotor));
}
}

View File

@@ -31,24 +31,23 @@ namespace OpenRA.Mods.Common.Traits
domainIndexes = new Dictionary<uint, MovementClassDomainIndex>();
tileSet = world.Map.Rules.TileSet;
var locomotors = world.WorldActor.TraitsImplementing<Locomotor>().Where(l => !string.IsNullOrEmpty(l.Info.Name));
var movementClasses = locomotors.Select(t => (uint)t.Info.GetMovementClass(tileSet)).Distinct();
var movementClasses = locomotors.Select(t => t.MovementClass).Distinct();
foreach (var mc in movementClasses)
domainIndexes[mc] = new MovementClassDomainIndex(world, mc);
}
public bool IsPassable(CPos p1, CPos p2, LocomotorInfo li)
public bool IsPassable(CPos p1, CPos p2, Locomotor locomotor)
{
// HACK: Work around units in other movement layers from being blocked
// when the point in the main layer is not pathable
if (p1.Layer != 0 || p2.Layer != 0)
return true;
if (li.DisableDomainPassabilityCheck)
if (locomotor.Info.DisableDomainPassabilityCheck)
return true;
var movementClass = li.GetMovementClass(tileSet);
return domainIndexes[movementClass].IsPassable(p1, p2);
return domainIndexes[locomotor.MovementClass].IsPassable(p1, p2);
}
/// <summary>Regenerate the domain index for a group of cells.</summary>

View File

@@ -99,21 +99,6 @@ namespace OpenRA.Mods.Common.Traits
return ret;
}
TerrainInfo[] LoadTilesetSpeeds(TileSet tileSet)
{
var info = new TerrainInfo[tileSet.TerrainInfo.Length];
for (var i = 0; i < info.Length; i++)
info[i] = TerrainInfo.Impassable;
foreach (var kvp in TerrainSpeeds)
{
if (tileSet.TryGetTerrainIndex(kvp.Key, out var index))
info[index] = kvp.Value;
}
return info;
}
public class TerrainInfo
{
public static readonly TerrainInfo Impassable = new TerrainInfo();
@@ -134,53 +119,6 @@ namespace OpenRA.Mods.Common.Traits
}
}
public struct WorldMovementInfo
{
internal readonly World World;
internal readonly TerrainInfo[] TerrainInfos;
internal WorldMovementInfo(World world, LocomotorInfo info)
{
// PERF: This struct allows us to cache the terrain info for the tileset used by the world.
// This allows us to speed up some performance-sensitive pathfinding calculations.
World = world;
TerrainInfos = info.TilesetTerrainInfo[world.Map.Rules.TileSet];
}
}
public readonly Cache<TileSet, TerrainInfo[]> TilesetTerrainInfo;
public readonly Cache<TileSet, int> TilesetMovementClass;
public LocomotorInfo()
{
TilesetTerrainInfo = new Cache<TileSet, TerrainInfo[]>(LoadTilesetSpeeds);
TilesetMovementClass = new Cache<TileSet, int>(CalculateTilesetMovementClass);
}
public int CalculateTilesetMovementClass(TileSet tileset)
{
// collect our ability to cross *all* terraintypes, in a bitvector
return TilesetTerrainInfo[tileset].Select(ti => ti.Cost < short.MaxValue).ToBits();
}
public uint GetMovementClass(TileSet tileset)
{
return (uint)TilesetMovementClass[tileset];
}
public int TileSetMovementHash(TileSet tileSet)
{
var terrainInfos = TilesetTerrainInfo[tileSet];
// Compute and return the hash using aggregate
return terrainInfos.Aggregate(terrainInfos.Length,
(current, terrainInfo) => unchecked(current * 31 + terrainInfo.Cost));
}
public WorldMovementInfo GetWorldMovementInfo(World world)
{
return new WorldMovementInfo(world, this);
}
public virtual bool DisableDomainPassabilityCheck { get { return false; } }
public override object Create(ActorInitializer init) { return new Locomotor(init.Self, this); }
@@ -203,14 +141,15 @@ namespace OpenRA.Mods.Common.Traits
}
public readonly LocomotorInfo Info;
public readonly uint MovementClass;
CellLayer<short> cellsCost;
CellLayer<CellCache> blockingCache;
readonly Dictionary<byte, CellLayer<short>> customLayerCellsCost = new Dictionary<byte, CellLayer<short>>();
readonly Dictionary<byte, CellLayer<CellCache>> customLayerBlockingCache = new Dictionary<byte, CellLayer<CellCache>>();
LocomotorInfo.TerrainInfo[] terrainInfos;
World world;
readonly LocomotorInfo.TerrainInfo[] terrainInfos;
readonly World world;
readonly HashSet<CPos> dirtyCells = new HashSet<CPos>();
IActorMap actorMap;
@@ -220,6 +159,15 @@ namespace OpenRA.Mods.Common.Traits
{
Info = info;
sharesCell = info.SharesCell;
world = self.World;
var tileSet = world.Map.Rules.TileSet;
terrainInfos = new LocomotorInfo.TerrainInfo[tileSet.TerrainInfo.Length];
for (var i = 0; i < terrainInfos.Length; i++)
if (!info.TerrainSpeeds.TryGetValue(tileSet.TerrainInfo[i].Type, out terrainInfos[i]))
terrainInfos[i] = LocomotorInfo.TerrainInfo.Impassable;
MovementClass = (uint)terrainInfos.Select(ti => ti.Cost < short.MaxValue).ToBits();
}
public short MovementCostForCell(CPos cell)
@@ -230,6 +178,14 @@ namespace OpenRA.Mods.Common.Traits
return cell.Layer == 0 ? cellsCost[cell] : customLayerCellsCost[cell.Layer][cell];
}
public int MovementSpeedForCell(CPos cell)
{
var index = cell.Layer == 0 ? world.Map.GetTerrainIndex(cell) :
world.GetCustomMovementLayers()[cell.Layer].GetTerrainIndex(cell);
return terrainInfos[index].Speed;
}
public short MovementCostToEnterCell(Actor actor, CPos destNode, BlockedByActor check, Actor ignoreActor)
{
if (!world.Map.Contains(destNode))
@@ -404,11 +360,9 @@ namespace OpenRA.Mods.Common.Traits
public void WorldLoaded(World w, WorldRenderer wr)
{
world = w;
var map = w.Map;
actorMap = w.ActorMap;
actorMap.CellUpdated += CellUpdated;
terrainInfos = Info.TilesetTerrainInfo[map.Rules.TileSet];
blockingCache = new CellLayer<CellCache>(map);
cellsCost = new CellLayer<short>(map);

View File

@@ -72,7 +72,7 @@ namespace OpenRA.Mods.Common.Traits
}
// If a water-land transition is required, bail early
if (domainIndex != null && !domainIndex.IsPassable(source, target, locomotor.Info))
if (domainIndex != null && !domainIndex.IsPassable(source, target, locomotor))
return EmptyPath;
var distance = source - target;
@@ -119,7 +119,7 @@ namespace OpenRA.Mods.Common.Traits
// Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
if (domainIndex != null)
{
tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, locomotor.Info)));
tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, locomotor)));
if (!tilesInRange.Any())
return EmptyPath;
}