LCOV - code coverage report
Current view: top level - source/simulation2/components - ICmpObstructionManager.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 40 79 50.6 %
Date: 2023-01-19 00:18:29 Functions: 23 43 53.5 %

          Line data    Source code
       1             : /* Copyright (C) 2022 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifndef INCLUDED_ICMPOBSTRUCTIONMANAGER
      19             : #define INCLUDED_ICMPOBSTRUCTIONMANAGER
      20             : 
      21             : #include "simulation2/system/Interface.h"
      22             : 
      23             : #include "maths/FixedVector2D.h"
      24             : #include "simulation2/helpers/Position.h"
      25             : 
      26             : #include <vector>
      27             : 
      28             : class IObstructionTestFilter;
      29             : template<typename T>
      30             : class Grid;
      31             : struct GridUpdateInformation;
      32             : using NavcellData = u16;
      33             : class PathfinderPassability;
      34             : 
      35             : 
      36             : /**
      37             :  * Obstruction manager: provides efficient spatial queries over objects in the world.
      38             :  *
      39             :  * The class deals with two types of shape:
      40             :  * "static" shapes, typically representing buildings, which are rectangles with a given
      41             :  * width and height and angle;
      42             :  * and "unit" shapes, representing units that can move around the world, which have a
      43             :  * radius and no rotation. (Units sometimes act as axis-aligned squares, sometimes
      44             :  * as approximately circles, due to the algorithm used by the short pathfinder.)
      45             :  *
      46             :  * Other classes (particularly ICmpObstruction) register shapes with this interface
      47             :  * and keep them updated.
      48             :  *
      49             :  * The @c Test functions provide exact collision tests.
      50             :  * The edge of a shape counts as 'inside' the shape, for the purpose of collisions.
      51             :  * The functions accept an IObstructionTestFilter argument, which can restrict the
      52             :  * set of shapes that are counted as collisions.
      53             :  *
      54             :  * Units can be marked as either moving or stationary, which simply determines whether
      55             :  * certain filters include or exclude them.
      56             :  *
      57             :  * The @c Rasterize function approximates the current set of shapes onto a 2D grid,
      58             :  * for use with tile-based pathfinding.
      59             :  */
      60          24 : class ICmpObstructionManager : public IComponent
      61             : {
      62             : public:
      63             :     /**
      64             :      * Standard representation for all types of shapes, for use with geometry processing code.
      65             :      */
      66          67 :     struct ObstructionSquare
      67             :     {
      68             :         entity_pos_t x, z; // position of center
      69             :         CFixedVector2D u, v; // 'horizontal' and 'vertical' orthogonal unit vectors, representing orientation
      70             :         entity_pos_t hw, hh; // half width, half height of square
      71             :     };
      72             : 
      73             :     /**
      74             :      * External identifiers for shapes.
      75             :      * (This is a struct rather than a raw u32 for type-safety.)
      76             :      */
      77             :     struct tag_t
      78             :     {
      79           3 :         tag_t() : n(0) {}
      80         130 :         explicit tag_t(u32 n) : n(n) {}
      81          10 :         bool valid() const { return n != 0; }
      82             : 
      83             :         u32 n;
      84             :     };
      85             : 
      86             :     /**
      87             :      * Boolean flags affecting the obstruction behaviour of a shape.
      88             :      */
      89             :     enum EFlags
      90             :     {
      91             :         FLAG_BLOCK_MOVEMENT           = (1 << 0), // prevents units moving through this shape
      92             :         FLAG_BLOCK_FOUNDATION         = (1 << 1), // prevents foundations being placed on this shape
      93             :         FLAG_BLOCK_CONSTRUCTION       = (1 << 2), // prevents buildings being constructed on this shape
      94             :         FLAG_BLOCK_PATHFINDING        = (1 << 3), // prevents the tile pathfinder choosing paths through this shape
      95             :         FLAG_MOVING                   = (1 << 4), // reserved for unitMotion - see usage there.
      96             :         FLAG_DELETE_UPON_CONSTRUCTION = (1 << 5)  // this entity is deleted when construction of a building placed on top of this entity starts
      97             :     };
      98             : 
      99             :     /**
     100             :      * Bitmask of EFlag values.
     101             :      */
     102             :     typedef u8 flags_t;
     103             : 
     104             :     /**
     105             :      * Set the bounds of the world.
     106             :      * Any point outside the bounds is considered obstructed.
     107             :      * @param x0,z0,x1,z1 Coordinates of the corners of the world
     108             :      */
     109             :     virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) = 0;
     110             : 
     111             :     /**
     112             :      * Register a static shape.
     113             :      *
     114             :      * @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
     115             :      * @param x,z coordinates of center, in world space
     116             :      * @param a angle of rotation (clockwise from +Z direction)
     117             :      * @param w width (size along X axis)
     118             :      * @param h height (size along Z axis)
     119             :      * @param flags a set of EFlags values
     120             :      * @param group primary control group of the shape. Must be a valid control group ID.
     121             :      * @param group2 Optional; secondary control group of the shape. Defaults to INVALID_ENTITY.
     122             :      * @return a valid tag for manipulating the shape
     123             :      * @see StaticShape
     124             :      */
     125             :     virtual tag_t AddStaticShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_angle_t a,
     126             :         entity_pos_t w, entity_pos_t h, flags_t flags, entity_id_t group, entity_id_t group2 = INVALID_ENTITY) = 0;
     127             : 
     128             :     /**
     129             :      * Register a unit shape.
     130             :      *
     131             :      * @param ent entity ID associated with this shape (or INVALID_ENTITY if none)
     132             :      * @param x,z coordinates of center, in world space
     133             :      * @param clearance pathfinding clearance of the unit (works as a radius)
     134             :      * @param flags a set of EFlags values
     135             :      * @param group control group (typically the owner entity, or a formation controller entity
     136             :      *  - units ignore collisions with others in the same group)
     137             :      * @return a valid tag for manipulating the shape
     138             :      * @see UnitShape
     139             :      */
     140             :     virtual tag_t AddUnitShape(entity_id_t ent, entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
     141             :         flags_t flags, entity_id_t group) = 0;
     142             : 
     143             :     /**
     144             :      * Adjust the position and angle of an existing shape.
     145             :      * @param tag tag of shape (must be valid)
     146             :      * @param x X coordinate of center, in world space
     147             :      * @param z Z coordinate of center, in world space
     148             :      * @param a angle of rotation (clockwise from +Z direction); ignored for unit shapes
     149             :      */
     150             :     virtual void MoveShape(tag_t tag, entity_pos_t x, entity_pos_t z, entity_angle_t a) = 0;
     151             : 
     152             :     /**
     153             :      * Set whether a unit shape is moving or stationary.
     154             :      * @param tag tag of shape (must be valid and a unit shape)
     155             :      * @param moving whether the unit is currently moving through the world or is stationary
     156             :      */
     157             :     virtual void SetUnitMovingFlag(tag_t tag, bool moving) = 0;
     158             : 
     159             :     /**
     160             :      * Set the control group of a unit shape.
     161             :      * @param tag tag of shape (must be valid and a unit shape)
     162             :      * @param group control group entity ID
     163             :      */
     164             :     virtual void SetUnitControlGroup(tag_t tag, entity_id_t group) = 0;
     165             : 
     166             :     /**
     167             :      * Sets the control group of a static shape.
     168             :      * @param tag Tag of the shape to set the control group for. Must be a valid and static shape tag.
     169             :      * @param group Control group entity ID.
     170             :      */
     171             :     virtual void SetStaticControlGroup(tag_t tag, entity_id_t group, entity_id_t group2) = 0;
     172             : 
     173             :     /**
     174             :      * Remove an existing shape. The tag will be made invalid and must not be used after this.
     175             :      * @param tag tag of shape (must be valid)
     176             :      */
     177             :     virtual void RemoveShape(tag_t tag) = 0;
     178             : 
     179             :     /**
     180             :      * Returns the distance from the obstruction to the point (px, pz), or -1 if the entity is out of the world.
     181             :      */
     182             :     virtual fixed DistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const = 0;
     183             : 
     184             :     /**
     185             :      * Calculate the largest straight line distance between the entity and the point.
     186             :      */
     187             :     virtual fixed MaxDistanceToPoint(entity_id_t ent, entity_pos_t px, entity_pos_t pz) const = 0;
     188             : 
     189             :     /**
     190             :      * Calculate the shortest distance between the entity and the target.
     191             :      */
     192             :     virtual fixed DistanceToTarget(entity_id_t ent, entity_id_t target) const = 0;
     193             : 
     194             :     /**
     195             :      * Calculate the largest straight line distance between the entity and the target.
     196             :      */
     197             :     virtual fixed MaxDistanceToTarget(entity_id_t ent, entity_id_t target) const = 0;
     198             : 
     199             :     /**
     200             :      * Calculate the shortest straight line distance between the source and the target
     201             :      */
     202             :     virtual fixed DistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const = 0;
     203             : 
     204             :     /**
     205             :      * Calculate the largest straight line distance between the source and the target
     206             :      */
     207             :     virtual fixed MaxDistanceBetweenShapes(const ObstructionSquare& source, const ObstructionSquare& target) const = 0;
     208             : 
     209             :     /**
     210             :      * Check if the given entity is in range of the other point given those parameters.
     211             :      * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
     212             :      */
     213             :     virtual bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0;
     214             : 
     215             :     /**
     216             :      * Check if the given entity is in range of the target given those parameters.
     217             :      * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
     218             :      */
     219             :     virtual bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0;
     220             : 
     221             :     /**
     222             :      * Check if the given entity is in parabolic range of the target given those parameters.
     223             :      * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
     224             :      */
     225             :     virtual bool IsInTargetParabolicRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin, bool opposite) const = 0;
     226             : 
     227             :     /**
     228             :      * Check if the given point is in range of the other point given those parameters.
     229             :      * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
     230             :      */
     231             :     virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const = 0;
     232             : 
     233             :     /**
     234             :      * Check if the given shape is in range of the target shape given those parameters.
     235             :      * @param maxRange - Can be a nonnegative decimal, ALWAYS_IN_RANGE or NEVER_IN_RANGE.
     236             :      */
     237             :     virtual bool AreShapesInRange(const ObstructionSquare& source, const ObstructionSquare& target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0;
     238             : 
     239             :     /**
     240             :      * Collision test a flat-ended thick line against the current set of shapes.
     241             :      * The line caps extend by @p r beyond the end points.
     242             :      * Only intersections going from outside to inside a shape are counted.
     243             :      * @param filter filter to restrict the shapes that are counted
     244             :      * @param x0 X coordinate of line's first point
     245             :      * @param z0 Z coordinate of line's first point
     246             :      * @param x1 X coordinate of line's second point
     247             :      * @param z1 Z coordinate of line's second point
     248             :      * @param r radius (half width) of line
     249             :      * @param relaxClearanceForUnits whether unit-unit collisions should be more permissive.
     250             :      * @return true if there is a collision
     251             :      */
     252             :     virtual bool TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits) const = 0;
     253             : 
     254             :     /**
     255             :      * Collision test a static square shape against the current set of shapes.
     256             :      * @param filter filter to restrict the shapes that are being tested against
     257             :      * @param x X coordinate of center
     258             :      * @param z Z coordinate of center
     259             :      * @param a angle of rotation (clockwise from +Z direction)
     260             :      * @param w width (size along X axis)
     261             :      * @param h height (size along Z axis)
     262             :      * @param out if non-NULL, all colliding shapes' entities will be added to this list
     263             :      * @return true if there is a collision
     264             :      */
     265             :     virtual bool TestStaticShape(const IObstructionTestFilter& filter,
     266             :         entity_pos_t x, entity_pos_t z, entity_pos_t a, entity_pos_t w, entity_pos_t h,
     267             :         std::vector<entity_id_t>* out) const = 0;
     268             : 
     269             :     /**
     270             :      * Collision test a unit shape against the current set of registered shapes, and optionally writes a list of the colliding
     271             :      * shapes' entities to an output list.
     272             :      *
     273             :      * @param filter filter to restrict the shapes that are being tested against
     274             :      * @param x X coordinate of shape's center
     275             :      * @param z Z coordinate of shape's center
     276             :      * @param clearance clearance of the shape's unit
     277             :      * @param out if non-NULL, all colliding shapes' entities will be added to this list
     278             :      *
     279             :      * @return true if there is a collision
     280             :      */
     281             :     virtual bool TestUnitShape(const IObstructionTestFilter& filter,
     282             :         entity_pos_t x, entity_pos_t z, entity_pos_t clearance,
     283             :         std::vector<entity_id_t>* out) const = 0;
     284             : 
     285             :     /**
     286             :      * Convert the current set of shapes onto a navcell grid, for all passability classes contained in @p passClasses.
     287             :      * If @p fullUpdate is false, the function will only go through dirty shapes.
     288             :      * Shapes are expanded by the @p passClasses clearances, by ORing their masks onto the @p grid.
     289             :      */
     290             :     virtual void Rasterize(Grid<NavcellData>& grid, const std::vector<PathfinderPassability>& passClasses, bool fullUpdate) = 0;
     291             : 
     292             :     /**
     293             :      * Gets dirtiness information and resets it afterwards. Then it's the role of CCmpPathfinder
     294             :      * to pass the information to other components if needed. (AIs, etc.)
     295             :      * The return value is false if an update is unnecessary.
     296             :      */
     297             :     virtual void UpdateInformations(GridUpdateInformation& informations) = 0;
     298             : 
     299             :     /**
     300             :      * Find all the obstructions that are inside (or partially inside) the given range.
     301             :      * @param filter filter to restrict the shapes that are counted
     302             :      * @param x0 X coordinate of left edge of range
     303             :      * @param z0 Z coordinate of bottom edge of range
     304             :      * @param x1 X coordinate of right edge of range
     305             :      * @param z1 Z coordinate of top edge of range
     306             :      * @param squares output list of obstructions
     307             :      */
     308             :     virtual void GetObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const = 0;
     309             :     virtual void GetStaticObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const = 0;
     310             :     virtual void GetUnitObstructionsInRange(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, std::vector<ObstructionSquare>& squares) const = 0;
     311             :     virtual void GetStaticObstructionsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter) const = 0;
     312             : 
     313             :     /**
     314             :      * Returns the entity IDs of all unit shapes that intersect the given
     315             :      * obstruction square, filtering out using the given filter.
     316             :      * @param square the Obstruction squre we want to compare with.
     317             :      * @param out output list of obstructions
     318             :      * @param filter filter for the obstructing units
     319             :      * @param strict whether to be strict in the check or more permissive (ie rasterize more or less). Default false.
     320             :      */
     321             :     virtual void GetUnitsOnObstruction(const ObstructionSquare& square, std::vector<entity_id_t>& out, const IObstructionTestFilter& filter, bool strict = false) const = 0;
     322             : 
     323             :     /**
     324             :      * Get the obstruction square representing the given shape.
     325             :      * @param tag tag of shape (must be valid)
     326             :      */
     327             :     virtual ObstructionSquare GetObstruction(tag_t tag) const = 0;
     328             : 
     329             :     virtual ObstructionSquare GetUnitShapeObstruction(entity_pos_t x, entity_pos_t z, entity_pos_t clearance) const = 0;
     330             : 
     331             :     virtual ObstructionSquare GetStaticShapeObstruction(entity_pos_t x, entity_pos_t z, entity_angle_t a, entity_pos_t w, entity_pos_t h) const = 0;
     332             : 
     333             :     /**
     334             :      * Set the passability to be restricted to a circular map.
     335             :      */
     336             :     virtual void SetPassabilityCircular(bool enabled) = 0;
     337             : 
     338             :     virtual bool GetPassabilityCircular() const = 0;
     339             : 
     340             :     /**
     341             :      * Toggle the rendering of debug info.
     342             :      */
     343             :     virtual void SetDebugOverlay(bool enabled) = 0;
     344             : 
     345         125 :     DECLARE_INTERFACE_TYPE(ObstructionManager)
     346             : };
     347             : 
     348             : /**
     349             :  * Interface for ICmpObstructionManager @c Test functions to filter out unwanted shapes.
     350             :  */
     351          13 : class IObstructionTestFilter
     352             : {
     353             : public:
     354             :     typedef ICmpObstructionManager::tag_t tag_t;
     355             :     typedef ICmpObstructionManager::flags_t flags_t;
     356             : 
     357          17 :     virtual ~IObstructionTestFilter() {}
     358             : 
     359             :     /**
     360             :      * Return true if the shape with the specified parameters should be tested for collisions.
     361             :      * This is called for all shapes that would collide, and also for some that wouldn't.
     362             :      *
     363             :      * @param tag tag of shape being tested
     364             :      * @param flags set of EFlags for the shape
     365             :      * @param group the control group of the shape (typically the shape's unit, or the unit's formation controller, or 0)
     366             :      * @param group2 an optional secondary control group of the shape, or INVALID_ENTITY if none specified. Currently
     367             :      *               exists only for static shapes.
     368             :      */
     369             :     virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const = 0;
     370             : };
     371             : 
     372             : /**
     373             :  * Obstruction test filter that will test against all shapes.
     374             :  */
     375           3 : class NullObstructionFilter : public IObstructionTestFilter
     376             : {
     377             : public:
     378          30 :     virtual bool TestShape(tag_t UNUSED(tag), flags_t UNUSED(flags), entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
     379             :     {
     380          30 :         return true;
     381             :     }
     382             : };
     383             : 
     384             : /**
     385             :  * Obstruction test filter that will test only against stationary (i.e. non-moving) shapes.
     386             :  */
     387           1 : class StationaryOnlyObstructionFilter : public IObstructionTestFilter
     388             : {
     389             : public:
     390           6 :     virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
     391             :     {
     392           6 :         return !(flags & ICmpObstructionManager::FLAG_MOVING);
     393             :     }
     394             : };
     395             : 
     396             : /**
     397             :  * Obstruction test filter that reject shapes in a given control group,
     398             :  * and rejects shapes that don't block unit movement, and optionally rejects moving shapes.
     399             :  */
     400           0 : class ControlGroupMovementObstructionFilter : public IObstructionTestFilter
     401             : {
     402             :     bool m_AvoidMoving;
     403             :     entity_id_t m_Group;
     404             : 
     405             : public:
     406           0 :     ControlGroupMovementObstructionFilter(bool avoidMoving, entity_id_t group) :
     407           0 :         m_AvoidMoving(avoidMoving), m_Group(group)
     408           0 :     {}
     409             : 
     410           0 :     virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
     411             :     {
     412           0 :         if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
     413           0 :             return false;
     414             : 
     415           0 :         if (!(flags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT))
     416           0 :             return false;
     417             : 
     418           0 :         if ((flags & ICmpObstructionManager::FLAG_MOVING) && !m_AvoidMoving)
     419           0 :             return false;
     420             : 
     421           0 :         return true;
     422             :     }
     423             : };
     424             : 
     425             : /**
     426             :  * Obstruction test filter that will test only against shapes that:
     427             :  *     - are part of neither one of the specified control groups
     428             :  *     - AND, depending on the value of the 'exclude' argument:
     429             :  *       - have at least one of the specified flags set.
     430             :  *       - OR have none of the specified flags set.
     431             :  *
     432             :  * The first (primary) control group to reject shapes from must be specified and valid. The secondary
     433             :  * control group to reject entities from may be set to INVALID_ENTITY to not use it.
     434             :  *
     435             :  * This filter is useful to e.g. allow foundations within the same control group to be placed and
     436             :  * constructed arbitrarily close together (e.g. for wall pieces that need to link up tightly).
     437             :  */
     438           6 : class SkipControlGroupsRequireFlagObstructionFilter : public IObstructionTestFilter
     439             : {
     440             :     bool m_Exclude;
     441             :     entity_id_t m_Group;
     442             :     entity_id_t m_Group2;
     443             :     flags_t m_Mask;
     444             : 
     445             : public:
     446           0 :     SkipControlGroupsRequireFlagObstructionFilter(bool exclude, entity_id_t group1, entity_id_t group2, flags_t mask) :
     447           0 :         m_Exclude(exclude), m_Group(group1), m_Group2(group2), m_Mask(mask)
     448             :     {
     449           0 :         Init();
     450           0 :     }
     451             : 
     452           6 :     SkipControlGroupsRequireFlagObstructionFilter(entity_id_t group1, entity_id_t group2, flags_t mask) :
     453           6 :         m_Exclude(false), m_Group(group1), m_Group2(group2), m_Mask(mask)
     454             :     {
     455           6 :         Init();
     456           6 :     }
     457             : 
     458          40 :     virtual bool TestShape(tag_t UNUSED(tag), flags_t flags, entity_id_t group, entity_id_t group2) const
     459             :     {
     460             :         // Don't test shapes that share one or more of our control groups.
     461          46 :         if (group == m_Group || group == m_Group2 || (group2 != INVALID_ENTITY &&
     462           8 :                 (group2 == m_Group || group2 == m_Group2)))
     463          22 :             return false;
     464             : 
     465             :         // If m_Exclude is true, don't test against shapes that have any of the
     466             :         // obstruction flags specified in m_Mask.
     467          18 :         if (m_Exclude)
     468           0 :             return (flags & m_Mask) == 0;
     469             : 
     470             :         // Otherwise, only include shapes that match at least one flag in m_Mask.
     471          18 :         return (flags & m_Mask) != 0;
     472             :     }
     473             : private:
     474           6 :     void Init()
     475             :     {
     476             :         // the primary control group to filter out must be valid
     477           6 :         ENSURE(m_Group != INVALID_ENTITY);
     478             : 
     479             :         // for simplicity, if m_Group2 is INVALID_ENTITY (i.e. not used), then set it equal to m_Group
     480             :         // so that we have fewer special cases to consider in TestShape().
     481           6 :         if (m_Group2 == INVALID_ENTITY)
     482           3 :             m_Group2 = m_Group;
     483           6 :     }
     484             : };
     485             : 
     486             : /**
     487             :  * Obstruction test filter that will test only against shapes that:
     488             :  *     - are part of both of the specified control groups
     489             :  *     - AND have at least one of the specified flags set.
     490             :  *
     491             :  * The first (primary) control group to include shapes from must be specified and valid.
     492             :  *
     493             :  * This filter is useful for preventing entities with identical control groups
     494             :  * from colliding e.g. building a new wall segment on top of an existing wall)
     495             :  *
     496             :  * @todo This filter needs test cases.
     497             :  */
     498           0 : class SkipTagRequireControlGroupsAndFlagObstructionFilter : public IObstructionTestFilter
     499             : {
     500             :     tag_t m_Tag;
     501             :     entity_id_t m_Group;
     502             :     entity_id_t m_Group2;
     503             :     flags_t m_Mask;
     504             : 
     505             : public:
     506           0 :     SkipTagRequireControlGroupsAndFlagObstructionFilter(tag_t tag, entity_id_t group1, entity_id_t group2, flags_t mask) :
     507           0 :         m_Tag(tag), m_Group(group1), m_Group2(group2), m_Mask(mask)
     508             :     {
     509           0 :         ENSURE(m_Group != INVALID_ENTITY);
     510           0 :     }
     511             : 
     512           0 :     virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
     513             :     {
     514             :         // To be included in testing, a shape must not have the specified tag, and must
     515             :         // match at least one of the flags in m_Mask, as well as both control groups.
     516           0 :         return (tag.n != m_Tag.n && (flags & m_Mask) != 0 && ((group == m_Group
     517           0 :             && group2 == m_Group2) || (group2 == m_Group && group == m_Group2)));
     518             :     }
     519             : };
     520             : 
     521             : /**
     522             :  * Obstruction test filter that will test only against shapes that do not have the specified tag set.
     523             :  */
     524           4 : class SkipTagObstructionFilter : public IObstructionTestFilter
     525             : {
     526             :     tag_t m_Tag;
     527             : public:
     528           4 :     SkipTagObstructionFilter(tag_t tag) : m_Tag(tag)
     529             :     {
     530           4 :     }
     531             : 
     532           6 :     virtual bool TestShape(tag_t tag, flags_t UNUSED(flags), entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
     533             :     {
     534           6 :         return tag.n != m_Tag.n;
     535             :     }
     536             : };
     537             : 
     538             : /**
     539             :  * Similar to ControlGroupMovementObstructionFilter, but also ignoring a specific tag. See D3482 for why this exists.
     540             :  */
     541           0 : class SkipTagAndControlGroupObstructionFilter : public IObstructionTestFilter
     542             : {
     543             :     entity_id_t m_Group;
     544             :     tag_t m_Tag;
     545             :     bool m_AvoidMoving;
     546             : 
     547             : public:
     548           0 :     SkipTagAndControlGroupObstructionFilter(tag_t tag, bool avoidMoving,  entity_id_t group) :
     549           0 :     m_Tag(tag), m_Group(group), m_AvoidMoving(avoidMoving)
     550           0 :     {}
     551             : 
     552           0 :     virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t group, entity_id_t group2) const
     553             :     {
     554           0 :         if (tag.n == m_Tag.n)
     555           0 :             return false;
     556             : 
     557           0 :         if (group == m_Group || (group2 != INVALID_ENTITY && group2 == m_Group))
     558           0 :             return false;
     559             : 
     560           0 :         if ((flags & ICmpObstructionManager::FLAG_MOVING) && !m_AvoidMoving)
     561           0 :             return false;
     562             : 
     563           0 :         if (!(flags & ICmpObstructionManager::FLAG_BLOCK_MOVEMENT))
     564           0 :             return false;
     565             : 
     566           0 :         return true;
     567             :     }
     568             : };
     569             : 
     570             : 
     571             : /**
     572             :  * Obstruction test filter that will test only against shapes that:
     573             :  *    - do not have the specified tag
     574             :  *    - AND have at least one of the specified flags set.
     575             :  */
     576           3 : class SkipTagRequireFlagsObstructionFilter : public IObstructionTestFilter
     577             : {
     578             :     tag_t m_Tag;
     579             :     flags_t m_Mask;
     580             : public:
     581           3 :     SkipTagRequireFlagsObstructionFilter(tag_t tag, flags_t mask) : m_Tag(tag), m_Mask(mask)
     582             :     {
     583           3 :     }
     584             : 
     585          18 :     virtual bool TestShape(tag_t tag, flags_t flags, entity_id_t UNUSED(group), entity_id_t UNUSED(group2)) const
     586             :     {
     587          18 :         return (tag.n != m_Tag.n && (flags & m_Mask) != 0);
     588             :     }
     589             : };
     590             : 
     591             : #endif // INCLUDED_ICMPOBSTRUCTIONMANAGER

Generated by: LCOV version 1.13