1 #region Copyright & License Information
2 /*
3  * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4  * This file is part of OpenRA, which is free software. It is made
5  * available to you under the terms of the GNU General Public License
6  * as published by the Free Software Foundation, either version 3 of
7  * the License, or (at your option) any later version. For more
8  * information, see COPYING.
9  */
10 #endregion
11 
12 using System;
13 using System.Collections.Generic;
14 using System.Diagnostics;
15 using System.Linq;
16 using OpenRA.Support;
17 using OpenRA.Traits;
18 
19 namespace OpenRA
20 {
21 	public static class WorldUtils
22 	{
ClosestTo(this IEnumerable<Actor> actors, Actor a)23 		public static Actor ClosestTo(this IEnumerable<Actor> actors, Actor a)
24 		{
25 			return actors.ClosestTo(a.CenterPosition);
26 		}
27 
ClosestTo(this IEnumerable<Actor> actors, WPos pos)28 		public static Actor ClosestTo(this IEnumerable<Actor> actors, WPos pos)
29 		{
30 			return actors.MinByOrDefault(a => (a.CenterPosition - pos).LengthSquared);
31 		}
32 
PositionClosestTo(this IEnumerable<WPos> positions, WPos pos)33 		public static WPos PositionClosestTo(this IEnumerable<WPos> positions, WPos pos)
34 		{
35 			return positions.MinByOrDefault(p => (p - pos).LengthSquared);
36 		}
37 
FindActorsInCircle(this World world, WPos origin, WDist r)38 		public static IEnumerable<Actor> FindActorsInCircle(this World world, WPos origin, WDist r)
39 		{
40 			// Target ranges are calculated in 2D, so ignore height differences
41 			var vec = new WVec(r, r, WDist.Zero);
42 			return world.ActorMap.ActorsInBox(origin - vec, origin + vec).Where(
43 				a => (a.CenterPosition - origin).HorizontalLengthSquared <= r.LengthSquared);
44 		}
45 
ContainsTemporaryBlocker(this World world, CPos cell, Actor ignoreActor = null)46 		public static bool ContainsTemporaryBlocker(this World world, CPos cell, Actor ignoreActor = null)
47 		{
48 			if (!world.RulesContainTemporaryBlocker)
49 				return false;
50 
51 			var temporaryBlockers = world.ActorMap.GetActorsAt(cell);
52 			foreach (var temporaryBlocker in temporaryBlockers)
53 			{
54 				if (temporaryBlocker == ignoreActor)
55 					continue;
56 
57 				var temporaryBlockerTraits = temporaryBlocker.TraitsImplementing<ITemporaryBlocker>();
58 				foreach (var temporaryBlockerTrait in temporaryBlockerTraits)
59 					if (temporaryBlockerTrait.IsBlocking(temporaryBlocker, cell))
60 						return true;
61 			}
62 
63 			return false;
64 		}
65 
DoTimed(this IEnumerable<T> e, Action<T> a, string text)66 		public static void DoTimed<T>(this IEnumerable<T> e, Action<T> a, string text)
67 		{
68 			// PERF: This is a hot path and must run with minimal added overhead.
69 			// Calling Stopwatch.GetTimestamp is a bit expensive, so we enumerate manually to allow us to call it only
70 			// once per iteration in the normal case.
71 			// See also: RunActivity
72 			var longTickThresholdInStopwatchTicks = PerfTimer.LongTickThresholdInStopwatchTicks;
73 			using (var enumerator = e.GetEnumerator())
74 			{
75 				var start = Stopwatch.GetTimestamp();
76 				while (enumerator.MoveNext())
77 				{
78 					a(enumerator.Current);
79 					var current = Stopwatch.GetTimestamp();
80 					if (current - start > longTickThresholdInStopwatchTicks)
81 					{
82 						PerfTimer.LogLongTick(start, current, text, enumerator.Current);
83 						start = Stopwatch.GetTimestamp();
84 					}
85 					else
86 						start = current;
87 				}
88 			}
89 		}
90 
AreMutualAllies(Player a, Player b)91 		public static bool AreMutualAllies(Player a, Player b)
92 		{
93 			return a.Stances[b] == Stance.Ally &&
94 				b.Stances[a] == Stance.Ally;
95 		}
96 	}
97 }
98