#region Copyright & License Information /* * Copyright (c) The OpenRA Developers and Contributors * This file is part of OpenRA, which is free software. It is made * available to you under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. For more * information, see COPYING. */ #endregion using System; using System.Collections.Generic; using System.Linq; using OpenRA.Support; using OpenRA.Traits; namespace OpenRA { public static class WorldUtils { /// /// From the given , select the one nearest the given by /// comparing their . No check is done to see if a path exists. /// public static Actor ClosestToIgnoringPath(this IEnumerable actors, Actor actor) { return actors.ClosestToIgnoringPath(actor.CenterPosition); } /// /// From the given , select the one nearest the given by /// comparing the . No check is done to see if a path exists. /// public static Actor ClosestToIgnoringPath(this IEnumerable actors, WPos position) { return actors.MinByOrDefault(a => (a.CenterPosition - position).LengthSquared); } /// /// From the given that can be projected to , /// select the one nearest the given by /// comparing their . No check is done to see if a path exists. /// public static T ClosestToIgnoringPath(IEnumerable items, Func selector, Actor actor) { return ClosestToIgnoringPath(items, selector, actor.CenterPosition); } /// /// From the given that can be projected to , /// select the one nearest the given by /// comparing the . No check is done to see if a path exists. /// public static T ClosestToIgnoringPath(IEnumerable items, Func selector, WPos position) { return items.MinByOrDefault(x => (selector(x).CenterPosition - position).LengthSquared); } /// /// From the given , select the one nearest the given . /// No check is done to see if a path exists, as an actor is required for that. /// public static WPos ClosestToIgnoringPath(this IEnumerable positions, WPos position) { return positions.MinByOrDefault(p => (p - position).LengthSquared); } public static IEnumerable FindActorsInCircle(this World world, WPos origin, WDist r) { // Target ranges are calculated in 2D, so ignore height differences var vec = new WVec(r, r, WDist.Zero); return world.ActorMap.ActorsInBox(origin - vec, origin + vec).Where( a => (a.CenterPosition - origin).HorizontalLengthSquared <= r.LengthSquared); } public static bool ContainsTemporaryBlocker(this World world, CPos cell, Actor ignoreActor = null) { if (!world.RulesContainTemporaryBlocker) return false; var temporaryBlockers = world.ActorMap.GetActorsAt(cell); foreach (var temporaryBlocker in temporaryBlockers) { if (temporaryBlocker == ignoreActor) continue; var temporaryBlockerTraits = temporaryBlocker.TraitsImplementing(); foreach (var temporaryBlockerTrait in temporaryBlockerTraits) if (temporaryBlockerTrait.IsBlocking(temporaryBlocker, cell)) return true; } return false; } public static void DoTimed(this IEnumerable e, Action a, string text) { // PERF: This is a hot path and must run with minimal added overhead, so we enumerate manually // to allow us to call PerfTickLogger only once per iteration in the normal case. using (var enumerator = e.GetEnumerator()) { var start = PerfTickLogger.GetTimestamp(); while (enumerator.MoveNext()) { a(enumerator.Current); start = PerfTickLogger.LogLongTick(start, text, enumerator.Current); } } } } }