LCOV - code coverage report
Current view: top level - source/simulation2/components - ICmpRangeManager.h (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 4 4 100.0 %
Date: 2023-01-19 00:18:29 Functions: 3 4 75.0 %

          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_ICMPRANGEMANAGER
      19             : #define INCLUDED_ICMPRANGEMANAGER
      20             : 
      21             : #include "maths/FixedVector3D.h"
      22             : #include "maths/FixedVector2D.h"
      23             : 
      24             : #include "simulation2/system/Interface.h"
      25             : #include "simulation2/helpers/Position.h"
      26             : #include "simulation2/helpers/Player.h"
      27             : 
      28             : #include <vector>
      29             : 
      30             : class FastSpatialSubdivision;
      31             : 
      32             : /**
      33             :  * Value assigned to a range we will always be in (caused by out of world or "too high" in parabolic ranges).
      34             :  * TODO Add this for minRanges too.
      35             :  */
      36          25 : const entity_pos_t ALWAYS_IN_RANGE = entity_pos_t::FromInt(-1);
      37             : 
      38             : /**
      39             :  * Value assigned to a range we will never be in (caused by out of world or "too high" in parabolic ranges).
      40             :  * TODO Add this to range queries too.
      41             :  */
      42          25 : const entity_pos_t NEVER_IN_RANGE = entity_pos_t::FromInt(-2);
      43             : 
      44             : /**
      45             :  * Since GetVisibility queries are run by the range manager
      46             :  * other code using these must include ICmpRangeManager.h anyways,
      47             :  * so define this enum here (Ideally, it'd be in its own header file,
      48             :  * but adding header file does incur its own compilation time increase).
      49             :  */
      50             : enum class LosVisibility : u8
      51             : {
      52             :     HIDDEN = 0,
      53             :     FOGGED = 1,
      54             :     VISIBLE = 2
      55             : };
      56             : 
      57             : /**
      58             :  * The same principle applies to CLosQuerier, but to avoid recompiling TUs (a fortiori headers)
      59             :  * dependent on RangeManager but not CLosQuerier when CLosQuerier changes,
      60             :  * we define it in another file. Code using LOS will then explicitly include the LOS header
      61             :  * which makes sense anyways.
      62             :  */
      63             : class CLosQuerier;
      64             : 
      65             : /**
      66             :  * Provides efficient range-based queries of the game world,
      67             :  * and also LOS-based effects (fog of war).
      68             :  *
      69             :  * (These are somewhat distinct concepts but they share a lot of the implementation,
      70             :  * so for efficiency they're combined into this class.)
      71             :  *
      72             :  * Possible use cases:
      73             :  * - combat units need to detect targetable enemies entering LOS, so they can choose
      74             :  *   to auto-attack.
      75             :  * - auras let a unit have some effect on all units (or those of the same player, or of enemies)
      76             :  *   within a certain range.
      77             :  * - capturable animals need to detect when a player-owned unit is nearby and no units of other
      78             :  *   players are in range.
      79             :  * - scenario triggers may want to detect when units enter a given area.
      80             :  * - units gathering from a resource that is exhausted need to find a new resource of the
      81             :  *   same type, near the old one and reachable.
      82             :  * - projectile weapons with splash damage need to find all units within some distance
      83             :  *   of the target point.
      84             :  * - ...
      85             :  *
      86             :  * In most cases the users are event-based and want notifications when something
      87             :  * has entered or left the range, and the query can be set up once and rarely changed.
      88             :  * These queries have to be fast. Entities are approximated as points or circles
      89             :  * (queries can be set up to ignore sizes because LOS currently ignores it, and mismatches are problematic).
      90             :  *
      91             :  * Current design:
      92             :  *
      93             :  * This class handles just the most common parts of range queries:
      94             :  * distance, target interface, and player ownership.
      95             :  * The caller can then apply any more complex filtering that it needs.
      96             :  *
      97             :  * There are two types of query:
      98             :  * Passive queries are performed by ExecuteQuery and immediately return the matching entities.
      99             :  * Active queries are set up by CreateActiveQuery, and then a CMessageRangeUpdate message will be
     100             :  * sent to the entity once per turn if anybody has entered or left the range since the last RangeUpdate.
     101             :  * Queries can be disabled, in which case no message will be sent.
     102             :  */
     103          12 : class ICmpRangeManager : public IComponent
     104             : {
     105             : public:
     106             :     /**
     107             :      * External identifiers for active queries.
     108             :      */
     109             :     typedef u32 tag_t;
     110             : 
     111             :     /**
     112             :      * Access the spatial subdivision kept by the range manager.
     113             :      * @return pointer to spatial subdivision structure.
     114             :      */
     115             :     virtual FastSpatialSubdivision* GetSubdivision() = 0;
     116             : 
     117             :     /**
     118             :      * Set the bounds of the world.
     119             :      * Entities should not be outside the bounds (else efficiency will suffer).
     120             :      * @param x0,z0,x1,z1 Coordinates of the corners of the world
     121             :      */
     122             :     virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1) = 0;
     123             : 
     124             :     /**
     125             :      * Execute a passive query.
     126             :      * @param source the entity around which the range will be computed.
     127             :      * @param minRange non-negative minimum distance in metres (inclusive).
     128             :      * @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
     129             :      * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
     130             :      * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
     131             :      * @param accountForSize if true, compensate for source/target entity sizes.
     132             :      * @return list of entities matching the query, ordered by increasing distance from the source entity.
     133             :      */
     134             :     virtual std::vector<entity_id_t> ExecuteQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange,
     135             :         const std::vector<int>& owners, int requiredInterface, bool accountForSize) = 0;
     136             : 
     137             :     /**
     138             :      * Execute a passive query.
     139             :      * @param pos the position around which the range will be computed.
     140             :      * @param minRange non-negative minimum distance in metres (inclusive).
     141             :      * @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
     142             :      * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
     143             :      * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
     144             :      * @param accountForSize if true, compensate for source/target entity sizes.
     145             :      * @return list of entities matching the query, ordered by increasing distance from the source entity.
     146             :      */
     147             :     virtual std::vector<entity_id_t> ExecuteQueryAroundPos(const CFixedVector2D& pos, entity_pos_t minRange, entity_pos_t maxRange,
     148             :         const std::vector<int>& owners, int requiredInterface, bool accountForSize) = 0;
     149             : 
     150             :     /**
     151             :      * Construct an active query. The query will be disabled by default.
     152             :      * @param source the entity around which the range will be computed.
     153             :      * @param minRange non-negative minimum distance in metres (inclusive).
     154             :      * @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
     155             :      * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
     156             :      * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
     157             :      * @param flags if a entity in range has one of the flags set it will show up.
     158             :      * @param accountForSize if true, compensate for source/target entity sizes.
     159             :      * @return unique non-zero identifier of query.
     160             :      */
     161             :     virtual tag_t CreateActiveQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange,
     162             :         const std::vector<int>& owners, int requiredInterface, u8 flags, bool accountForSize) = 0;
     163             : 
     164             :     /**
     165             :      * Construct an active query of a paraboloic form around the unit.
     166             :      * The query will be disabled by default.
     167             :      * @param source the entity around which the range will be computed.
     168             :      * @param minRange non-negative minimum horizontal distance in metres (inclusive). MinRange doesn't do parabolic checks.
     169             :      * @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation;
     170             :      *      or -1.0 to ignore distance.
     171             :      *      For units on a different height positions, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them
     172             :      * @param yOrigin extra bonus so the source can be placed higher and shoot further
     173             :      * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
     174             :      * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
     175             :      * @param flags if a entity in range has one of the flags set it will show up.
     176             :      * NB: this one has no accountForSize parameter (assumed true), because we currently can only have 7 arguments for JS functions.
     177             :      * @return unique non-zero identifier of query.
     178             :      */
     179             :     virtual tag_t CreateActiveParabolicQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t yOrigin,
     180             :         const std::vector<int>& owners, int requiredInterface, u8 flags) = 0;
     181             : 
     182             : 
     183             :     /**
     184             :      * Get the effective range in a parablic range query.
     185             :      * @param source The entity id at the origin of the query.
     186             :      * @param target A target entity id.
     187             :      * @param range The distance to compare terrain height with.
     188             :      * @param yOrigin Height the source gains over the target by default.
     189             :      * @return a fixed number representing the effective range correcting parabolicly for the height difference. Returns -1 when the target is too high compared to the source to be in range.
     190             :      */
     191             :     virtual entity_pos_t GetEffectiveParabolicRange(entity_id_t source, entity_id_t target, entity_pos_t range, entity_pos_t yOrigin) const = 0;
     192             : 
     193             :     /**
     194             :      * Get the average elevation over 8 points on distance range around the entity
     195             :      * @param id the entity id to look around
     196             :      * @param range the distance to compare terrain height with
     197             :      * @return a fixed number representing the average difference. It's positive when the entity is on average higher than the terrain surrounding it.
     198             :      */
     199             :     virtual entity_pos_t GetElevationAdaptedRange(const CFixedVector3D& pos, const CFixedVector3D& rot, entity_pos_t range, entity_pos_t yOrigin, entity_pos_t angle) const = 0;
     200             : 
     201             :     /**
     202             :      * Destroy a query and clean up resources. This must be called when an entity no longer needs its
     203             :      * query (e.g. when the entity is destroyed).
     204             :      * @param tag identifier of query.
     205             :      */
     206             :     virtual void DestroyActiveQuery(tag_t tag) = 0;
     207             : 
     208             :     /**
     209             :      * Re-enable the processing of a query.
     210             :      * @param tag identifier of query.
     211             :      */
     212             :     virtual void EnableActiveQuery(tag_t tag) = 0;
     213             : 
     214             :     /**
     215             :      * Disable the processing of a query (no RangeUpdate messages will be sent).
     216             :      * @param tag identifier of query.
     217             :      */
     218             :     virtual void DisableActiveQuery(tag_t tag) = 0;
     219             : 
     220             :     /**
     221             :      * Check if the processing of a query is enabled.
     222             :      * @param tag identifier of a query.
     223             :      */
     224             :     virtual bool IsActiveQueryEnabled(tag_t tag) const = 0;
     225             : 
     226             :     /**
     227             :      * Immediately execute a query, and re-enable it if disabled.
     228             :      * The next RangeUpdate message will say who has entered/left since this call,
     229             :      * so you won't miss any notifications.
     230             :      * @param tag identifier of query.
     231             :      * @return list of entities matching the query, ordered by increasing distance from the source entity.
     232             :      */
     233             :     virtual std::vector<entity_id_t> ResetActiveQuery(tag_t tag) = 0;
     234             : 
     235             :     /**
     236             :      * Returns a list of all entities for a specific player.
     237             :      * (This is on this interface because it shares a lot of the implementation.
     238             :      * Maybe it should be extended to be more like ExecuteQuery without
     239             :      * the range parameter.)
     240             :      */
     241             :     virtual std::vector<entity_id_t> GetEntitiesByPlayer(player_id_t player) const = 0;
     242             : 
     243             :     /**
     244             :      * Returns a list of all entities of all players except gaia.
     245             :      */
     246             :     virtual std::vector<entity_id_t> GetNonGaiaEntities() const = 0;
     247             : 
     248             :     /**
     249             :      * Returns a list of all entities owned by a player or gaia.
     250             :      */
     251             :     virtual std::vector<entity_id_t> GetGaiaAndNonGaiaEntities() const = 0;
     252             : 
     253             :     /**
     254             :      * Toggle the rendering of debug info.
     255             :      */
     256             :     virtual void SetDebugOverlay(bool enabled) = 0;
     257             : 
     258             :     /**
     259             :      * Returns the mask for the specified identifier.
     260             :      */
     261             :     virtual u8 GetEntityFlagMask(const std::string& identifier) const = 0;
     262             : 
     263             :     /**
     264             :      * Set the flag specified by the identifier to the supplied value for the entity
     265             :      * @param ent the entity whose flags will be modified.
     266             :      * @param identifier the flag to be modified.
     267             :      * @param value to which the flag will be set.
     268             :      */
     269             :     virtual void SetEntityFlag(entity_id_t ent, const std::string& identifier, bool value) = 0;
     270             : 
     271             : 
     272             :     //////////////////////////////////////////////////////////////////
     273             :     ////              LOS interface below this line               ////
     274             :     //////////////////////////////////////////////////////////////////
     275             : 
     276             :     /**
     277             :      * Returns a CLosQuerier for checking whether vertex positions are visible to the given player
     278             :      *  (or other players it shares LOS with).
     279             :      */
     280             :     virtual CLosQuerier GetLosQuerier(player_id_t player) const = 0;
     281             : 
     282             :     /**
     283             :      * Toggle the scripted Visibility component activation for entity ent.
     284             :      */
     285             :     virtual void ActivateScriptedVisibility(entity_id_t ent, bool status) = 0;
     286             : 
     287             :     /**
     288             :      * Returns the visibility status of the given entity, with respect to the given player.
     289             :      * Returns LosVisibility::HIDDEN if the entity doesn't exist or is not in the world.
     290             :      * This respects the GetLosRevealAll flag.
     291             :      */
     292             :     virtual LosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player) const = 0;
     293             :     virtual LosVisibility GetLosVisibility(entity_id_t ent, player_id_t player) const = 0;
     294             : 
     295             :     /**
     296             :      * Returns the visibility status of the given position, with respect to the given player.
     297             :      * This respects the GetLosRevealAll flag.
     298             :      */
     299             :     virtual LosVisibility GetLosVisibilityPosition(entity_pos_t x, entity_pos_t z, player_id_t player) const = 0;
     300             : 
     301             :     /**
     302             :      * Request the update of the visibility cache of ent at next turn.
     303             :      * Typically used for fogging.
     304             :      */
     305             :     virtual void RequestVisibilityUpdate(entity_id_t ent) = 0;
     306             : 
     307             : 
     308             :     /**
     309             :      * GetLosVisibility wrapped for script calls.
     310             :      * Returns "hidden", "fogged" or "visible".
     311             :      */
     312             :     std::string GetLosVisibility_wrapper(entity_id_t ent, player_id_t player) const;
     313             : 
     314             :     /**
     315             :      * GetLosVisibilityPosition wrapped for script calls.
     316             :      * Returns "hidden", "fogged" or "visible".
     317             :      */
     318             :     std::string GetLosVisibilityPosition_wrapper(entity_pos_t x, entity_pos_t z, player_id_t player) const;
     319             : 
     320             :     /**
     321             :      * Explore the map (but leave it in the FoW) for player p
     322             :      */
     323             :     virtual void ExploreMap(player_id_t p) = 0;
     324             : 
     325             :     /**
     326             :      * Explore the tiles inside each player's territory.
     327             :      * This is done only at the beginning of the game.
     328             :      */
     329             :     virtual void ExploreTerritories() = 0;
     330             : 
     331             :     /**
     332             :      * Reveal the shore for specified player p.
     333             :      * This works like for entities: if RevealShore is called multiple times with enabled, it
     334             :      * will be necessary to call it the same number of times with !enabled to make the shore
     335             :      * fall back into the FoW.
     336             :      */
     337             :     virtual void RevealShore(player_id_t p, bool enable) = 0;
     338             : 
     339             :     /**
     340             :      * Set whether the whole map should be made visible to the given player.
     341             :      * If player is -1, the map will be made visible to all players.
     342             :      */
     343             :     virtual void SetLosRevealAll(player_id_t player, bool enabled) = 0;
     344             : 
     345             :     /**
     346             :      * Returns whether the whole map has been made visible to the given player.
     347             :      */
     348             :     virtual bool GetLosRevealAll(player_id_t player) const = 0;
     349             : 
     350             :     /**
     351             :      * Set the LOS to be restricted to a circular map.
     352             :      */
     353             :     virtual void SetLosCircular(bool enabled) = 0;
     354             : 
     355             :     /**
     356             :      * Returns whether the LOS is restricted to a circular map.
     357             :      */
     358             :     virtual bool GetLosCircular() const = 0;
     359             : 
     360             :     /**
     361             :      * Sets shared LOS data for player to the given list of players.
     362             :      */
     363             :     virtual void SetSharedLos(player_id_t player, const std::vector<player_id_t>& players) = 0;
     364             : 
     365             :     /**
     366             :      * Returns shared LOS mask for player.
     367             :      */
     368             :     virtual u32 GetSharedLosMask(player_id_t player) const = 0;
     369             : 
     370             :     /**
     371             :      * Get percent map explored statistics for specified player.
     372             :      */
     373             :     virtual u8 GetPercentMapExplored(player_id_t player) const = 0;
     374             : 
     375             :     /**
     376             :      * Get percent map explored statistics for specified set of players.
     377             :      * Note: this function computes statistics from scratch and should not be called too often.
     378             :      */
     379             :     virtual u8 GetUnionPercentMapExplored(const std::vector<player_id_t>& players) const = 0;
     380             : 
     381             :     /**
     382             :      * @return The number of LOS vertices.
     383             :      */
     384             :     virtual size_t GetVerticesPerSide() const = 0;
     385             : 
     386             :     /**
     387             :      * Perform some internal consistency checks for testing/debugging.
     388             :      */
     389             :     virtual void Verify() = 0;
     390             : 
     391         123 :     DECLARE_INTERFACE_TYPE(RangeManager)
     392             : };
     393             : 
     394             : #endif // INCLUDED_ICMPRANGEMANAGER

Generated by: LCOV version 1.13