Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ICmpRangeManager.h
Go to the documentation of this file.
1 /* Copyright (C) 2013 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 
26 
27 #include "graphics/Terrain.h" // for TERRAIN_TILE_SIZE
28 
29 /**
30  * Provides efficient range-based queries of the game world,
31  * and also LOS-based effects (fog of war).
32  *
33  * (These are somewhat distinct concepts but they share a lot of the implementation,
34  * so for efficiency they're combined into this class.)
35  *
36  * Possible use cases:
37  * - combat units need to detect targetable enemies entering LOS, so they can choose
38  * to auto-attack.
39  * - auras let a unit have some effect on all units (or those of the same player, or of enemies)
40  * within a certain range.
41  * - capturable animals need to detect when a player-owned unit is nearby and no units of other
42  * players are in range.
43  * - scenario triggers may want to detect when units enter a given area.
44  * - units gathering from a resource that is exhausted need to find a new resource of the
45  * same type, near the old one and reachable.
46  * - projectile weapons with splash damage need to find all units within some distance
47  * of the target point.
48  * - ...
49  *
50  * In most cases the users are event-based and want notifications when something
51  * has entered or left the range, and the query can be set up once and rarely changed.
52  * These queries have to be fast. It's fine to approximate an entity as a point.
53  *
54  * Current design:
55  *
56  * This class handles just the most common parts of range queries:
57  * distance, target interface, and player ownership.
58  * The caller can then apply any more complex filtering that it needs.
59  *
60  * There are two types of query:
61  * Passive queries are performed by ExecuteQuery and immediately return the matching entities.
62  * Active queries are set up by CreateActiveQuery, and then a CMessageRangeUpdate message will be
63  * sent to the entity once per turn if anybody has entered or left the range since the last RangeUpdate.
64  * Queries can be disabled, in which case no message will be sent.
65  */
67 {
68 public:
69  /**
70  * External identifiers for active queries.
71  */
72  typedef u32 tag_t;
73 
74  /**
75  * Set the bounds of the world.
76  * Entities should not be outside the bounds (else efficiency will suffer).
77  * @param x0,z0,x1,z1 Coordinates of the corners of the world
78  * @param vertices Number of terrain vertices per side
79  */
80  virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, ssize_t vertices) = 0;
81 
82  /**
83  * Execute a passive query.
84  * @param source the entity around which the range will be computed.
85  * @param minRange non-negative minimum distance in metres (inclusive).
86  * @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
87  * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
88  * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
89  * @return list of entities matching the query, ordered by increasing distance from the source entity.
90  */
91  virtual std::vector<entity_id_t> ExecuteQuery(entity_id_t source,
92  entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface) = 0;
93 
94  /**
95  * Construct an active query. The query will be disabled by default.
96  * @param source the entity around which the range will be computed.
97  * @param minRange non-negative minimum distance in metres (inclusive).
98  * @param maxRange non-negative maximum distance in metres (inclusive); or -1.0 to ignore distance.
99  * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
100  * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
101  * @param flags if a entity in range has one of the flags set it will show up.
102  * @return unique non-zero identifier of query.
103  */
104  virtual tag_t CreateActiveQuery(entity_id_t source,
105  entity_pos_t minRange, entity_pos_t maxRange, std::vector<int> owners, int requiredInterface, u8 flags) = 0;
106 
107  /**
108  * Construct an active query of a paraboloic form around the unit.
109  * The query will be disabled by default.
110  * @param source the entity around which the range will be computed.
111  * @param minRange non-negative minimum horizontal distance in metres (inclusive). MinRange doesn't do parabolic checks.
112  * @param maxRange non-negative maximum distance in metres (inclusive) for units on the same elevation;
113  * or -1.0 to ignore distance.
114  * For units on a different elevation, a physical correct paraboloid with height=maxRange/2 above the unit is used to query them
115  * @param elevationBonus extra bonus so the source can be placed higher and shoot further
116  * @param owners list of player IDs that matching entities may have; -1 matches entities with no owner.
117  * @param requiredInterface if non-zero, an interface ID that matching entities must implement.
118  * @param flags if a entity in range has one of the flags set it will show up.
119  * @return unique non-zero identifier of query.
120  */
122  entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus, std::vector<int> owners, int requiredInterface, u8 flags) = 0;
123 
124 
125  /**
126  * Get the average elevation over 8 points on distance range around the entity
127  * @param id the entity id to look around
128  * @param range the distance to compare terrain height with
129  * @return a fixed number representing the average difference. It's positive when the entity is on average higher than the terrain surrounding it.
130  */
132 
133  /**
134  * Destroy a query and clean up resources. This must be called when an entity no longer needs its
135  * query (e.g. when the entity is destroyed).
136  * @param tag identifier of query.
137  */
138  virtual void DestroyActiveQuery(tag_t tag) = 0;
139 
140  /**
141  * Re-enable the processing of a query.
142  * @param tag identifier of query.
143  */
144  virtual void EnableActiveQuery(tag_t tag) = 0;
145 
146  /**
147  * Disable the processing of a query (no RangeUpdate messages will be sent).
148  * @param tag identifier of query.
149  */
150  virtual void DisableActiveQuery(tag_t tag) = 0;
151 
152  /**
153  * Immediately execute a query, and re-enable it if disabled.
154  * The next RangeUpdate message will say who has entered/left since this call,
155  * so you won't miss any notifications.
156  * @param tag identifier of query.
157  * @return list of entities matching the query, ordered by increasing distance from the source entity.
158  */
159  virtual std::vector<entity_id_t> ResetActiveQuery(tag_t tag) = 0;
160 
161  /**
162  * Returns list of all entities for specific player.
163  * (This is on this interface because it shares a lot of the implementation.
164  * Maybe it should be extended to be more like ExecuteQuery without
165  * the range parameter.)
166  */
167  virtual std::vector<entity_id_t> GetEntitiesByPlayer(player_id_t player) = 0;
168 
169  /**
170  * Toggle the rendering of debug info.
171  */
172  virtual void SetDebugOverlay(bool enabled) = 0;
173 
174  /**
175  * Returns the mask for the specified identifier.
176  */
177  virtual u8 GetEntityFlagMask(std::string identifier) = 0;
178 
179  /**
180  * Set the flag specified by the identifier to the supplied value for the entity
181  * @param ent the entity whose flags will be modified.
182  * @param identifier the flag to be modified.
183  * @param value to which the flag will be set.
184  */
185  virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value) = 0;
186 
187  // LOS interface:
188 
190  {
195  };
196 
198  {
202  };
203 
204  /**
205  * Object providing efficient abstracted access to the LOS state.
206  * This depends on some implementation details of CCmpRangeManager.
207  *
208  * This *ignores* the GetLosRevealAll flag - callers should check that explicitly.
209  */
211  {
212  private:
213  friend class CCmpRangeManager;
214  friend class TestLOSTexture;
215 
216  CLosQuerier(u32 playerMask, const std::vector<u32>& data, ssize_t verticesPerSide) :
217  m_Data(&data[0]), m_PlayerMask(playerMask), m_VerticesPerSide(verticesPerSide)
218  {
219  }
220 
221  const CLosQuerier& operator=(const CLosQuerier&); // not implemented
222 
223  public:
224  /**
225  * Returns whether the given vertex is visible (i.e. is within a unit's LOS).
226  */
227  inline bool IsVisible(ssize_t i, ssize_t j)
228  {
229  if (!(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide))
230  return false;
231 
232  // Check high bit of each bit-pair
233  if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0xAAAAAAAAu)
234  return true;
235  else
236  return false;
237  }
238 
239  /**
240  * Returns whether the given vertex is explored (i.e. was (or still is) within a unit's LOS).
241  */
242  inline bool IsExplored(ssize_t i, ssize_t j)
243  {
244  if (!(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide))
245  return false;
246 
247  // Check low bit of each bit-pair
248  if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0x55555555u)
249  return true;
250  else
251  return false;
252  }
253 
254  /**
255  * Returns whether the given vertex is visible (i.e. is within a unit's LOS).
256  * i and j must be in the range [0, verticesPerSide), else behaviour is undefined.
257  */
259  {
260 #ifndef NDEBUG
261  ENSURE(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
262 #endif
263  // Check high bit of each bit-pair
264  if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0xAAAAAAAAu)
265  return true;
266  else
267  return false;
268  }
269 
270  /**
271  * Returns whether the given vertex is explored (i.e. was (or still is) within a unit's LOS).
272  * i and j must be in the range [0, verticesPerSide), else behaviour is undefined.
273  */
275  {
276 #ifndef NDEBUG
277  ENSURE(i >= 0 && j >= 0 && i < m_VerticesPerSide && j < m_VerticesPerSide);
278 #endif
279  // Check low bit of each bit-pair
280  if ((m_Data[j*m_VerticesPerSide + i] & m_PlayerMask) & 0x55555555u)
281  return true;
282  else
283  return false;
284  }
285 
286  private:
288  const u32* m_Data;
290  };
291 
292  /**
293  * Returns a CLosQuerier for checking whether vertex positions are visible to the given player
294  * (or other players it shares LOS with).
295  */
296  virtual CLosQuerier GetLosQuerier(player_id_t player) = 0;
297 
298  /**
299  * Returns the visibility status of the given entity, with respect to the given player.
300  * Returns VIS_HIDDEN if the entity doesn't exist or is not in the world.
301  * This respects the GetLosRevealAll flag.
302  * If forceRetainInFog is true, the visibility acts as if CCmpVision's RetainInFog flag were set.
303  * TODO: This is a hack to allow preview entities in FoW to return fogged instead of hidden,
304  * see http://trac.wildfiregames.com/ticket/958
305  */
306  virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog = false) = 0;
307  virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player, bool forceRetainInFog = false) = 0;
308 
309  /**
310  * GetLosVisibility wrapped for script calls.
311  * Returns "hidden", "fogged" or "visible".
312  */
313  std::string GetLosVisibility_wrapper(entity_id_t ent, player_id_t player, bool forceRetainInFog);
314 
315  /**
316  * Set whether the whole map should be made visible to the given player.
317  * If player is -1, the map will be made visible to all players.
318  */
319  virtual void SetLosRevealAll(player_id_t player, bool enabled) = 0;
320 
321  /**
322  * Returns whether the whole map has been made visible to the given player.
323  */
324  virtual bool GetLosRevealAll(player_id_t player) = 0;
325 
326  /**
327  * Set the LOS to be restricted to a circular map.
328  */
329  virtual void SetLosCircular(bool enabled) = 0;
330 
331  /**
332  * Returns whether the LOS is restricted to a circular map.
333  */
334  virtual bool GetLosCircular() = 0;
335 
336  /**
337  * Sets shared LOS data for player to the given list of players.
338  */
339  virtual void SetSharedLos(player_id_t player, std::vector<player_id_t> players) = 0;
340 
341  /**
342  * Returns shared LOS mask for player.
343  */
344  virtual u32 GetSharedLosMask(player_id_t player) = 0;
345 
346  /**
347  * Get percent map explored statistics for specified player.
348  */
349  virtual u8 GetPercentMapExplored(player_id_t player) = 0;
350 
351 
352  /**
353  * Perform some internal consistency checks for testing/debugging.
354  */
355  virtual void Verify() = 0;
356 
357  DECLARE_INTERFACE_TYPE(RangeManager)
358 };
359 
360 #endif // INCLUDED_ICMPRANGEMANAGER
bool IsVisible_UncheckedRange(ssize_t i, ssize_t j)
Returns whether the given vertex is visible (i.e.
#define u8
Definition: types.h:39
A simple fixed-point number class.
Definition: Fixed.h:115
const CLosQuerier & operator=(const CLosQuerier &)
CLosQuerier(u32 playerMask, const std::vector< u32 > &data, ssize_t verticesPerSide)
virtual CLosQuerier GetLosQuerier(player_id_t player)=0
Returns a CLosQuerier for checking whether vertex positions are visible to the given player (or other...
virtual u8 GetEntityFlagMask(std::string identifier)=0
Returns the mask for the specified identifier.
virtual bool GetLosRevealAll(player_id_t player)=0
Returns whether the whole map has been made visible to the given player.
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
Definition: Entity.h:80
virtual u32 GetSharedLosMask(player_id_t player)=0
Returns shared LOS mask for player.
virtual void Verify()=0
Perform some internal consistency checks for testing/debugging.
Provides efficient range-based queries of the game world, and also LOS-based effects (fog of war)...
virtual void SetDebugOverlay(bool enabled)=0
Toggle the rendering of debug info.
virtual bool GetLosCircular()=0
Returns whether the LOS is restricted to a circular map.
virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog=false)=0
Returns the visibility status of the given entity, with respect to the given player.
int32_t player_id_t
valid player IDs are non-negative (see ICmpOwnership)
Definition: Player.h:24
virtual u8 GetPercentMapExplored(player_id_t player)=0
Get percent map explored statistics for specified player.
virtual std::vector< entity_id_t > ResetActiveQuery(tag_t tag)=0
Immediately execute a query, and re-enable it if disabled.
virtual void DisableActiveQuery(tag_t tag)=0
Disable the processing of a query (no RangeUpdate messages will be sent).
virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value)=0
Set the flag specified by the identifier to the supplied value for the entity.
virtual tag_t CreateActiveParabolicQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, entity_pos_t elevationBonus, std::vector< int > owners, int requiredInterface, u8 flags)=0
Construct an active query of a paraboloic form around the unit.
Range manager implementation.
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
virtual void SetLosRevealAll(player_id_t player, bool enabled)=0
Set whether the whole map should be made visible to the given player.
virtual entity_pos_t GetElevationAdaptedRange(CFixedVector3D pos, CFixedVector3D rot, entity_pos_t range, entity_pos_t elevationBonus, entity_pos_t angle)=0
Get the average elevation over 8 points on distance range around the entity.
bool IsExplored_UncheckedRange(ssize_t i, ssize_t j)
Returns whether the given vertex is explored (i.e.
#define DECLARE_INTERFACE_TYPE(iname)
Definition: Interface.h:23
virtual void SetLosCircular(bool enabled)=0
Set the LOS to be restricted to a circular map.
virtual std::vector< entity_id_t > GetEntitiesByPlayer(player_id_t player)=0
Returns list of all entities for specific player.
virtual std::vector< entity_id_t > ExecuteQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, std::vector< int > owners, int requiredInterface)=0
Execute a passive query.
intptr_t ssize_t
Definition: wposix_types.h:82
bool IsVisible(ssize_t i, ssize_t j)
Returns whether the given vertex is visible (i.e.
bool IsExplored(ssize_t i, ssize_t j)
Returns whether the given vertex is explored (i.e.
#define u32
Definition: types.h:41
virtual void SetSharedLos(player_id_t player, std::vector< player_id_t > players)=0
Sets shared LOS data for player to the given list of players.
Object providing efficient abstracted access to the LOS state.
virtual void EnableActiveQuery(tag_t tag)=0
Re-enable the processing of a query.
Entity coordinate types.
u32 entity_id_t
Entity ID type.
Definition: Entity.h:24
virtual tag_t CreateActiveQuery(entity_id_t source, entity_pos_t minRange, entity_pos_t maxRange, std::vector< int > owners, int requiredInterface, u8 flags)=0
Construct an active query.
u32 tag_t
External identifiers for active queries.
virtual void SetBounds(entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, ssize_t vertices)=0
Set the bounds of the world.
virtual void DestroyActiveQuery(tag_t tag)=0
Destroy a query and clean up resources.
std::string GetLosVisibility_wrapper(entity_id_t ent, player_id_t player, bool forceRetainInFog)
GetLosVisibility wrapped for script calls.