Ticket #1707: RangeManagerOpt.2.patch
File RangeManagerOpt.2.patch, 13.0 KB (added by , 11 years ago) |
---|
-
trunk/source/simulation2/serialization/SerializeTemplates.h
24 24 */ 25 25 26 26 #include "simulation2/components/ICmpPathfinder.h" 27 #include "simulation2/helpers/EntityMap.h" 27 28 28 29 template<typename ELEM> 29 30 struct SerializeVector … … 87 88 } 88 89 }; 89 90 91 template<typename VS> 92 struct SerializeEntityMap 93 { 94 template<typename V> 95 void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap<V>& value) 96 { 97 size_t len = value.size(); 98 serialize.NumberU32_Unbounded("length", (u32)len); 99 for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it) 100 { 101 serialize.NumberU32_Unbounded("key", it->first); 102 VS()(serialize, "value", it->second); 103 } 104 } 105 106 template<typename V> 107 void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap<V>& value) 108 { 109 value.clear(); 110 u32 len; 111 deserialize.NumberU32_Unbounded("length", len); 112 for (size_t i = 0; i < len; ++i) 113 { 114 entity_id_t k; 115 deserialize.NumberU32_Unbounded("key", k); 116 V v; 117 VS()(deserialize, "value", v); 118 value.insert(std::make_pair(k, v)); 119 } 120 } 121 }; 122 90 123 // We have to order the map before serializing to make things consistent 91 124 template<typename KS, typename VS> 92 125 struct SerializeUnorderedMap -
trunk/source/simulation2/components/CCmpRangeManager.cpp
26 26 #include "simulation2/components/ICmpVision.h" 27 27 #include "simulation2/helpers/Render.h" 28 28 #include "simulation2/helpers/Spatial.h" 29 #include "simulation2/helpers/EntityMap.h" 29 30 30 31 #include "graphics/Overlay.h" 31 32 #include "graphics/Terrain.h" … … 149 150 */ 150 151 struct EntityDistanceOrdering 151 152 { 152 EntityDistanceOrdering(const std::map<entity_id_t,EntityData>& entities, const CFixedVector2D& source) :153 EntityDistanceOrdering(const EntityMap<EntityData>& entities, const CFixedVector2D& source) : 153 154 m_EntityData(entities), m_Source(source) 154 155 { 155 156 } … … 163 164 return (vecA.CompareLength(vecB) < 0); 164 165 } 165 166 166 const std::map<entity_id_t,EntityData>& m_EntityData;167 const EntityMap<EntityData>& m_EntityData; 167 168 CFixedVector2D m_Source; 168 169 169 170 private: … … 210 211 // Range query state: 211 212 tag_t m_QueryNext; // next allocated id 212 213 std::map<tag_t, Query> m_Queries; 213 std::map<entity_id_t,EntityData> m_EntityData;214 EntityMap<EntityData> m_EntityData; 214 215 SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData 215 216 216 217 // LOS state: … … 288 289 289 290 serialize.NumberU32_Unbounded("query next", m_QueryNext); 290 291 SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries); 291 Serialize Map<SerializeU32_Unbounded,SerializeEntityData>()(serialize, "entity data", m_EntityData);292 SerializeEntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData); 292 293 293 294 SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll); 294 295 serialize.Bool("los circular", m_LosCircular); … … 359 360 const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg); 360 361 entity_id_t ent = msgData.entity; 361 362 362 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);363 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 363 364 364 365 // Ignore if we're not already tracking this entity 365 366 if (it == m_EntityData.end()) … … 406 407 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 407 408 entity_id_t ent = msgData.entity; 408 409 409 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);410 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 410 411 411 412 // Ignore if we're not already tracking this entity 412 413 if (it == m_EntityData.end()) … … 429 430 const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg); 430 431 entity_id_t ent = msgData.entity; 431 432 432 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);433 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 433 434 434 435 // Ignore if we're not already tracking this entity 435 436 if (it == m_EntityData.end()) … … 451 452 const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg); 452 453 entity_id_t ent = msgData.entity; 453 454 454 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);455 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 455 456 456 457 // Ignore if we're not already tracking this entity 457 458 if (it == m_EntityData.end()) … … 576 577 m_LosStateRevealed.clear(); 577 578 m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide); 578 579 579 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)580 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 580 581 { 581 582 if (it->second.inWorld) 582 583 LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z)); … … 602 603 // (TODO: find the optimal number instead of blindly guessing) 603 604 m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); 604 605 605 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)606 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 606 607 { 607 if (it->second.inWorld) 608 if (it->second.inWorld) // also checks validity as default is false. 608 609 m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z)); 609 610 } 610 611 } … … 723 724 724 725 u32 ownerMask = CalcOwnerMask(player); 725 726 726 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)727 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 727 728 { 728 729 // Check owner and add to list if it matches 729 if ( CalcOwnerMask(it->second.owner) & ownerMask)730 if (it->first != INVALID_ENTITY && CalcOwnerMask(it->second.owner) & ownerMask) 730 731 entities.push_back(it->first); 731 732 } 732 733 … … 834 835 // Special case: range -1.0 means check all entities ignoring distance 835 836 if (q.maxRange == entity_pos_t::FromInt(-1)) 836 837 { 837 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)838 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 838 839 { 840 if (it->first == INVALID_ENTITY) 841 continue; 839 842 if (!TestEntityQuery(q, it->first, it->second)) 840 843 continue; 841 844 … … 845 848 else 846 849 { 847 850 // Get a quick list of entities that are potentially in range 848 std::vector<entity_id_t> ents = m_Subdivision.GetNear (pos, q.maxRange);851 std::vector<entity_id_t> ents = m_Subdivision.GetNearUnsorted(pos, q.maxRange); 849 852 850 853 for (size_t i = 0; i < ents.size(); ++i) 851 854 { 852 std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.find(ents[i]);855 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]); 853 856 ENSURE(it != m_EntityData.end()); 854 857 855 858 if (!TestEntityQuery(q, it->first, it->second)) … … 975 978 976 979 virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value) 977 980 { 978 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);981 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 979 982 980 983 // We don't have this entity 981 984 if (it == m_EntityData.end()) -
trunk/source/simulation2/helpers/Spatial.h
215 215 216 216 return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range)); 217 217 } 218 219 /** 220 * Returns a list of items that includes all items 221 * within the given axis-aligned square range. 222 * This version is unsorted, which is faster if that's not required. 223 * However the result might contain some entities twice or more. 224 */ 225 std::vector<T> GetInRangeUnsorted(CFixedVector2D posMin, CFixedVector2D posMax) 226 { 227 std::vector<T> ret; 228 229 ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y); 230 231 u32 i0 = GetI0(posMin.X); 232 u32 j0 = GetJ0(posMin.Y); 233 u32 i1 = GetI1(posMax.X); 234 u32 j1 = GetJ1(posMax.Y); 235 for (u32 j = j0; j <= j1; ++j) 236 { 237 for (u32 i = i0; i <= i1; ++i) 238 { 239 std::vector<T>& div = m_Divisions[i + j*m_DivisionsW]; 240 ret.insert(ret.end(), div.begin(), div.end()); 241 } 242 } 243 return ret; 244 } 245 246 /** 247 * Returns a sorted list of unique items that includes all items 248 * within the given circular distance of the given point. 249 * This returns unsorted results. 250 */ 251 std::vector<T> GetNearUnsorted(CFixedVector2D pos, entity_pos_t range) 252 { 253 // TODO: be cleverer and return a circular pattern of divisions, 254 // not this square over-approximation 255 256 return GetInRangeUnsorted(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range)); 257 } 218 258 219 259 private: 220 260 // Helper functions for translating coordinates into division indexes -
trunk/source/simulation2/helpers/EntityMap.h
1 #ifndef INCLUDED_ENTITYMAP 2 #define INCLUDED_ENTITYMAP 3 4 /** 5 * A fast replacement for map<entity_id_t, T>. 6 * We make the following assumptions: 7 * - entity id's (keys) are unique and are inserted in increasing order 8 * - an entity id that was removed is never added again 9 * - modifications (add / delete) are far less frequent then look-ups 10 * - preformance for iteration is important 11 */ 12 template<typename T> class EntityMap 13 { 14 public: 15 // Map interface: 16 // Member types 17 typedef entity_id_t key_type; 18 typedef T mapped_type; 19 typedef std::pair<entity_id_t, T> value_type; 20 21 typedef typename std::vector<value_type>::difference_type difference_type; 22 typedef typename std::vector<value_type>::size_type size_type; 23 24 typedef typename std::vector<value_type>::iterator iterator; 25 typedef typename std::vector<value_type>::const_iterator const_iterator; 26 27 private: 28 std::vector<value_type> m_Data; 29 size_t m_Size; 30 31 public: 32 inline EntityMap() : m_Data(), m_Size(0) 33 { 34 } 35 36 inline EntityMap(const EntityMap& m) : m_Data(m.m_Data), m_Size(m.m_Size) 37 { 38 } 39 40 // Iterators 41 42 inline iterator begin() 43 { 44 iterator it(m_Data.begin()); 45 if (size() != 0 && it->first == INVALID_ENTITY) 46 while (it != end() && (it++)->first == INVALID_ENTITY); 47 return it; 48 } 49 inline iterator end() 50 { 51 if (size() == 0) return begin(); 52 return m_Data.end(); 53 } 54 inline const_iterator begin() const 55 { 56 const_iterator it(m_Data.begin()); 57 if (size() != 0 && it->first == INVALID_ENTITY) 58 while (it != end() && (it++)->first == INVALID_ENTITY); 59 return it; 60 } 61 inline const_iterator end() const 62 { 63 if (size() == 0) return begin(); 64 return m_Data.end(); 65 } 66 67 // Capacity 68 inline bool empty() const { return m_Size == 0; } 69 inline size_type size() const { return m_Size; } 70 71 // Modification 72 std::pair<iterator, bool> insert(const value_type& val) 73 { 74 difference_type index = val.first; 75 bool new_index = false; // was a new element created? 76 if (index >= (int)m_Data.size()) 77 { 78 m_Data.resize(index + 1); 79 new_index = true; 80 ++m_Size; 81 } 82 m_Data[index] = val; 83 return std::make_pair(iterator(&m_Data[index]), new_index); // false: element existed 84 } 85 86 void erase(iterator it) 87 { 88 // only reliable way right now? or we could try ~T() and memset null? 89 it->first = INVALID_ENTITY; // mark it as 'invalid entity_id' 90 it->second.~T(); // call dtor 91 new (&it->second) T(); // call placement new 92 --m_Size; 93 } 94 95 size_type erase(const key_type& key) 96 { 97 iterator it = find(key); 98 if (it != end()) 99 erase(it); 100 return 1; 101 } 102 103 inline void swap(EntityMap &map) 104 { 105 m_Data.swap(map.m_Data); 106 } 107 108 inline void clear() 109 { 110 m_Size = 0; 111 m_Data.clear(); 112 } 113 114 // Operations 115 inline iterator find(const key_type& key) 116 { 117 if (key < m_Data.size()) 118 { 119 const value_type& val = m_Data[key]; 120 if (val.first != INVALID_ENTITY) // is this a valid element? 121 return iterator(&m_Data[key]); 122 } 123 return end(); // not found 124 } 125 126 inline const_iterator find(const key_type& key) const 127 { 128 if (key < m_Data.size()) 129 { 130 const value_type& val = m_Data[key]; 131 if (val.first != INVALID_ENTITY) // is this a valid element? 132 return const_iterator(&m_Data[key]); 133 } 134 return end(); // not found 135 } 136 137 inline size_type count(const key_type& key) const 138 { 139 return find(key) == end() ? 0 : 1; 140 } 141 }; 142 #endif