Ticket #2573: 0001-Revert-r13854-spatial-subdivision-optimisations.patch
File 0001-Revert-r13854-spatial-subdivision-optimisations.patch, 45.4 KB (added by , 10 years ago) |
---|
-
deleted file source/lib/ps_stl.h
From b6fe72e60ea20016d0df5b37e6ff548669c9acc1 Mon Sep 17 00:00:00 2001 From: Philip Taylor <philip@zaynar.co.uk> Date: Tue, 20 May 2014 23:33:49 +0100 Subject: [PATCH] Revert r13854 (spatial subdivision optimisations) The hardcoded limit on the number of returned entities causes warnings and buggy behaviour, especially when PickEntitiesAtPoint calls GetNear() with a large range. The attempted optimisations are not a good enough solution by themselves, and are not worth the bugs they introduced. --- source/lib/ps_stl.h | 101 ------- source/simulation2/MessageTypes.h | 22 +- .../components/CCmpObstructionManager.cpp | 30 +-- source/simulation2/components/CCmpRangeManager.cpp | 137 ++++------ source/simulation2/components/ICmpRangeManager.h | 2 +- source/simulation2/helpers/Selection.cpp | 5 +- source/simulation2/helpers/Spatial.h | 237 +++++------------ source/simulation2/system/EntityMap.h | 282 -------------------- source/simulation2/system/SimContext.cpp | 1 + 9 files changed, 153 insertions(+), 664 deletions(-) delete mode 100644 source/lib/ps_stl.h delete mode 100644 source/simulation2/system/EntityMap.h diff --git a/source/lib/ps_stl.h b/source/lib/ps_stl.h deleted file mode 100644 index ce7eb47..0000000
+ - 1 /* Copyright (c) 2013 Wildfire Games2 *3 * Permission is hereby granted, free of charge, to any person obtaining4 * a copy of this software and associated documentation files (the5 * "Software"), to deal in the Software without restriction, including6 * without limitation the rights to use, copy, modify, merge, publish,7 * distribute, sublicense, and/or sell copies of the Software, and to8 * permit persons to whom the Software is furnished to do so, subject to9 * the following conditions:10 *11 * The above copyright notice and this permission notice shall be included12 * in all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.21 */22 #ifndef INCLUDED_PS_STL23 #define INCLUDED_PS_STL24 25 /**26 * @author Jorma Rebane27 * @note Pyrogenesis STL methods28 * @note This file contains useful and optimized methods for use with STL29 */30 31 namespace ps32 {33 /**34 * Removes the first occurrence of the specified value from the container.35 * @param container The STL-compatible container to remove from.36 * @param value The value to remove.37 */38 template<class Container, class T>39 inline void remove_first_occurrence(Container& container, const T& value)40 {41 if (int count = container.size())42 {43 T* data = &container[0];44 for (int i = 0; i < count; ++i)45 {46 if (data[i] == value)47 {48 container.erase(container.begin() + i);49 return;50 }51 }52 }53 }54 55 /**56 * @param container The STL-compatible container to search in.57 * @param value The value to search for.58 * @return TRUE if [value] exists in [container].59 */60 template<class Container, class T>61 inline bool exists_in(const Container& container, const T& value)62 {63 if (int count = container.size())64 {65 for (const T* data = &container[0]; count; ++data, --count)66 {67 if (*data == value)68 {69 return true;70 }71 }72 }73 return false;74 }75 76 /**77 * Finds a value in a container78 * @param container The STL-compatible container to search in.79 * @param value The value to search for.80 * @return Pointer to the value if found, NULL if not found.81 */82 template<class Container, class T>83 inline T* find_in(const Container& container, const T& value)84 {85 if (int count = container.size())86 {87 for (const T* data = &container[0]; count; ++data, --count)88 {89 if (*data == value)90 {91 return (T*)data;92 }93 }94 }95 return NULL;96 }97 98 99 } // namespace ps100 101 #endif // INCLUDED_PS_STL102 No newline at end of file -
source/simulation2/MessageTypes.h
diff --git a/source/simulation2/MessageTypes.h b/source/simulation2/MessageTypes.h index 80e9e22..8dce8a4 100644
a b class CMessageRangeUpdate : public CMessage 329 329 public: 330 330 DEFAULT_MESSAGE_IMPL(RangeUpdate) 331 331 332 332 CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed) : 333 tag(tag), added(added), removed(removed) 334 { 335 } 333 336 334 337 u32 tag; 335 338 std::vector<entity_id_t> added; … … public: 339 342 // swap vectors instead of copying (to save on memory allocations), 340 343 // so add some constructors for it: 341 344 342 // don't init tag in empty ctor 343 CMessageRangeUpdate() 344 { 345 } 346 CMessageRangeUpdate(u32 tag) : tag(tag) 345 CMessageRangeUpdate(u32 tag) : 346 tag(tag) 347 347 { 348 348 } 349 CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed) 350 : tag(tag), added(added), removed(removed) 351 { 352 } 353 CMessageRangeUpdate(const CMessageRangeUpdate& other) 354 : CMessage(), tag(other.tag), added(other.added), removed(other.removed) 349 350 CMessageRangeUpdate(const CMessageRangeUpdate& other) : 351 CMessage(), tag(other.tag), added(other.added), removed(other.removed) 355 352 { 356 353 } 354 357 355 CMessageRangeUpdate& operator=(const CMessageRangeUpdate& other) 358 356 { 359 357 tag = other.tag; -
source/simulation2/components/CCmpObstructionManager.cpp
diff --git a/source/simulation2/components/CCmpObstructionManager.cpp b/source/simulation2/components/CCmpObstructionManager.cpp index fe843e8..2f5eed0 100644
a b public: 124 124 bool m_DebugOverlayDirty; 125 125 std::vector<SOverlayLine> m_DebugOverlayLines; 126 126 127 SpatialSubdivision m_UnitSubdivision;128 SpatialSubdivision m_StaticSubdivision;127 SpatialSubdivision<u32> m_UnitSubdivision; 128 SpatialSubdivision<u32> m_StaticSubdivision; 129 129 130 130 // TODO: using std::map is a bit inefficient; is there a better way to store these? 131 131 std::map<u32, UnitShape> m_UnitShapes; … … public: 161 161 162 162 // Initialise with bogus values (these will get replaced when 163 163 // SetBounds is called) 164 ResetSubdivisions(entity_pos_t::FromInt(1 024), entity_pos_t::FromInt(1024));164 ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1)); 165 165 } 166 166 167 167 virtual void Deinit() … … public: 171 171 template<typename S> 172 172 void SerializeCommon(S& serialize) 173 173 { 174 SerializeSpatialSubdivision ()(serialize, "unit subdiv", m_UnitSubdivision);175 SerializeSpatialSubdivision ()(serialize, "static subdiv", m_StaticSubdivision);174 SerializeSpatialSubdivision<SerializeU32_Unbounded>()(serialize, "unit subdiv", m_UnitSubdivision); 175 SerializeSpatialSubdivision<SerializeU32_Unbounded>()(serialize, "static subdiv", m_StaticSubdivision); 176 176 177 177 SerializeMap<SerializeU32_Unbounded, SerializeUnitShape>()(serialize, "unit shapes", m_UnitShapes); 178 178 SerializeMap<SerializeU32_Unbounded, SerializeStaticShape>()(serialize, "static shapes", m_StaticShapes); … … bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti 544 544 CFixedVector2D posMin (std::min(x0, x1) - r, std::min(z0, z1) - r); 545 545 CFixedVector2D posMax (std::max(x0, x1) + r, std::max(z0, z1) + r); 546 546 547 SpatialQueryArray unitShapes; 548 m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); 549 for (int i = 0; i < unitShapes.size(); ++i) 547 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(posMin, posMax); 548 for (size_t i = 0; i < unitShapes.size(); ++i) 550 549 { 551 550 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); 552 551 ENSURE(it != m_UnitShapes.end()); … … bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, enti 560 559 return true; 561 560 } 562 561 563 SpatialQueryArray staticShapes; 564 m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax); 565 for (int i = 0; i < staticShapes.size(); ++i) 562 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(posMin, posMax); 563 for (size_t i = 0; i < staticShapes.size(); ++i) 566 564 { 567 565 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); 568 566 ENSURE(it != m_StaticShapes.end()); … … void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter 882 880 883 881 ENSURE(x0 <= x1 && z0 <= z1); 884 882 885 SpatialQueryArray unitShapes; 886 m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 887 for (int i = 0; i < unitShapes.size(); ++i) 883 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 884 for (size_t i = 0; i < unitShapes.size(); ++i) 888 885 { 889 886 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); 890 887 ENSURE(it != m_UnitShapes.end()); … … void CCmpObstructionManager::GetObstructionsInRange(const IObstructionTestFilter 904 901 squares.push_back(s); 905 902 } 906 903 907 SpatialQueryArray staticShapes; 908 m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 909 for (int i = 0; i < staticShapes.size(); ++i) 904 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 905 for (size_t i = 0; i < staticShapes.size(); ++i) 910 906 { 911 907 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); 912 908 ENSURE(it != m_StaticShapes.end()); -
source/simulation2/components/CCmpRangeManager.cpp
diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp index a281332..e4504f4 100644
a b 21 21 #include "ICmpRangeManager.h" 22 22 23 23 #include "ICmpTerrain.h" 24 #include "simulation2/system/EntityMap.h"25 24 #include "simulation2/MessageTypes.h" 26 25 #include "simulation2/components/ICmpPosition.h" 27 26 #include "simulation2/components/ICmpTerritoryManager.h" … … 37 36 #include "ps/Overlay.h" 38 37 #include "ps/Profile.h" 39 38 #include "renderer/Scene.h" 40 #include "lib/ps_stl.h"41 42 39 43 40 #define DEBUG_RANGE_MANAGER_BOUNDS 0 44 41 … … struct Query 63 60 * Convert an owner ID (-1 = unowned, 0 = gaia, 1..30 = players) 64 61 * into a 32-bit mask for quick set-membership tests. 65 62 */ 66 static inlineu32 CalcOwnerMask(player_id_t owner)63 static u32 CalcOwnerMask(player_id_t owner) 67 64 { 68 65 if (owner >= -1 && owner < 31) 69 66 return 1 << (1+owner); … … static inline u32 CalcOwnerMask(player_id_t owner) 74 71 /** 75 72 * Returns LOS mask for given player. 76 73 */ 77 static inlineu32 CalcPlayerLosMask(player_id_t player)74 static u32 CalcPlayerLosMask(player_id_t player) 78 75 { 79 76 if (player > 0 && player <= 16) 80 77 return ICmpRangeManager::LOS_MASK << (2*(player-1)); … … struct SerializeEntityData 211 208 */ 212 209 struct EntityDistanceOrdering 213 210 { 214 EntityDistanceOrdering(const EntityMap<EntityData>& entities, const CFixedVector2D& source) :211 EntityDistanceOrdering(const std::map<entity_id_t, EntityData>& entities, const CFixedVector2D& source) : 215 212 m_EntityData(entities), m_Source(source) 216 213 { 217 214 } … … struct EntityDistanceOrdering 225 222 return (vecA.CompareLength(vecB) < 0); 226 223 } 227 224 228 const EntityMap<EntityData>& m_EntityData;225 const std::map<entity_id_t, EntityData>& m_EntityData; 229 226 CFixedVector2D m_Source; 230 227 231 228 private: … … public: 272 269 // Range query state: 273 270 tag_t m_QueryNext; // next allocated id 274 271 std::map<tag_t, Query> m_Queries; 275 EntityMap<EntityData> m_EntityData; 276 277 SpatialSubdivision m_Subdivision; // spatial index of m_EntityData 272 std::map<entity_id_t, EntityData> m_EntityData; 273 SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData 278 274 279 275 // LOS state: 280 276 static const player_id_t MAX_LOS_PLAYER_ID = 16; … … public: 321 317 322 318 // Initialise with bogus values (these will get replaced when 323 319 // SetBounds is called) 324 ResetSubdivisions(entity_pos_t::FromInt(1 024), entity_pos_t::FromInt(1024));320 ResetSubdivisions(entity_pos_t::FromInt(1), entity_pos_t::FromInt(1)); 325 321 326 322 // The whole map should be visible to Gaia by default, else e.g. animals 327 323 // will get confused when trying to run from enemies … … public: 348 344 349 345 serialize.NumberU32_Unbounded("query next", m_QueryNext); 350 346 SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries, GetSimContext()); 351 Serialize EntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData);347 SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData); 352 348 353 349 SerializeVector<SerializeBool>()(serialize, "los reveal all", m_LosRevealAll); 354 350 serialize.Bool("los circular", m_LosCircular); … … public: 409 405 } 410 406 411 407 // Remember this entity 412 m_EntityData.insert(ent, entdata); 408 m_EntityData.insert(std::make_pair(ent, entdata)); 409 413 410 break; 414 411 } 415 412 case MT_PositionChanged: … … public: 417 414 const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg); 418 415 entity_id_t ent = msgData.entity; 419 416 420 EntityMap<EntityData>::iterator it = m_EntityData.find(ent);417 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent); 421 418 422 419 // Ignore if we're not already tracking this entity 423 420 if (it == m_EntityData.end()) … … public: 464 461 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 465 462 entity_id_t ent = msgData.entity; 466 463 467 EntityMap<EntityData>::iterator it = m_EntityData.find(ent);464 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent); 468 465 469 466 // Ignore if we're not already tracking this entity 470 467 if (it == m_EntityData.end()) … … public: 487 484 const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg); 488 485 entity_id_t ent = msgData.entity; 489 486 490 EntityMap<EntityData>::iterator it = m_EntityData.find(ent);487 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent); 491 488 492 489 // Ignore if we're not already tracking this entity 493 490 if (it == m_EntityData.end()) … … public: 509 506 const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg); 510 507 entity_id_t ent = msgData.entity; 511 508 512 EntityMap<EntityData>::iterator it = m_EntityData.find(ent);509 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent); 513 510 514 511 // Ignore if we're not already tracking this entity 515 512 if (it == m_EntityData.end()) … … public: 573 570 574 571 std::vector<std::vector<u16> > oldPlayerCounts = m_LosPlayerCounts; 575 572 std::vector<u32> oldStateRevealed = m_LosStateRevealed; 576 SpatialSubdivision oldSubdivision = m_Subdivision;573 SpatialSubdivision<entity_id_t> oldSubdivision = m_Subdivision; 577 574 578 575 ResetDerivedData(true); 579 576 … … public: 601 598 debug_warn(L"inconsistent subdivs"); 602 599 } 603 600 604 SpatialSubdivision * GetSubdivision()601 SpatialSubdivision<entity_id_t>* GetSubdivision() 605 602 { 606 return & 603 return &m_Subdivision; 607 604 } 608 605 609 606 // Reinitialise subdivisions and LOS data, based on entity data … … public: 639 636 m_LosStateRevealed.clear(); 640 637 m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide); 641 638 642 for ( EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)639 for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 643 640 { 644 641 if (it->second.inWorld) 645 642 LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z)); … … public: 665 662 // (TODO: find the optimal number instead of blindly guessing) 666 663 m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); 667 664 668 for ( EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)665 for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 669 666 { 670 667 if (it->second.inWorld) 671 668 m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z)); … … public: 810 807 811 808 u32 ownerMask = CalcOwnerMask(player); 812 809 813 for ( EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)810 for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 814 811 { 815 812 // Check owner and add to list if it matches 816 813 if (CalcOwnerMask(it->second.owner) & ownerMask) … … public: 838 835 // Store a queue of all messages before sending any, so we can assume 839 836 // no entities will move until we've finished checking all the ranges 840 837 std::vector<std::pair<entity_id_t, CMessageRangeUpdate> > messages; 841 std::vector<entity_id_t> results;842 std::vector<entity_id_t> added;843 std::vector<entity_id_t> removed;844 838 845 839 for (std::map<tag_t, Query>::iterator it = m_Queries.begin(); it != m_Queries.end(); ++it) 846 840 { 847 Query& q uery= it->second;841 Query& q = it->second; 848 842 849 if (!q uery.enabled)843 if (!q.enabled) 850 844 continue; 851 845 852 CmpPtr<ICmpPosition> cmpSourcePosition(q uery.source);846 CmpPtr<ICmpPosition> cmpSourcePosition(q.source); 853 847 if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld()) 854 848 continue; 855 849 856 results.clear(); 857 results.reserve(query.lastMatch.size()); 850 std::vector<entity_id_t> r; 851 r.reserve(q.lastMatch.size()); 852 858 853 CFixedVector2D pos = cmpSourcePosition->GetPosition2D(); 859 PerformQuery(q uery, results, pos);854 PerformQuery(q, r, pos); 860 855 861 856 // Compute the changes vs the last match 862 added.clear(); 863 removed.clear(); 864 // Return the 'added' list sorted by distance from the entity 865 // (Don't bother sorting 'removed' because they might not even have positions or exist any more) 866 std::set_difference(results.begin(), results.end(), query.lastMatch.begin(), query.lastMatch.end(), 867 std::back_inserter(added)); 868 std::set_difference(query.lastMatch.begin(), query.lastMatch.end(), results.begin(), results.end(), 869 std::back_inserter(removed)); 857 std::vector<entity_id_t> added; 858 std::vector<entity_id_t> removed; 859 std::set_difference(r.begin(), r.end(), q.lastMatch.begin(), q.lastMatch.end(), std::back_inserter(added)); 860 std::set_difference(q.lastMatch.begin(), q.lastMatch.end(), r.begin(), r.end(), std::back_inserter(removed)); 861 870 862 if (added.empty() && removed.empty()) 871 863 continue; 872 864 873 std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, cmpSourcePosition->GetPosition2D())); 865 // Return the 'added' list sorted by distance from the entity 866 // (Don't bother sorting 'removed' because they might not even have positions or exist any more) 867 std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, pos)); 868 869 messages.push_back(std::make_pair(q.source.GetId(), CMessageRangeUpdate(it->first))); 870 messages.back().second.added.swap(added); 871 messages.back().second.removed.swap(removed); 874 872 875 messages.resize(messages.size() + 1); 876 std::pair<entity_id_t, CMessageRangeUpdate>& back = messages.back(); 877 back.first = query.source.GetId(); 878 back.second.tag = it->first; 879 back.second.added.swap(added); 880 back.second.removed.swap(removed); 881 it->second.lastMatch.swap(results); 873 it->second.lastMatch.swap(r); 882 874 } 883 875 884 CComponentManager& cmpMgr = GetSimContext().GetComponentManager();885 876 for (size_t i = 0; i < messages.size(); ++i) 886 cmpMgr.PostMessage(messages[i].first, messages[i].second);877 GetSimContext().GetComponentManager().PostMessage(messages[i].first, messages[i].second); 887 878 } 888 879 889 880 /** … … public: 923 914 // Special case: range -1.0 means check all entities ignoring distance 924 915 if (q.maxRange == entity_pos_t::FromInt(-1)) 925 916 { 926 for ( EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)917 for (std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 927 918 { 928 919 if (!TestEntityQuery(q, it->first, it->second)) 929 920 continue; … … public: 939 930 CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+ 940 931 CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ; 941 932 // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange 942 SpatialQueryArray ents; 943 m_Subdivision.GetNear(ents, pos, q.maxRange*2); 933 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange*2); 944 934 945 for ( int i = 0; i < ents.size(); ++i)935 for (size_t i = 0; i < ents.size(); ++i) 946 936 { 947 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);937 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]); 948 938 ENSURE(it != m_EntityData.end()); 949 939 950 940 if (!TestEntityQuery(q, it->first, it->second)) … … public: 970 960 } 971 961 972 962 r.push_back(it->first); 963 973 964 } 974 965 } 975 966 // check a regular range (i.e. not the entire world, and not parabolic) 976 967 else 977 968 { 978 969 // Get a quick list of entities that are potentially in range 979 SpatialQueryArray ents; 980 m_Subdivision.GetNear(ents, pos, q.maxRange); 970 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange); 981 971 982 for ( int i = 0; i < ents.size(); ++i)972 for (size_t i = 0; i < ents.size(); ++i) 983 973 { 984 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]);974 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]); 985 975 ENSURE(it != m_EntityData.end()); 986 976 987 977 if (!TestEntityQuery(q, it->first, it->second)) … … public: 1000 990 } 1001 991 1002 992 r.push_back(it->first); 993 1003 994 } 1004 995 } 1005 996 } … … public: 1153 1144 { 1154 1145 if (!m_DebugOverlayEnabled) 1155 1146 return; 1156 static CColor disabledRingColour(1, 0, 0, 1); // red 1157 static CColor enabledRingColour(0, 1, 0, 1); // green1158 static CColor subdivColour(0, 0, 1, 1); // blue1159 staticCColor rayColour(1, 1, 0, 0.2f);1147 1148 CColor enabledRingColour(0, 1, 0, 1); 1149 CColor disabledRingColour(1, 0, 0, 1); 1150 CColor rayColour(1, 1, 0, 0.2f); 1160 1151 1161 1152 if (m_DebugOverlayDirty) 1162 1153 { … … public: 1263 1254 } 1264 1255 } 1265 1256 1266 // render subdivision grid1267 float divSize = m_Subdivision.GetDivisionSize().ToFloat();1268 int width = m_Subdivision.GetWidth();1269 int height = m_Subdivision.GetHeight();1270 for (int x = 0; x < width; ++x)1271 {1272 for (int y = 0; y < height; ++y)1273 {1274 m_DebugOverlayLines.push_back(SOverlayLine());1275 m_DebugOverlayLines.back().m_Color = subdivColour;1276 1277 float xpos = x*divSize + divSize/2;1278 float zpos = y*divSize + divSize/2;1279 SimRender::ConstructSquareOnGround(GetSimContext(), xpos, zpos, divSize, divSize, 0.0f,1280 m_DebugOverlayLines.back(), false, 1.0f);1281 }1282 }1283 1284 1257 m_DebugOverlayDirty = false; 1285 1258 } 1286 1259 … … public: 1301 1274 1302 1275 virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value) 1303 1276 { 1304 EntityMap<EntityData>::iterator it = m_EntityData.find(ent);1277 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent); 1305 1278 1306 1279 // We don't have this entity 1307 1280 if (it == m_EntityData.end()) -
source/simulation2/components/ICmpRangeManager.h
diff --git a/source/simulation2/components/ICmpRangeManager.h b/source/simulation2/components/ICmpRangeManager.h index f68a2d7..62dcdad 100644
a b public: 77 77 * Access the spatial subdivision kept by the range manager. 78 78 * @return pointer to spatial subdivision structure. 79 79 */ 80 virtual SpatialSubdivision * GetSubdivision() = 0;80 virtual SpatialSubdivision<entity_id_t>* GetSubdivision() = 0; 81 81 82 82 /** 83 83 * Set the bounds of the world. -
source/simulation2/helpers/Selection.cpp
diff --git a/source/simulation2/helpers/Selection.cpp b/source/simulation2/helpers/Selection.cpp index fc83f6f..b5f39b4 100644
a b std::vector<entity_id_t> EntitySelection::PickEntitiesAtPoint(CSimulation2& simu 49 49 CFixedVector2D pos(fixed::FromFloat(pos3d.X), fixed::FromFloat(pos3d.Z)); 50 50 51 51 // Get a rough group of entities using our approximated origin. 52 SpatialQueryArray ents; 53 cmpRangeManager->GetSubdivision()->GetNear(ents, pos, entity_pos_t::FromInt(range)); 52 std::vector<entity_id_t> ents = cmpRangeManager->GetSubdivision()->GetNear(pos, entity_pos_t::FromInt(range)); 54 53 55 54 // Filter for relevent entities and calculate precise distances. 56 55 std::vector<std::pair<float, entity_id_t> > hits; // (dist^2, entity) pairs 57 for ( int i = 0; i < ents.size(); ++i)56 for (size_t i = 0; i < ents.size(); ++i) 58 57 { 59 58 CmpPtr<ICmpSelectable> cmpSelectable(simulation, ents[i]); 60 59 if (!cmpSelectable) -
source/simulation2/helpers/Spatial.h
diff --git a/source/simulation2/helpers/Spatial.h b/source/simulation2/helpers/Spatial.h index cd3b8d8..78f0b6b 100644
a b 23 23 #include "ps/CLogger.h" 24 24 25 25 /** 26 * A simple fixed-size array that works similar to an std::vector27 * but is obviously limited in its max items28 */29 struct SpatialQueryArray30 {31 enum { MAX_COUNT = 2048 };32 int count;33 uint32_t items[MAX_COUNT];34 35 inline SpatialQueryArray() : count(0) {}36 inline const uint32_t& operator[](int index) const { return items[index]; }37 inline uint32_t& operator[](int index) { return items[index]; }38 inline int size() const { return count; }39 inline void clear() { count = 0; }40 void make_unique() // removes any duplicate entries41 {42 if (count)43 {44 std::sort(items, items + count); // we need a sorted list for std::unique to work45 count = int(std::unique(items, items + count) - items);46 }47 }48 };49 50 /**51 26 * A very basic subdivision scheme for finding items in ranges. 52 27 * Items are stored in lists in fixed-size divisions. 53 28 * Items have a size (min/max values of their axis-aligned bounding box) … … struct SpatialQueryArray 61 36 * 62 37 * (TODO: maybe an adaptive quadtree would be better than fixed sizes?) 63 38 */ 39 template<typename T> 64 40 class SpatialSubdivision 65 41 { 66 struct SubDivisionGrid67 {68 std::vector<uint32_t> items;69 70 inline void push_back(uint32_t value)71 {72 items.push_back(value);73 }74 75 inline void erase(int index)76 {77 // Delete by swapping with the last element then popping78 if ((int)items.size() > 1) // but only if we have more than 1 elements79 items[index] = items.back();80 items.pop_back();81 }82 83 void copy_items(SpatialQueryArray& out)84 {85 if (items.empty())86 return; // nothing to copy87 88 int dsti = out.count; // the index in [out] where to start copying89 int count = (int)items.size();90 if ((dsti + count) > SpatialQueryArray::MAX_COUNT)91 {92 LOGWARNING(L"SpatialSubdivision Query too large. Results truncated.");93 count = SpatialQueryArray::MAX_COUNT - dsti; // don't copy overflowing items94 }95 uint32_t* dst = &out.items[dsti];96 uint32_t* src = &items[0];97 for (int i = 0; i < count; ++i) // copy all items98 dst[i] = src[i];99 out.count += count;100 }101 };102 103 104 entity_pos_t m_DivisionSize;105 SubDivisionGrid* m_Divisions;106 uint32_t m_DivisionsW;107 uint32_t m_DivisionsH;108 109 friend struct SerializeSubDivisionGrid;110 friend struct SerializeSpatialSubdivision;111 112 42 public: 113 SpatialSubdivision() : m_Divisions(NULL), m_DivisionsW(0), m_DivisionsH(0) 43 SpatialSubdivision() : 44 m_DivisionsW(0), m_DivisionsH(0) 114 45 { 115 46 } 116 ~SpatialSubdivision()117 {118 delete[] m_Divisions;119 }120 SpatialSubdivision(const SpatialSubdivision& rhs)121 {122 m_DivisionSize = rhs.m_DivisionSize;123 m_DivisionsW = rhs.m_DivisionsW;124 m_DivisionsH = rhs.m_DivisionsH;125 size_t n = m_DivisionsW * m_DivisionsH;126 m_Divisions = new SubDivisionGrid[n];127 for (size_t i = 0; i < n; ++i)128 m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy129 }130 SpatialSubdivision& operator=(const SpatialSubdivision& rhs)131 {132 if (this != &rhs)133 {134 m_DivisionSize = rhs.m_DivisionSize;135 size_t n = rhs.m_DivisionsW * rhs.m_DivisionsH;136 if (m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH)137 Create(n); // size changed, recreate138 139 m_DivisionsW = rhs.m_DivisionsW;140 m_DivisionsH = rhs.m_DivisionsH;141 for (size_t i = 0; i < n; ++i)142 m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy143 }144 return *this;145 }146 147 inline entity_pos_t GetDivisionSize() const { return m_DivisionSize; }148 inline uint32_t GetWidth() const { return m_DivisionsW; }149 inline uint32_t GetHeight() const { return m_DivisionsH; }150 151 void Create(size_t count)152 {153 if (m_Divisions) delete[] m_Divisions;154 m_Divisions = new SubDivisionGrid[count];155 }156 47 157 48 /** 158 49 * Equivalence test (ignoring order of items within each subdivision) … … public: 162 53 if (m_DivisionSize != rhs.m_DivisionSize || m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH) 163 54 return false; 164 55 165 uint32_t n = m_DivisionsH * m_DivisionsW; 166 for (uint32_t i = 0; i < n; ++i) 56 for (u32 j = 0; j < m_DivisionsH; ++j) 167 57 { 168 if (m_Divisions[i].items.size() != rhs.m_Divisions[i].items.size()) 169 return false; 170 171 // don't bother optimizing this, this is only used in the TESTING SUITE 172 std::vector<uint32_t> a = m_Divisions[i].items; 173 std::vector<uint32_t> b = rhs.m_Divisions[i].items; 174 std::sort(a.begin(), a.end()); 175 std::sort(b.begin(), b.end()); 176 if (a != b) 177 return false; 58 for (u32 i = 0; i < m_DivisionsW; ++i) 59 { 60 std::vector<T> div1 = m_Divisions.at(i + j*m_DivisionsW); 61 std::vector<T> div2 = rhs.m_Divisions.at(i + j*m_DivisionsW); 62 std::sort(div1.begin(), div1.end()); 63 std::sort(div2.begin(), div2.end()); 64 if (div1 != div2) 65 return false; 66 } 178 67 } 68 179 69 return true; 180 70 } 181 71 182 inlinebool operator!=(const SpatialSubdivision& rhs)72 bool operator!=(const SpatialSubdivision& rhs) 183 73 { 184 74 return !(*this == rhs); 185 75 } … … public: 189 79 m_DivisionSize = divisionSize; 190 80 m_DivisionsW = (maxX / m_DivisionSize).ToInt_RoundToInfinity(); 191 81 m_DivisionsH = (maxZ / m_DivisionSize).ToInt_RoundToInfinity(); 192 193 Create(m_DivisionsW * m_DivisionsH);82 m_Divisions.clear(); 83 m_Divisions.resize(m_DivisionsW * m_DivisionsH); 194 84 } 195 85 196 197 86 /** 198 87 * Add an item with the given 'to' size. 199 88 * The item must not already be present. 200 89 */ 201 void Add( uint32_titem, CFixedVector2D toMin, CFixedVector2D toMax)90 void Add(T item, CFixedVector2D toMin, CFixedVector2D toMax) 202 91 { 203 92 ENSURE(toMin.X <= toMax.X && toMin.Y <= toMax.Y); 204 93 … … public: 210 99 { 211 100 for (u32 i = i0; i <= i1; ++i) 212 101 { 213 m_Divisions[i + j*m_DivisionsW].push_back(item); 102 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW); 103 div.push_back(item); 214 104 } 215 105 } 216 106 } … … public: 220 110 * The item should already be present. 221 111 * The size must match the size that was last used when adding the item. 222 112 */ 223 void Remove( uint32_titem, CFixedVector2D fromMin, CFixedVector2D fromMax)113 void Remove(T item, CFixedVector2D fromMin, CFixedVector2D fromMax) 224 114 { 225 115 ENSURE(fromMin.X <= fromMax.X && fromMin.Y <= fromMax.Y); 226 116 … … public: 232 122 { 233 123 for (u32 i = i0; i <= i1; ++i) 234 124 { 235 SubDivisionGrid& div = m_Divisions[i + j*m_DivisionsW];236 int size = div.items.size(); 237 for ( int n = 0; n < size; ++n)125 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW); 126 127 for (u32 n = 0; n < div.size(); ++n) 238 128 { 239 if (div .items[n] == item)129 if (div[n] == item) 240 130 { 241 div.erase(n); 131 // Delete by swapping with the last element then popping 132 div[n] = div.back(); 133 div.pop_back(); 242 134 break; 243 135 } 244 136 } … … public: 249 141 /** 250 142 * Equivalent to Remove() then Add(), but potentially faster. 251 143 */ 252 void Move( uint32_titem, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)144 void Move(T item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax) 253 145 { 254 146 // Skip the work if we're staying in the same divisions 255 147 if (GetIndex0(fromMin) == GetIndex0(toMin) && GetIndex1(fromMax) == GetIndex1(toMax)) … … public: 263 155 * Convenience function for Add() of individual points. 264 156 * (Note that points on a boundary may occupy multiple divisions.) 265 157 */ 266 void Add( uint32_titem, CFixedVector2D to)158 void Add(T item, CFixedVector2D to) 267 159 { 268 160 Add(item, to, to); 269 161 } … … public: 271 163 /** 272 164 * Convenience function for Remove() of individual points. 273 165 */ 274 void Remove( uint32_titem, CFixedVector2D from)166 void Remove(T item, CFixedVector2D from) 275 167 { 276 168 Remove(item, from, from); 277 169 } … … public: 279 171 /** 280 172 * Convenience function for Move() of individual points. 281 173 */ 282 void Move( uint32_titem, CFixedVector2D from, CFixedVector2D to)174 void Move(T item, CFixedVector2D from, CFixedVector2D to) 283 175 { 284 176 Move(item, from, from, to, to); 285 177 } … … public: 288 180 * Returns a sorted list of unique items that includes all items 289 181 * within the given axis-aligned square range. 290 182 */ 291 void GetInRange(SpatialQueryArray& out,CFixedVector2D posMin, CFixedVector2D posMax)183 std::vector<T> GetInRange(CFixedVector2D posMin, CFixedVector2D posMax) 292 184 { 293 out.clear(); 185 std::vector<T> ret; 186 294 187 ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y); 295 188 296 189 u32 i0 = GetI0(posMin.X); … … public: 301 194 { 302 195 for (u32 i = i0; i <= i1; ++i) 303 196 { 304 m_Divisions[i + j*m_DivisionsW].copy_items(out); 197 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW); 198 ret.insert(ret.end(), div.begin(), div.end()); 305 199 } 306 200 } 307 // some buildings span several tiles, so we need to make it unique 308 out.make_unique(); 201 202 // Remove duplicates 203 std::sort(ret.begin(), ret.end()); 204 ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); 205 206 return ret; 309 207 } 310 208 311 209 /** 312 210 * Returns a sorted list of unique items that includes all items 313 211 * within the given circular distance of the given point. 314 212 */ 315 void GetNear(SpatialQueryArray& out,CFixedVector2D pos, entity_pos_t range)213 std::vector<T> GetNear(CFixedVector2D pos, entity_pos_t range) 316 214 { 317 215 // TODO: be cleverer and return a circular pattern of divisions, 318 216 // not this square over-approximation 319 CFixedVector2D r(range, range); 320 GetInRange(out, pos - r, pos + r);217 218 return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range)); 321 219 } 322 220 323 221 private: … … private: 325 223 // (avoiding out-of-bounds accesses, and rounding correctly so that 326 224 // points precisely between divisions are counted in both): 327 225 328 u int32_tGetI0(entity_pos_t x)226 u32 GetI0(entity_pos_t x) 329 227 { 330 228 return Clamp((x / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsW-1); 331 229 } 332 230 333 u int32_tGetJ0(entity_pos_t z)231 u32 GetJ0(entity_pos_t z) 334 232 { 335 233 return Clamp((z / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsH-1); 336 234 } 337 235 338 u int32_tGetI1(entity_pos_t x)236 u32 GetI1(entity_pos_t x) 339 237 { 340 238 return Clamp((x / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsW-1); 341 239 } 342 240 343 u int32_tGetJ1(entity_pos_t z)241 u32 GetJ1(entity_pos_t z) 344 242 { 345 243 return Clamp((z / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsH-1); 346 244 } 347 245 348 u int32_tGetIndex0(CFixedVector2D pos)246 u32 GetIndex0(CFixedVector2D pos) 349 247 { 350 248 return GetI0(pos.X) + GetJ0(pos.Y)*m_DivisionsW; 351 249 } 352 250 353 u int32_tGetIndex1(CFixedVector2D pos)251 u32 GetIndex1(CFixedVector2D pos) 354 252 { 355 253 return GetI1(pos.X) + GetJ1(pos.Y)*m_DivisionsW; 356 254 } 255 256 entity_pos_t m_DivisionSize; 257 std::vector<std::vector<T> > m_Divisions; 258 u32 m_DivisionsW; 259 u32 m_DivisionsH; 260 261 template<typename ELEM> friend struct SerializeSpatialSubdivision; 357 262 }; 358 263 359 264 /** 360 265 * Serialization helper template for SpatialSubdivision 361 266 */ 267 template<typename ELEM> 362 268 struct SerializeSpatialSubdivision 363 269 { 364 void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision& value) 270 template<typename T> 271 void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value) 365 272 { 366 273 serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize); 274 SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions); 367 275 serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW); 368 276 serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH); 369 370 size_t count = value.m_DivisionsH * value.m_DivisionsW;371 for (size_t i = 0; i < count; ++i)372 SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items);373 277 } 374 278 375 void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision& value) 279 template<typename T> 280 void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value) 376 281 { 377 282 serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize); 378 serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW); 379 serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH); 283 SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions); 380 284 381 size_t count = value.m_DivisionsW * value.m_DivisionsH; 382 value.Create(count); 383 for (size_t i = 0; i < count; ++i) 384 SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items); 285 u32 w, h; 286 serialize.NumberU32_Unbounded("divs w", w); 287 serialize.NumberU32_Unbounded("divs h", h); 288 value.m_DivisionsW = w; 289 value.m_DivisionsH = h; 385 290 } 386 291 }; 387 292 -
deleted file source/simulation2/system/EntityMap.h
diff --git a/source/simulation2/system/EntityMap.h b/source/simulation2/system/EntityMap.h deleted file mode 100644 index 98b0ebe..0000000
+ - 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 modify5 * it under the terms of the GNU General Public License as published by6 * the Free Software Foundation, either version 2 of the License, or7 * (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 of11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12 * GNU General Public License for more details.13 *14 * You should have received a copy of the GNU General Public License15 * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>.16 */17 #ifndef INCLUDED_ENTITYMAP18 #define INCLUDED_ENTITYMAP19 20 #include "Entity.h"21 22 /**23 * A fast replacement for map<entity_id_t, T>.24 * We make the following assumptions:25 * - entity id's (keys) are unique26 * - modifications (add / delete) are far less frequent then look-ups27 * - preformance for iteration is important28 */29 template<class T> class EntityMap30 {31 private:32 EntityMap(const EntityMap&); // non-copyable33 EntityMap& operator=(const EntityMap&); // non-copyable34 35 public:36 typedef entity_id_t key_type;37 typedef T mapped_type;38 template<class K, class V> struct key_val {39 typedef K first_type;40 typedef V second_type;41 K first;42 V second;43 };44 typedef key_val<entity_id_t, T> value_type;45 46 private:47 size_t m_BufferSize; // number of elements in the buffer48 size_t m_BufferCapacity; // capacity of the buffer49 value_type* m_Buffer; // vector with all the mapped key-value pairs50 51 size_t m_Count; // number of 'valid' entity id's52 53 public:54 55 inline EntityMap() : m_BufferSize(1), m_BufferCapacity(4096), m_Count(0)56 {57 // for entitymap we allocate the buffer right away58 // with first element in buffer being the Invalid Entity59 m_Buffer = (value_type*)malloc(sizeof(value_type) * (m_BufferCapacity + 1));60 61 // create the first element:62 m_Buffer[0].first = INVALID_ENTITY;63 m_Buffer[1].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF64 }65 inline ~EntityMap()66 {67 free(m_Buffer);68 }69 70 // Iterators71 template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U>72 {73 U* val;74 inline _iter(U* init) : val(init) {}75 inline U& operator*() { return *val; }76 inline U* operator->() { return val; }77 inline _iter& operator++() // ++it78 {79 ++val;80 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities81 return *this;82 }83 inline _iter& operator++(int) // it++84 {85 U* ptr = val;86 ++val;87 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities88 return ptr;89 }90 inline bool operator==(_iter other) { return val == other.val; }91 inline bool operator!=(_iter other) { return val != other.val; }92 inline operator _iter<U const>() const { return _iter<U const>(val); }93 };94 95 typedef _iter<value_type> iterator;96 typedef _iter<value_type const> const_iterator;97 98 inline iterator begin()99 {100 value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY101 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities102 return ptr;103 }104 inline iterator end()105 {106 return iterator(m_Buffer + m_BufferSize);107 }108 inline const_iterator begin() const109 {110 value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY111 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities112 return ptr;113 }114 inline const_iterator end() const115 {116 return const_iterator(m_Buffer + m_BufferSize);117 }118 119 // Size120 inline bool empty() const { return m_Count == 0; }121 inline size_t size() const { return m_Count; }122 123 // Modification124 void insert(const key_type key, const mapped_type& value)125 {126 if (key >= m_BufferCapacity) // do we need to resize buffer?127 {128 size_t newCapacity = m_BufferCapacity + 4096;129 while (key >= newCapacity) newCapacity += 4096;130 // always allocate +1 behind the scenes, because end() must have a 0xFFFFFFFF key131 value_type* mem = (value_type*)realloc(m_Buffer, sizeof(value_type) * (newCapacity + 1));132 if (!mem)133 {134 debug_warn("EntityMap::insert() realloc failed! Out of memory.");135 throw std::bad_alloc(); // fail to expand and insert136 }137 m_BufferCapacity = newCapacity;138 m_Buffer = mem;139 goto fill_gaps;140 }141 else if (key > m_BufferSize) // weird insert far beyond the end142 {143 fill_gaps:144 // set all entity id's to INVALID_ENTITY inside the new range145 for (size_t i = m_BufferSize; i <= key; ++i)146 m_Buffer[i].first = INVALID_ENTITY;147 m_BufferSize = key; // extend the new size148 }149 150 value_type& item = m_Buffer[key];151 key_type oldKey = item.first;152 item.first = key;153 if (key == m_BufferSize) // push_back154 {155 ++m_BufferSize; // expand156 ++m_Count;157 new (&item.second) mapped_type(value); // copy ctor to init158 m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF159 }160 else if(!item.first) // insert new to middle161 {162 ++m_Count;163 new (&item.second) mapped_type(value); // copy ctor to init164 }165 else // set existing value166 {167 if (oldKey == INVALID_ENTITY)168 m_Count++;169 item.second = value; // overwrite existing170 }171 }172 173 void erase(iterator it)174 {175 value_type* ptr = it.val;176 if (ptr->first != INVALID_ENTITY)177 {178 ptr->first = INVALID_ENTITY;179 ptr->second.~T(); // call dtor180 --m_Count;181 }182 }183 void erase(const entity_id_t key)184 {185 if (key < m_BufferSize)186 {187 value_type* ptr = m_Buffer + key;188 if (ptr->first != INVALID_ENTITY)189 {190 ptr->first = INVALID_ENTITY;191 ptr->second.~T(); // call dtor192 --m_Count;193 }194 }195 }196 inline void clear()197 {198 // orphan whole range199 value_type* ptr = m_Buffer;200 value_type* end = m_Buffer + m_BufferSize;201 for (; ptr != end; ++ptr)202 {203 if (ptr->first != INVALID_ENTITY)204 {205 ptr->first = INVALID_ENTITY;206 ptr->second.~T(); // call dtor207 }208 }209 m_Count = 0; // no more valid entities210 }211 212 // Operations213 inline iterator find(const entity_id_t key)214 {215 if (key < m_BufferSize) // is this key in the range of existing entitites?216 {217 value_type* ptr = m_Buffer + key;218 if (ptr->first != INVALID_ENTITY)219 return ptr;220 }221 return m_Buffer + m_BufferSize; // return iterator end()222 }223 inline const_iterator find(const entity_id_t key) const224 {225 if (key < m_BufferSize) // is this key in the range of existing entitites?226 {227 const value_type* ptr = m_Buffer + key;228 if (ptr->first != INVALID_ENTITY)229 return ptr;230 }231 return m_Buffer + m_BufferSize; // return iterator end()232 }233 inline size_t count(const entity_id_t key) const234 {235 if (key < m_BufferSize)236 {237 if (m_Buffer[key].first != INVALID_ENTITY)238 return 1;239 }240 return 0;241 }242 };243 244 template<class VSerializer>245 struct SerializeEntityMap246 {247 template<class V>248 void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap<V>& value)249 {250 size_t len = value.size();251 serialize.NumberU32_Unbounded("length", (u32)len);252 size_t count = 0;253 for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it)254 {255 serialize.NumberU32_Unbounded("key", it->first);256 VSerializer()(serialize, "value", it->second);257 count++;258 }259 // test to see if the entityMap count wasn't wrong260 // (which causes a crashing deserialisation)261 ENSURE(count == len);262 }263 264 template<class V>265 void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap<V>& value)266 {267 value.clear();268 uint32_t len;269 deserialize.NumberU32_Unbounded("length", len);270 for (size_t i = 0; i < len; ++i)271 {272 entity_id_t k;273 V v;274 deserialize.NumberU32_Unbounded("key", k);275 VSerializer()(deserialize, "value", v);276 value.insert(k, v);277 }278 }279 };280 281 282 #endif -
source/simulation2/system/SimContext.cpp
diff --git a/source/simulation2/system/SimContext.cpp b/source/simulation2/system/SimContext.cpp index 33cbb68..e5a84b2 100644
a b CSimContext::~CSimContext() 34 34 35 35 CComponentManager& CSimContext::GetComponentManager() const 36 36 { 37 ENSURE(m_ComponentManager); 37 38 return *m_ComponentManager; 38 39 } 39 40