Initial terrain domain work
This commit is contained in:
106
OpenRA.Game/DomainIndex.cs
Normal file
106
OpenRA.Game/DomainIndex.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
using OpenRA.Effects;
|
||||
using OpenRA.FileFormats;
|
||||
using OpenRA.Graphics;
|
||||
using OpenRA.Network;
|
||||
using OpenRA.Orders;
|
||||
using OpenRA.Support;
|
||||
using OpenRA.Traits;
|
||||
using XRandom = OpenRA.Thirdparty.Random;
|
||||
|
||||
namespace OpenRA
|
||||
{
|
||||
public class DomainIndex
|
||||
{
|
||||
Rectangle bounds;
|
||||
int[,] domains;
|
||||
|
||||
public DomainIndex(World world)
|
||||
{
|
||||
bounds = world.Map.Bounds;
|
||||
domains = new int[(bounds.Width + bounds.X), (bounds.Height + bounds.Y)];
|
||||
|
||||
BuildDomains(world);
|
||||
}
|
||||
|
||||
public int GetDomainOf(CPos p)
|
||||
{
|
||||
return domains[p.X, p.Y];
|
||||
}
|
||||
|
||||
public bool IsCrossDomain(CPos p1, CPos p2)
|
||||
{
|
||||
return GetDomainOf(p1) != GetDomainOf(p2);
|
||||
}
|
||||
|
||||
public void SetDomain(CPos p, int domain)
|
||||
{
|
||||
domains[p.X, p.Y] = domain;
|
||||
}
|
||||
|
||||
void BuildDomains(World world)
|
||||
{
|
||||
Map map = world.Map;
|
||||
|
||||
int i = 1;
|
||||
HashSet<CPos> unassigned = new HashSet<CPos>();
|
||||
|
||||
// Fill up our set of yet-unassigned map cells
|
||||
for (int x = map.Bounds.Left; x < bounds.Right; x += 1)
|
||||
{
|
||||
for (int y = bounds.Top; y < bounds.Bottom; y += 1)
|
||||
{
|
||||
unassigned.Add(new CPos(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
while (unassigned.Count != 0)
|
||||
{
|
||||
var start = unassigned.First();
|
||||
unassigned.Remove(start);
|
||||
|
||||
// Wander around looking for water transitions
|
||||
bool inWater = WorldUtils.GetTerrainInfo(world, start).IsWater;
|
||||
Queue<CPos> toProcess = new Queue<CPos>();
|
||||
HashSet<CPos> seen = new HashSet<CPos>();
|
||||
toProcess.Enqueue(start);
|
||||
|
||||
do
|
||||
{
|
||||
CPos p = toProcess.Dequeue();
|
||||
if (seen.Contains(p)) continue;
|
||||
seen.Add(p);
|
||||
|
||||
TerrainTypeInfo cellInfo = WorldUtils.GetTerrainInfo(world, p);
|
||||
bool isWater = cellInfo.IsWater;
|
||||
|
||||
// Check if we're still in one contiguous domain
|
||||
if (inWater == isWater)
|
||||
{
|
||||
SetDomain(p, i);
|
||||
unassigned.Remove(p);
|
||||
|
||||
// Visit our neighbors, if we haven't already
|
||||
foreach (var d in CVec.directions)
|
||||
{
|
||||
CPos nextPos = p + d;
|
||||
if (nextPos.X >= map.Bounds.Left && nextPos.Y >= map.Bounds.Top &&
|
||||
nextPos.X < map.Bounds.Right && nextPos.Y < map.Bounds.Bottom)
|
||||
{
|
||||
if (!seen.Contains(nextPos)) toProcess.Enqueue(nextPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (toProcess.Count != 0);
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Log.Write("debug", "{0}: Found {1} domains", map.Title, i-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@
|
||||
<Compile Include="ActorInitializer.cs" />
|
||||
<Compile Include="ActorMap.cs" />
|
||||
<Compile Include="ActorReference.cs" />
|
||||
<Compile Include="DomainIndex.cs" />
|
||||
<Compile Include="Graphics\QuadRenderer.cs" />
|
||||
<Compile Include="PSubVec.cs" />
|
||||
<Compile Include="PSubPos.cs" />
|
||||
|
||||
@@ -111,6 +111,7 @@ namespace OpenRA
|
||||
}
|
||||
}
|
||||
|
||||
public DomainIndex WorldDomains;
|
||||
internal World(Manifest manifest, Map map, OrderManager orderManager, bool isShellmap)
|
||||
{
|
||||
IsShellmap = isShellmap;
|
||||
@@ -121,6 +122,9 @@ namespace OpenRA
|
||||
TileSet = Rules.TileSets[Map.Tileset];
|
||||
TileSet.LoadTiles();
|
||||
|
||||
// Identify untraversable regions of the map for faster pathfinding, especially with AI
|
||||
WorldDomains = new DomainIndex(this);
|
||||
|
||||
SharedRandom = new XRandom(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
|
||||
|
||||
WorldActor = CreateActor( "World", new TypeDictionary() );
|
||||
|
||||
@@ -44,6 +44,9 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
using (new PerfSample("Pathfinder"))
|
||||
{
|
||||
// If a water-land transition is required, bail early
|
||||
if (world.WorldDomains.IsCrossDomain(from, target)) return new List<CPos>(0);
|
||||
|
||||
var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self);
|
||||
if (cached != null)
|
||||
{
|
||||
@@ -72,6 +75,13 @@ namespace OpenRA.Mods.RA.Move
|
||||
{
|
||||
using (new PerfSample("Pathfinder"))
|
||||
{
|
||||
// As with FindUnitPath, avoid trying to traverse domain transitions.
|
||||
// In this case it's pretty sketchy; path false-negatives are possible.
|
||||
if(world.WorldDomains.IsCrossDomain(src, target.ToCPos()))
|
||||
{
|
||||
return new List<CPos>(0);
|
||||
}
|
||||
|
||||
var mi = self.Info.Traits.Get<MobileInfo>();
|
||||
var targetCell = target.ToCPos();
|
||||
var rangeSquared = range.Range*range.Range;
|
||||
|
||||
Reference in New Issue
Block a user