Ticket #1707: RangeManagerEntityMap.patch
File RangeManagerEntityMap.patch, 41.8 KB (added by , 11 years ago) |
---|
-
lib/ps_stl.h
1 /* Copyright (c) 2013 Wildfire Games 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining 4 * a copy of this software and associated documentation files (the 5 * "Software"), to deal in the Software without restriction, including 6 * without limitation the rights to use, copy, modify, merge, publish, 7 * distribute, sublicense, and/or sell copies of the Software, and to 8 * permit persons to whom the Software is furnished to do so, subject to 9 * the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included 12 * 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 OF 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 */ 22 #ifndef INCLUDED_PS_STL 23 #define INCLUDED_PS_STL 24 25 /** 26 * @author Jorma Rebane 27 * @note Pyrogenesis STL methods 28 * @note This file contains useful and optimized methods for use with STL 29 */ 30 31 namespace ps 32 { 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 container 78 * @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 ps 100 101 #endif // INCLUDED_PS_STL 102 No newline at end of file -
simulation2/components/CCmpObstructionManager.cpp
124 124 bool m_DebugOverlayDirty; 125 125 std::vector<SOverlayLine> m_DebugOverlayLines; 126 126 127 SpatialSubdivision <u32>m_UnitSubdivision;128 SpatialSubdivision <u32>m_StaticSubdivision;127 SpatialSubdivision m_UnitSubdivision; 128 SpatialSubdivision 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; … … 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 ), entity_pos_t::FromInt(1));164 ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024)); 165 165 } 166 166 167 167 virtual void Deinit() … … 171 171 template<typename S> 172 172 void SerializeCommon(S& serialize) 173 173 { 174 SerializeSpatialSubdivision <SerializeU32_Unbounded>()(serialize, "unit subdiv", m_UnitSubdivision);175 SerializeSpatialSubdivision <SerializeU32_Unbounded>()(serialize, "static subdiv", m_StaticSubdivision);174 SerializeSpatialSubdivision()(serialize, "unit subdiv", m_UnitSubdivision); 175 SerializeSpatialSubdivision()(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); … … 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 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(posMin, posMax); 548 for (size_t i = 0; i < unitShapes.size(); ++i) 547 SpatialQueryArray unitShapes; 548 m_UnitSubdivision.GetInRange(unitShapes, posMin, posMax); 549 for (int i = 0; i < unitShapes.size(); ++i) 549 550 { 550 551 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); 551 552 ENSURE(it != m_UnitShapes.end()); … … 559 560 return true; 560 561 } 561 562 562 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(posMin, posMax); 563 for (size_t i = 0; i < staticShapes.size(); ++i) 563 SpatialQueryArray staticShapes; 564 m_StaticSubdivision.GetInRange(staticShapes, posMin, posMax); 565 for (int i = 0; i < staticShapes.size(); ++i) 564 566 { 565 567 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); 566 568 ENSURE(it != m_StaticShapes.end()); … … 880 882 881 883 ENSURE(x0 <= x1 && z0 <= z1); 882 884 883 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 884 for (size_t i = 0; i < unitShapes.size(); ++i) 885 SpatialQueryArray unitShapes; 886 m_UnitSubdivision.GetInRange(unitShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 887 for (int i = 0; i < unitShapes.size(); ++i) 885 888 { 886 889 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); 887 890 ENSURE(it != m_UnitShapes.end()); … … 901 904 squares.push_back(s); 902 905 } 903 906 904 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 905 for (size_t i = 0; i < staticShapes.size(); ++i) 907 SpatialQueryArray staticShapes; 908 m_StaticSubdivision.GetInRange(staticShapes, CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 909 for (int i = 0; i < staticShapes.size(); ++i) 906 910 { 907 911 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); 908 912 ENSURE(it != m_StaticShapes.end()); -
simulation2/components/CCmpRangeManager.cpp
21 21 #include "ICmpRangeManager.h" 22 22 23 23 #include "ICmpTerrain.h" 24 #include "simulation2/system/EntityMap.h" 24 25 #include "simulation2/MessageTypes.h" 25 26 #include "simulation2/components/ICmpPosition.h" 26 27 #include "simulation2/components/ICmpTerritoryManager.h" … … 37 38 #include "ps/Overlay.h" 38 39 #include "ps/Profile.h" 39 40 #include "renderer/Scene.h" 41 #include "lib/ps_stl.h" 40 42 43 41 44 #define DEBUG_RANGE_MANAGER_BOUNDS 0 42 45 43 46 /** … … 61 64 * Convert an owner ID (-1 = unowned, 0 = gaia, 1..30 = players) 62 65 * into a 32-bit mask for quick set-membership tests. 63 66 */ 64 static u32 CalcOwnerMask(player_id_t owner)67 static inline u32 CalcOwnerMask(player_id_t owner) 65 68 { 66 69 if (owner >= -1 && owner < 31) 67 70 return 1 << (1+owner); … … 72 75 /** 73 76 * Returns LOS mask for given player. 74 77 */ 75 static u32 CalcPlayerLosMask(player_id_t player)78 static inline u32 CalcPlayerLosMask(player_id_t player) 76 79 { 77 80 if (player > 0 && player <= 16) 78 81 return ICmpRangeManager::LOS_MASK << (2*(player-1)); … … 210 213 */ 211 214 struct EntityDistanceOrdering 212 215 { 213 EntityDistanceOrdering(const std::map<entity_id_t,EntityData>& entities, const CFixedVector2D& source) :216 EntityDistanceOrdering(const EntityMap<EntityData>& entities, const CFixedVector2D& source) : 214 217 m_EntityData(entities), m_Source(source) 215 218 { 216 219 } … … 224 227 return (vecA.CompareLength(vecB) < 0); 225 228 } 226 229 227 const std::map<entity_id_t,EntityData>& m_EntityData;230 const EntityMap<EntityData>& m_EntityData; 228 231 CFixedVector2D m_Source; 229 232 230 233 private: … … 271 274 // Range query state: 272 275 tag_t m_QueryNext; // next allocated id 273 276 std::map<tag_t, Query> m_Queries; 274 std::map<entity_id_t, EntityData> m_EntityData; 275 SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData 277 EntityMap<EntityData> m_EntityData; 276 278 279 SpatialSubdivision m_Subdivision; // spatial index of m_EntityData 280 277 281 // LOS state: 278 282 279 283 std::map<player_id_t, bool> m_LosRevealAll; … … 319 323 320 324 // Initialise with bogus values (these will get replaced when 321 325 // SetBounds is called) 322 ResetSubdivisions(entity_pos_t::FromInt(1 ), entity_pos_t::FromInt(1));326 ResetSubdivisions(entity_pos_t::FromInt(1024), entity_pos_t::FromInt(1024)); 323 327 324 328 // The whole map should be visible to Gaia by default, else e.g. animals 325 329 // will get confused when trying to run from enemies … … 349 353 350 354 serialize.NumberU32_Unbounded("query next", m_QueryNext); 351 355 SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries, GetSimContext()); 352 Serialize Map<SerializeU32_Unbounded,SerializeEntityData>()(serialize, "entity data", m_EntityData);356 SerializeEntityMap<SerializeEntityData>()(serialize, "entity data", m_EntityData); 353 357 354 358 SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll); 355 359 serialize.Bool("los circular", m_LosCircular); … … 411 415 } 412 416 413 417 // Remember this entity 414 m_EntityData.insert(std::make_pair(ent, entdata)); 415 418 m_EntityData.insert(ent, entdata); 416 419 break; 417 420 } 418 421 case MT_PositionChanged: … … 420 423 const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg); 421 424 entity_id_t ent = msgData.entity; 422 425 423 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);426 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 424 427 425 428 // Ignore if we're not already tracking this entity 426 429 if (it == m_EntityData.end()) … … 467 470 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 468 471 entity_id_t ent = msgData.entity; 469 472 470 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);473 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 471 474 472 475 // Ignore if we're not already tracking this entity 473 476 if (it == m_EntityData.end()) … … 490 493 const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg); 491 494 entity_id_t ent = msgData.entity; 492 495 493 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);496 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 494 497 495 498 // Ignore if we're not already tracking this entity 496 499 if (it == m_EntityData.end()) … … 512 515 const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg); 513 516 entity_id_t ent = msgData.entity; 514 517 515 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);518 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 516 519 517 520 // Ignore if we're not already tracking this entity 518 521 if (it == m_EntityData.end()) … … 576 579 577 580 std::vector<std::vector<u16> > oldPlayerCounts = m_LosPlayerCounts; 578 581 std::vector<u32> oldStateRevealed = m_LosStateRevealed; 579 SpatialSubdivision <entity_id_t>oldSubdivision = m_Subdivision;582 SpatialSubdivision oldSubdivision = m_Subdivision; 580 583 581 584 ResetDerivedData(true); 582 585 … … 637 640 m_LosStateRevealed.clear(); 638 641 m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide); 639 642 640 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)643 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 641 644 { 642 645 if (it->second.inWorld) 643 646 LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z)); … … 663 666 // (TODO: find the optimal number instead of blindly guessing) 664 667 m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); 665 668 666 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)669 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 667 670 { 668 671 if (it->second.inWorld) 669 672 m_Subdivision.Add(it->first, CFixedVector2D(it->second.x, it->second.z)); … … 794 797 795 798 u32 ownerMask = CalcOwnerMask(player); 796 799 797 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)800 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 798 801 { 799 802 // Check owner and add to list if it matches 800 803 if (CalcOwnerMask(it->second.owner) & ownerMask) … … 822 825 // Store a queue of all messages before sending any, so we can assume 823 826 // no entities will move until we've finished checking all the ranges 824 827 std::vector<std::pair<entity_id_t, CMessageRangeUpdate> > messages; 828 std::vector<entity_id_t> results; 829 std::vector<entity_id_t> added; 830 std::vector<entity_id_t> removed; 825 831 826 832 for (std::map<tag_t, Query>::iterator it = m_Queries.begin(); it != m_Queries.end(); ++it) 827 833 { 828 Query& q = it->second;834 Query& query = it->second; 829 835 830 if (!q .enabled)836 if (!query.enabled) 831 837 continue; 832 838 833 CmpPtr<ICmpPosition> cmpSourcePosition(q .source);839 CmpPtr<ICmpPosition> cmpSourcePosition(query.source); 834 840 if (!cmpSourcePosition || !cmpSourcePosition->IsInWorld()) 835 841 continue; 836 842 837 std::vector<entity_id_t> r; 838 r.reserve(q.lastMatch.size()); 843 results.clear(); 844 results.reserve(query.lastMatch.size()); 845 PerformQuery(query, results); 839 846 840 PerformQuery(q, r);841 842 847 // Compute the changes vs the last match 843 std::vector<entity_id_t> added;844 std::vector<entity_id_t> removed;845 s td::set_difference(r.begin(), r.end(), q.lastMatch.begin(), q.lastMatch.end(), std::back_inserter(added));846 s td::set_difference(q.lastMatch.begin(), q.lastMatch.end(), r.begin(), r.end(), std::back_inserter(removed));848 added.clear(); 849 removed.clear(); 850 size_t resultsSize = results.size(); 851 size_t lastMatchSize = query.lastMatch.size(); 847 852 853 // check results for any new ones: 854 for (size_t i = 0; i < resultsSize; ++i) 855 { 856 entity_id_t entity = results[i]; 857 if (ps::exists_in(query.lastMatch, entity) == false) 858 added.push_back(entity); // not in last matches, so it's NEW 859 } 860 // check last matches for any missing ones: 861 for (size_t i = 0; i < lastMatchSize; ++i) 862 { 863 entity_id_t entity = query.lastMatch[i]; 864 if (ps::exists_in(results, entity) == false) 865 removed.push_back(entity); // not in results, so it's moved out of range 866 } 848 867 if (added.empty() && removed.empty()) 849 868 continue; 850 869 851 870 // Return the 'added' list sorted by distance from the entity 852 871 // (Don't bother sorting 'removed' because they might not even have positions or exist any more) 853 CFixedVector2D pos = cmpSourcePosition->GetPosition2D(); 854 std::stable_sort(added.begin(), added.end(), EntityDistanceOrdering(m_EntityData, pos)); 872 if (!added.empty()) 873 { 874 CFixedVector2D pos = cmpSourcePosition->GetPosition2D(); 875 std::stable_sort(&added[0], &added[0] + added.size(), EntityDistanceOrdering(m_EntityData, pos)); 876 } 855 877 856 messages.push_back(std::make_pair(q.source.GetId(), CMessageRangeUpdate(it->first))); 857 messages.back().second.added.swap(added); 858 messages.back().second.removed.swap(removed); 859 860 it->second.lastMatch.swap(r); 878 messages.resize(messages.size() + 1); 879 std::pair<entity_id_t, CMessageRangeUpdate>& back = messages.back(); 880 back.first = query.source.GetId(); 881 back.second.tag = it->first; 882 back.second.added.swap(added); 883 back.second.removed.swap(removed); 884 it->second.lastMatch.swap(results); 861 885 } 862 886 887 CComponentManager& cmpMgr = GetSimContext().GetComponentManager(); 863 888 for (size_t i = 0; i < messages.size(); ++i) 864 GetSimContext().GetComponentManager().PostMessage(messages[i].first, messages[i].second);889 cmpMgr.PostMessage(messages[i].first, messages[i].second); 865 890 } 866 891 867 892 /** … … 905 930 // Special case: range -1.0 means check all entities ignoring distance 906 931 if (q.maxRange == entity_pos_t::FromInt(-1)) 907 932 { 908 for ( std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)933 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 909 934 { 910 935 if (!TestEntityQuery(q, it->first, it->second)) 911 936 continue; … … 920 945 CFixedVector3D pos3d = cmpSourcePosition->GetPosition()+ 921 946 CFixedVector3D(entity_pos_t::Zero(), q.elevationBonus, entity_pos_t::Zero()) ; 922 947 // Get a quick list of entities that are potentially in range, with a cutoff of 2*maxRange 923 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange*2); 948 SpatialQueryArray ents; 949 m_Subdivision.GetNear(ents, pos, q.maxRange*2); 924 950 925 for ( size_t i = 0; i < ents.size(); ++i)951 for (int i = 0; i < ents.size(); ++i) 926 952 { 927 std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.find(ents[i]);953 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]); 928 954 ENSURE(it != m_EntityData.end()); 929 955 930 956 if (!TestEntityQuery(q, it->first, it->second)) … … 950 976 } 951 977 952 978 r.push_back(it->first); 953 954 979 } 955 980 } 956 981 // check a regular range (i.e. not the entire world, and not parabolic) … … 957 982 else 958 983 { 959 984 // Get a quick list of entities that are potentially in range 960 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange); 961 962 for (size_t i = 0; i < ents.size(); ++i) 985 SpatialQueryArray ents; 986 m_Subdivision.GetNear(ents, pos, q.maxRange); 987 988 for (int i = 0; i < ents.size(); ++i) 963 989 { 964 std::map<entity_id_t,EntityData>::const_iterator it = m_EntityData.find(ents[i]);990 EntityMap<EntityData>::const_iterator it = m_EntityData.find(ents[i]); 965 991 ENSURE(it != m_EntityData.end()); 966 992 967 993 if (!TestEntityQuery(q, it->first, it->second)) … … 980 1006 } 981 1007 982 1008 r.push_back(it->first); 983 984 1009 } 985 1010 } 986 1011 } … … 1135 1160 { 1136 1161 if (!m_DebugOverlayEnabled) 1137 1162 return; 1138 CColor enabledRingColour(0, 1, 0, 1); 1139 CColor disabledRingColour(1, 0, 0, 1); 1140 CColor rayColour(1, 1, 0, 0.2f); 1163 static CColor disabledRingColour(1, 0, 0, 1); // red 1164 static CColor enabledRingColour(0, 1, 0, 1); // green 1165 static CColor subdivColour(0, 0, 1, 1); // blue 1166 static CColor rayColour(1, 1, 0, 0.2f); 1141 1167 1142 1168 if (m_DebugOverlayDirty) 1143 1169 { … … 1244 1270 } 1245 1271 } 1246 1272 1273 // render subdivision grid 1274 float divSize = m_Subdivision.GetDivisionSize().ToFloat(); 1275 int width = m_Subdivision.GetWidth(); 1276 int height = m_Subdivision.GetHeight(); 1277 for (int x = 0; x < width; ++x) 1278 { 1279 for (int y = 0; y < height; ++y) 1280 { 1281 m_DebugOverlayLines.push_back(SOverlayLine()); 1282 m_DebugOverlayLines.back().m_Color = subdivColour; 1283 1284 float xpos = x*divSize + divSize/2; 1285 float zpos = y*divSize + divSize/2; 1286 SimRender::ConstructSquareOnGround(GetSimContext(), xpos, zpos, divSize, divSize, 0.0f, 1287 m_DebugOverlayLines.back(), false, 1.0f); 1288 } 1289 } 1290 1247 1291 m_DebugOverlayDirty = false; 1248 1292 } 1249 1293 … … 1264 1308 1265 1309 virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value) 1266 1310 { 1267 std::map<entity_id_t,EntityData>::iterator it = m_EntityData.find(ent);1311 EntityMap<EntityData>::iterator it = m_EntityData.find(ent); 1268 1312 1269 1313 // We don't have this entity 1270 1314 if (it == m_EntityData.end()) -
simulation2/helpers/Spatial.h
21 21 #include "simulation2/serialization/SerializeTemplates.h" 22 22 23 23 /** 24 * A simple fixed-size array that works similar to an std::vector 25 * but is obviously limited in its max items 26 */ 27 struct SpatialQueryArray 28 { 29 enum { MAX_COUNT = 1024 }; 30 int count; 31 uint32_t items[MAX_COUNT]; 32 33 inline SpatialQueryArray() : count(0) {} 34 inline const uint32_t& operator[](int index) const { return items[index]; } 35 inline uint32_t& operator[](int index) { return items[index]; } 36 inline int size() const { return count; } 37 inline void clear() { count = 0; } 38 void make_unique() // removes any duplicate entries 39 { 40 if (count) 41 count = int(std::unique(items, items + count) - items); 42 } 43 }; 44 45 /** 24 46 * A very basic subdivision scheme for finding items in ranges. 25 47 * Items are stored in lists in fixed-size divisions. 26 48 * Items have a size (min/max values of their axis-aligned bounding box) … … 34 56 * 35 57 * (TODO: maybe an adaptive quadtree would be better than fixed sizes?) 36 58 */ 37 template<typename T>38 59 class SpatialSubdivision 39 60 { 61 struct SubDivisionGrid 62 { 63 std::vector<uint32_t> items; 64 65 inline void push_back(uint32_t value) 66 { 67 items.push_back(value); 68 } 69 70 inline void erase(int index) 71 { 72 // Delete by swapping with the last element then popping 73 if ((int)items.size() > 1) // but only if we have more than 1 elements 74 items[index] = items.back(); 75 items.pop_back(); 76 } 77 78 void copy_items(SpatialQueryArray& out) 79 { 80 if (items.empty()) 81 return; // nothing to copy 82 83 int dsti = out.count; // the index in [out] where to start copying 84 int count = (int)items.size(); 85 if ((dsti + count) > SpatialQueryArray::MAX_COUNT) 86 count = SpatialQueryArray::MAX_COUNT - dsti; // silently fail to copy overflowing items 87 uint32_t* dst = &out.items[dsti]; 88 uint32_t* src = &items[0]; 89 for (int i = 0; i < count; ++i) // copy all items 90 dst[i] = src[i]; 91 out.count += count; 92 } 93 }; 94 95 96 entity_pos_t m_DivisionSize; 97 SubDivisionGrid* m_Divisions; 98 uint32_t m_DivisionsW; 99 uint32_t m_DivisionsH; 100 101 friend struct SerializeSubDivisionGrid; 102 friend struct SerializeSpatialSubdivision; 103 40 104 public: 41 SpatialSubdivision() : 42 m_DivisionsW(0), m_DivisionsH(0) 105 SpatialSubdivision() : m_Divisions(NULL), m_DivisionsW(0), m_DivisionsH(0) 43 106 { 44 107 } 108 ~SpatialSubdivision() 109 { 110 delete[] m_Divisions; 111 } 112 SpatialSubdivision(const SpatialSubdivision& rhs) 113 { 114 m_DivisionSize = rhs.m_DivisionSize; 115 m_DivisionsW = rhs.m_DivisionsW; 116 m_DivisionsH = rhs.m_DivisionsH; 117 size_t n = m_DivisionsW * m_DivisionsH; 118 m_Divisions = new SubDivisionGrid[n]; 119 for (size_t i = 0; i < n; ++i) 120 m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy 121 } 122 SpatialSubdivision& operator=(const SpatialSubdivision& rhs) 123 { 124 if (this != &rhs) 125 { 126 m_DivisionSize = rhs.m_DivisionSize; 127 size_t n = rhs.m_DivisionsW * rhs.m_DivisionsH; 128 if (m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH) 129 Create(n); // size changed, recreate 130 131 m_DivisionsW = rhs.m_DivisionsW; 132 m_DivisionsH = rhs.m_DivisionsH; 133 for (size_t i = 0; i < n; ++i) 134 m_Divisions[i] = rhs.m_Divisions[i]; // just fall back to piecemeal copy 135 } 136 return *this; 137 } 45 138 139 inline entity_pos_t GetDivisionSize() const { return m_DivisionSize; } 140 inline uint32_t GetWidth() const { return m_DivisionsW; } 141 inline uint32_t GetHeight() const { return m_DivisionsH; } 142 143 void Create(size_t count) 144 { 145 if (m_Divisions) delete[] m_Divisions; 146 m_Divisions = new SubDivisionGrid[count]; 147 } 148 46 149 /** 47 150 * Equivalence test (ignoring order of items within each subdivision) 48 151 */ … … 51 154 if (m_DivisionSize != rhs.m_DivisionSize || m_DivisionsW != rhs.m_DivisionsW || m_DivisionsH != rhs.m_DivisionsH) 52 155 return false; 53 156 54 for (u32 j = 0; j < m_DivisionsH; ++j) 157 uint32_t n = m_DivisionsH * m_DivisionsW; 158 for (uint32_t i = 0; i < n; ++i) 55 159 { 56 for (u32 i = 0; i < m_DivisionsW; ++i) 57 { 58 std::vector<T> div1 = m_Divisions.at(i + j*m_DivisionsW); 59 std::vector<T> div2 = rhs.m_Divisions.at(i + j*m_DivisionsW); 60 std::sort(div1.begin(), div1.end()); 61 std::sort(div2.begin(), div2.end()); 62 if (div1 != div2) 63 return false; 64 } 160 if (m_Divisions[i].items.size() != rhs.m_Divisions[i].items.size()) 161 return false; 162 163 // don't bother optimizing this, this is only used in the TESTING SUITE 164 std::vector<uint32_t> a = m_Divisions[i].items; 165 std::vector<uint32_t> b = rhs.m_Divisions[i].items; 166 std::sort(a.begin(), a.end()); 167 std::sort(b.begin(), b.end()); 168 if (a != b) 169 return false; 65 170 } 66 67 171 return true; 68 172 } 69 173 70 bool operator!=(const SpatialSubdivision& rhs)174 inline bool operator!=(const SpatialSubdivision& rhs) 71 175 { 72 176 return !(*this == rhs); 73 177 } … … 77 181 m_DivisionSize = divisionSize; 78 182 m_DivisionsW = (maxX / m_DivisionSize).ToInt_RoundToInfinity(); 79 183 m_DivisionsH = (maxZ / m_DivisionSize).ToInt_RoundToInfinity(); 80 m_Divisions.clear(); 81 m_Divisions.resize(m_DivisionsW * m_DivisionsH);184 185 Create(m_DivisionsW * m_DivisionsH); 82 186 } 83 187 188 84 189 /** 85 190 * Add an item with the given 'to' size. 86 191 * The item must not already be present. 87 192 */ 88 void Add( Titem, CFixedVector2D toMin, CFixedVector2D toMax)193 void Add(uint32_t item, CFixedVector2D toMin, CFixedVector2D toMax) 89 194 { 90 195 ENSURE(toMin.X <= toMax.X && toMin.Y <= toMax.Y); 91 196 … … 97 202 { 98 203 for (u32 i = i0; i <= i1; ++i) 99 204 { 100 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW); 101 div.push_back(item); 205 m_Divisions[i + j*m_DivisionsW].push_back(item); 102 206 } 103 207 } 104 208 } … … 108 212 * The item should already be present. 109 213 * The size must match the size that was last used when adding the item. 110 214 */ 111 void Remove( Titem, CFixedVector2D fromMin, CFixedVector2D fromMax)215 void Remove(uint32_t item, CFixedVector2D fromMin, CFixedVector2D fromMax) 112 216 { 113 217 ENSURE(fromMin.X <= fromMax.X && fromMin.Y <= fromMax.Y); 114 218 … … 120 224 { 121 225 for (u32 i = i0; i <= i1; ++i) 122 226 { 123 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW);124 125 for ( u32 n = 0; n < div.size(); ++n)227 SubDivisionGrid& div = m_Divisions[i + j*m_DivisionsW]; 228 int size = div.items.size(); 229 for (int n = 0; n < size; ++n) 126 230 { 127 if (div [n] == item)231 if (div.items[n] == item) 128 232 { 129 // Delete by swapping with the last element then popping 130 div[n] = div.back(); 131 div.pop_back(); 233 div.erase(n); 132 234 break; 133 235 } 134 236 } … … 139 241 /** 140 242 * Equivalent to Remove() then Add(), but potentially faster. 141 243 */ 142 void Move( Titem, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax)244 void Move(uint32_t item, CFixedVector2D fromMin, CFixedVector2D fromMax, CFixedVector2D toMin, CFixedVector2D toMax) 143 245 { 144 246 // Skip the work if we're staying in the same divisions 145 247 if (GetIndex0(fromMin) == GetIndex0(toMin) && GetIndex1(fromMax) == GetIndex1(toMax)) … … 153 255 * Convenience function for Add() of individual points. 154 256 * (Note that points on a boundary may occupy multiple divisions.) 155 257 */ 156 void Add( Titem, CFixedVector2D to)258 void Add(uint32_t item, CFixedVector2D to) 157 259 { 158 260 Add(item, to, to); 159 261 } … … 161 263 /** 162 264 * Convenience function for Remove() of individual points. 163 265 */ 164 void Remove( Titem, CFixedVector2D from)266 void Remove(uint32_t item, CFixedVector2D from) 165 267 { 166 268 Remove(item, from, from); 167 269 } … … 169 271 /** 170 272 * Convenience function for Move() of individual points. 171 273 */ 172 void Move( Titem, CFixedVector2D from, CFixedVector2D to)274 void Move(uint32_t item, CFixedVector2D from, CFixedVector2D to) 173 275 { 174 276 Move(item, from, from, to, to); 175 277 } … … 178 280 * Returns a sorted list of unique items that includes all items 179 281 * within the given axis-aligned square range. 180 282 */ 181 std::vector<T> GetInRange(CFixedVector2D posMin, CFixedVector2D posMax)283 void GetInRange(SpatialQueryArray& out, CFixedVector2D posMin, CFixedVector2D posMax) 182 284 { 183 std::vector<T> ret; 184 285 out.clear(); 185 286 ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y); 186 287 187 288 u32 i0 = GetI0(posMin.X); … … 192 293 { 193 294 for (u32 i = i0; i <= i1; ++i) 194 295 { 195 std::vector<T>& div = m_Divisions.at(i + j*m_DivisionsW); 196 ret.insert(ret.end(), div.begin(), div.end()); 296 m_Divisions[i + j*m_DivisionsW].copy_items(out); 197 297 } 198 298 } 199 200 // Remove duplicates 201 std::sort(ret.begin(), ret.end()); 202 ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); 203 204 return ret; 299 // some buildings span several tiles, so we need to make it unique 300 out.make_unique(); 205 301 } 206 302 207 303 /** … … 208 304 * Returns a sorted list of unique items that includes all items 209 305 * within the given circular distance of the given point. 210 306 */ 211 std::vector<T> GetNear(CFixedVector2D pos, entity_pos_t range)307 void GetNear(SpatialQueryArray& out, CFixedVector2D pos, entity_pos_t range) 212 308 { 213 309 // TODO: be cleverer and return a circular pattern of divisions, 214 310 // not this square over-approximation 215 216 return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range));311 CFixedVector2D r(range, range); 312 GetInRange(out, pos - r, pos + r); 217 313 } 218 314 219 315 private: … … 221 317 // (avoiding out-of-bounds accesses, and rounding correctly so that 222 318 // points precisely between divisions are counted in both): 223 319 224 u 32GetI0(entity_pos_t x)320 uint32_t GetI0(entity_pos_t x) 225 321 { 226 322 return Clamp((x / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsW-1); 227 323 } 228 324 229 u 32GetJ0(entity_pos_t z)325 uint32_t GetJ0(entity_pos_t z) 230 326 { 231 327 return Clamp((z / m_DivisionSize).ToInt_RoundToInfinity()-1, 0, (int)m_DivisionsH-1); 232 328 } 233 329 234 u 32GetI1(entity_pos_t x)330 uint32_t GetI1(entity_pos_t x) 235 331 { 236 332 return Clamp((x / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsW-1); 237 333 } 238 334 239 u 32GetJ1(entity_pos_t z)335 uint32_t GetJ1(entity_pos_t z) 240 336 { 241 337 return Clamp((z / m_DivisionSize).ToInt_RoundToNegInfinity(), 0, (int)m_DivisionsH-1); 242 338 } 243 339 244 u 32GetIndex0(CFixedVector2D pos)340 uint32_t GetIndex0(CFixedVector2D pos) 245 341 { 246 342 return GetI0(pos.X) + GetJ0(pos.Y)*m_DivisionsW; 247 343 } 248 344 249 u 32GetIndex1(CFixedVector2D pos)345 uint32_t GetIndex1(CFixedVector2D pos) 250 346 { 251 347 return GetI1(pos.X) + GetJ1(pos.Y)*m_DivisionsW; 252 348 } 253 254 entity_pos_t m_DivisionSize;255 std::vector<std::vector<T> > m_Divisions;256 u32 m_DivisionsW;257 u32 m_DivisionsH;258 259 template<typename ELEM> friend struct SerializeSpatialSubdivision;260 349 }; 261 350 262 351 /** 263 352 * Serialization helper template for SpatialSubdivision 264 353 */ 265 template<typename ELEM>266 354 struct SerializeSpatialSubdivision 267 355 { 268 template<typename T> 269 void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value) 356 void operator()(ISerializer& serialize, const char* UNUSED(name), SpatialSubdivision& value) 270 357 { 271 358 serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize); 272 SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions);273 359 serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW); 274 360 serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH); 361 362 size_t count = value.m_DivisionsH * value.m_DivisionsW; 363 for (size_t i = 0; i < count; ++i) 364 SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items); 275 365 } 276 366 277 template<typename T> 278 void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision<T>& value) 367 void operator()(IDeserializer& serialize, const char* UNUSED(name), SpatialSubdivision& value) 279 368 { 280 369 serialize.NumberFixed_Unbounded("div size", value.m_DivisionSize); 281 SerializeVector<SerializeVector<ELEM> >()(serialize, "divs", value.m_Divisions); 370 serialize.NumberU32_Unbounded("divs w", value.m_DivisionsW); 371 serialize.NumberU32_Unbounded("divs h", value.m_DivisionsH); 282 372 283 u32 w, h; 284 serialize.NumberU32_Unbounded("divs w", w); 285 serialize.NumberU32_Unbounded("divs h", h); 286 value.m_DivisionsW = w; 287 value.m_DivisionsH = h; 373 size_t count = value.m_DivisionsW * value.m_DivisionsH; 374 value.Create(count); 375 for (size_t i = 0; i < count; ++i) 376 SerializeVector<SerializeU32_Unbounded>()(serialize, "subdiv items", value.m_Divisions[i].items); 288 377 } 289 378 }; 290 379 -
simulation2/MessageTypes.h
314 314 public: 315 315 DEFAULT_MESSAGE_IMPL(RangeUpdate) 316 316 317 CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed) :318 tag(tag), added(added), removed(removed)319 {320 }321 317 318 322 319 u32 tag; 323 320 std::vector<entity_id_t> added; 324 321 std::vector<entity_id_t> removed; … … 327 324 // swap vectors instead of copying (to save on memory allocations), 328 325 // so add some constructors for it: 329 326 330 CMessageRangeUpdate(u32 tag) :331 tag(tag)327 // don't init tag in empty ctor 328 CMessageRangeUpdate() 332 329 { 333 330 } 334 335 CMessageRangeUpdate(const CMessageRangeUpdate& other) : 336 CMessage(), tag(other.tag), added(other.added), removed(other.removed) 331 CMessageRangeUpdate(u32 tag) : tag(tag) 337 332 { 338 333 } 339 334 CMessageRangeUpdate(u32 tag, const std::vector<entity_id_t>& added, const std::vector<entity_id_t>& removed) 335 : tag(tag), added(added), removed(removed) 336 { 337 } 338 CMessageRangeUpdate(const CMessageRangeUpdate& other) 339 : CMessage(), tag(other.tag), added(other.added), removed(other.removed) 340 { 341 } 340 342 CMessageRangeUpdate& operator=(const CMessageRangeUpdate& other) 341 343 { 342 344 tag = other.tag; -
simulation2/system/EntityMap.h
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 #ifndef INCLUDED_ENTITYMAP 18 #define INCLUDED_ENTITYMAP 19 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 unique and are inserted in increasing order 26 * - an entity id that was removed is never added again 27 * - modifications (add / delete) are far less frequent then look-ups 28 * - preformance for iteration is important 29 */ 30 template<class T> class EntityMap 31 { 32 private: 33 EntityMap(const EntityMap&); // non-copyable 34 EntityMap& operator=(const EntityMap&); // non-copyable 35 36 public: 37 typedef entity_id_t key_type; 38 typedef T mapped_type; 39 template<class K, class V> struct key_val { 40 typedef K first_type; 41 typedef V second_type; 42 K first; 43 V second; 44 }; 45 typedef key_val<entity_id_t, T> value_type; 46 47 private: 48 size_t m_BufferSize; // number of elements in the buffer 49 size_t m_BufferCapacity; // capacity of the buffer 50 value_type* m_Buffer; // vector with all the mapped key-value pairs 51 52 size_t m_Count; // number of 'valid' entity id's 53 54 public: 55 56 inline EntityMap() : m_BufferSize(1), m_BufferCapacity(4096), m_Count(0) 57 { 58 // for entitymap we allocate the buffer right away 59 // with first element in buffer being the Invalid Entity 60 m_Buffer = (value_type*)malloc(sizeof(value_type) * (m_BufferCapacity + 1)); 61 62 // create the first element: 63 m_Buffer[0].first = INVALID_ENTITY; 64 m_Buffer[1].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 65 } 66 inline ~EntityMap() 67 { 68 free(m_Buffer); 69 } 70 71 // Iterators 72 template<class U> struct _iter : public std::iterator<std::forward_iterator_tag, U> 73 { 74 U* val; 75 inline _iter(U* init) : val(init) {} 76 inline U& operator*() { return *val; } 77 inline U* operator->() { return val; } 78 inline _iter& operator++() // ++it 79 { 80 ++val; 81 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities 82 return *this; 83 } 84 inline _iter& operator++(int) // it++ 85 { 86 U* ptr = val; 87 ++val; 88 while (val->first == INVALID_ENTITY) ++val; // skip any invalid entities 89 return ptr; 90 } 91 inline bool operator==(_iter other) { return val == other.val; } 92 inline bool operator!=(_iter other) { return val != other.val; } 93 inline operator _iter<U const>() const { return _iter<U const>(val); } 94 }; 95 96 typedef _iter<value_type> iterator; 97 typedef _iter<value_type const> const_iterator; 98 99 inline iterator begin() 100 { 101 value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY 102 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities 103 return ptr; 104 } 105 inline iterator end() 106 { 107 return iterator(m_Buffer + m_BufferSize); 108 } 109 inline const_iterator begin() const 110 { 111 value_type* ptr = m_Buffer + 1; // skip the first INVALID_ENTITY 112 while (ptr->first == INVALID_ENTITY) ++ptr; // skip any other invalid entities 113 return ptr; 114 } 115 inline const_iterator end() const 116 { 117 return const_iterator(m_Buffer + m_BufferSize); 118 } 119 120 // Size 121 inline bool empty() const { return m_Count == 0; } 122 inline size_t size() const { return m_Count; } 123 124 // Modification 125 void insert(const key_type key, const mapped_type& value) 126 { 127 if (key >= m_BufferCapacity) // do we need to resize buffer? 128 { 129 do { m_BufferCapacity += 4096; } while (key >= m_BufferCapacity); 130 131 // always allocate +1 behind the scenes, because end() must have a 0xFFFFFFFF key 132 m_Buffer = (value_type*)realloc(m_Buffer, sizeof(value_type) * (m_BufferCapacity + 1)); 133 134 goto fill_gaps; 135 } 136 else if (key > m_BufferSize) // weird insert far beyond the end 137 { 138 fill_gaps: 139 // set all entity id's to INVALID_ENTITY inside the new range 140 for (size_t i = m_BufferSize; i <= key; ++i) 141 m_Buffer[i].first = INVALID_ENTITY; 142 m_BufferSize = key; // extend the new size 143 } 144 145 value_type& item = m_Buffer[key]; 146 item.first = key; 147 if (key == m_BufferSize) // push_back 148 { 149 ++m_BufferSize; // expand 150 ++m_Count; 151 new (&item.second) mapped_type(value); // copy ctor to init 152 m_Buffer[m_BufferSize].first = 0xFFFFFFFF; // ensure end() always has 0xFFFFFFFF 153 } 154 else if(!item.first) // insert new to middle 155 { 156 ++m_Count; 157 new (&item.second) mapped_type(value); // copy ctor to init 158 } 159 else // set existing value 160 { 161 item.second = value; // overwrite existing 162 } 163 } 164 165 void erase(iterator it) 166 { 167 value_type* ptr = it.val; 168 if (ptr->first != INVALID_ENTITY) 169 { 170 ptr->first = INVALID_ENTITY; 171 ptr->second.~T(); // call dtor 172 --m_Count; 173 } 174 } 175 void erase(const entity_id_t key) 176 { 177 if (key < m_BufferSize) 178 { 179 value_type* ptr = m_Buffer + key; 180 if (ptr->first != INVALID_ENTITY) 181 { 182 ptr->first = INVALID_ENTITY; 183 ptr->second.~T(); // call dtor 184 --m_Count; 185 } 186 } 187 } 188 inline void clear() 189 { 190 // orphan whole range 191 value_type* ptr = m_Buffer; 192 value_type* end = m_Buffer + m_BufferSize; 193 for (; ptr != end; ++ptr) 194 { 195 if (ptr->first != INVALID_ENTITY) 196 { 197 ptr->first = INVALID_ENTITY; 198 ptr->second.~T(); // call dtor 199 } 200 } 201 m_Count = 0; // no more valid entities 202 } 203 204 // Operations 205 inline iterator find(const entity_id_t key) 206 { 207 if (key < m_BufferSize) // is this key in the range of existing entitites? 208 { 209 value_type* ptr = m_Buffer + key; 210 if (ptr->first != INVALID_ENTITY) 211 return ptr; 212 } 213 return m_Buffer + m_BufferSize; // return iterator end() 214 } 215 inline const_iterator find(const entity_id_t key) const 216 { 217 if (key < m_BufferSize) // is this key in the range of existing entitites? 218 { 219 const value_type* ptr = m_Buffer + key; 220 if (ptr->first != INVALID_ENTITY) 221 return ptr; 222 } 223 return m_Buffer + m_BufferSize; // return iterator end() 224 } 225 inline size_t count(const entity_id_t key) const 226 { 227 if (key < m_BufferSize) 228 { 229 if (m_Buffer[key].first != INVALID_ENTITY) 230 return 1; 231 } 232 return 0; 233 } 234 }; 235 236 template<class VSerializer> 237 struct SerializeEntityMap 238 { 239 template<class V> 240 void operator()(ISerializer& serialize, const char* UNUSED(name), EntityMap<V>& value) 241 { 242 size_t len = value.size(); 243 serialize.NumberU32_Unbounded("length", (u32)len); 244 for (typename EntityMap<V>::iterator it = value.begin(); it != value.end(); ++it) 245 { 246 serialize.NumberI32_Unbounded("key", it->first); 247 VSerializer()(serialize, "value", it->second); 248 } 249 } 250 251 template<class V> 252 void operator()(IDeserializer& deserialize, const char* UNUSED(name), EntityMap<V>& value) 253 { 254 value.clear(); 255 uint32_t len; 256 deserialize.NumberU32_Unbounded("length", len); 257 for (size_t i = 0; i < len; ++i) 258 { 259 entity_id_t k; 260 V v; 261 deserialize.NumberU32_Unbounded("key", k); 262 VSerializer()(deserialize, "value", v); 263 value.insert(k, v); 264 } 265 } 266 }; 267 268 269 #endif -
simulation2/system/SimContext.cpp
34 34 35 35 CComponentManager& CSimContext::GetComponentManager() const 36 36 { 37 ENSURE(m_ComponentManager);38 37 return *m_ComponentManager; 39 38 } 40 39