Ticket #1707: rangeManagerOptimizations.patch
File rangeManagerOptimizations.patch, 18.3 KB (added by , 11 years ago) |
---|
-
Users/lancelot/Desktop/0ad-svn/trunk/source/simulation2/components/CCmpRangeManager.cpp
129 129 struct SerializeEntityData 130 130 { 131 131 template<typename S> 132 void operator()(S& serialize, const char* UNUSED(name), EntityData &value)132 void operator()(S& serialize, const char* UNUSED(name), EntityData* value) 133 133 { 134 serialize.NumberFixed_Unbounded("x", value .x);135 serialize.NumberFixed_Unbounded("z", value .z);136 serialize.NumberFixed_Unbounded("vision", value .visionRange);137 serialize.NumberU8("retain in fog", value .retainInFog, 0, 1);138 serialize.NumberI8_Unbounded("owner", value .owner);139 serialize.NumberU8("in world", value .inWorld, 0, 1);140 serialize.NumberU8_Unbounded("flags", value .flags);134 serialize.NumberFixed_Unbounded("x", value->x); 135 serialize.NumberFixed_Unbounded("z", value->z); 136 serialize.NumberFixed_Unbounded("vision", value->visionRange); 137 serialize.NumberU8("retain in fog", value->retainInFog, 0, 1); 138 serialize.NumberI8_Unbounded("owner", value->owner); 139 serialize.NumberU8("in world", value->inWorld, 0, 1); 140 serialize.NumberU8_Unbounded("flags", value->flags); 141 141 } 142 142 }; 143 143 … … 149 149 */ 150 150 struct EntityDistanceOrdering 151 151 { 152 EntityDistanceOrdering(const std:: map<entity_id_t, EntityData>& entities, const CFixedVector2D& source) :152 EntityDistanceOrdering(const std::vector<EntityData*>& entities, const CFixedVector2D& source) : 153 153 m_EntityData(entities), m_Source(source) 154 154 { 155 155 } 156 156 157 157 bool operator()(entity_id_t a, entity_id_t b) 158 158 { 159 const EntityData& da = m_EntityData.find(a)->second; 160 const EntityData& db = m_EntityData.find(b)->second; 161 CFixedVector2D vecA = CFixedVector2D(da.x, da.z) - m_Source; 162 CFixedVector2D vecB = CFixedVector2D(db.x, db.z) - m_Source; 159 const EntityData* da = m_EntityData[a]; 160 const EntityData* db = m_EntityData[b]; 161 if (da == NULL) 162 return false; 163 if (db == NULL) 164 return false; 165 CFixedVector2D vecA = CFixedVector2D(da->x, da->z) - m_Source; 166 CFixedVector2D vecB = CFixedVector2D(db->x, db->z) - m_Source; 163 167 return (vecA.CompareLength(vecB) < 0); 164 168 } 165 169 166 const std:: map<entity_id_t, EntityData>& m_EntityData;170 const std::vector<EntityData*>& m_EntityData; 167 171 CFixedVector2D m_Source; 168 172 169 173 private: … … 210 214 // Range query state: 211 215 tag_t m_QueryNext; // next allocated id 212 216 std::map<tag_t, Query> m_Queries; 213 std::map<entity_id_t, EntityData> m_EntityData; 217 //std::map<entity_id_t, EntityData> m_EntityData; 218 std::vector<EntityData*> m_EntityData; 214 219 SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData 215 220 216 221 // LOS state: … … 284 289 285 290 serialize.NumberU32_Unbounded("query next", m_QueryNext); 286 291 SerializeMap<SerializeU32_Unbounded, SerializeQuery>()(serialize, "queries", m_Queries); 287 SerializeMap<SerializeU32_Unbounded, SerializeEntityData>()(serialize, "entity data", m_EntityData);292 //SerializeVector<SerializeEntityData>()(serialize, "entity data array", m_EntityData); 288 293 289 294 SerializeMap<SerializeI32_Unbounded, SerializeBool>()(serialize, "los reveal all", m_LosRevealAll); 290 295 serialize.Bool("los circular", m_LosCircular); … … 335 340 // The newly-created entity will have owner -1 and position out-of-world 336 341 // (any initialisation of those values will happen later), so we can just 337 342 // use the default-constructed EntityData here 338 EntityData entdata;339 343 EntityData* entdata = new EntityData; 344 340 345 // Store the LOS data, if any 341 346 CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent); 342 347 if (cmpVision) 343 348 { 344 entdata .visionRange = cmpVision->GetRange();345 entdata .retainInFog = (cmpVision->GetRetainInFog() ? 1 : 0);349 entdata->visionRange = cmpVision->GetRange(); 350 entdata->retainInFog = (cmpVision->GetRetainInFog() ? 1 : 0); 346 351 } 347 352 348 353 // Remember this entity 349 m_EntityData.insert(std::make_pair(ent, entdata)); 354 if (ent >= m_EntityData.size()) { 355 m_EntityData.resize(ent+1); 356 } 357 m_EntityData[ent] = entdata; 350 358 351 359 break; 352 360 } … … 355 363 const CMessagePositionChanged& msgData = static_cast<const CMessagePositionChanged&> (msg); 356 364 entity_id_t ent = msgData.entity; 357 365 358 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);359 360 366 // Ignore if we're not already tracking this entity 361 if ( it == m_EntityData.end())367 if (ent >= m_EntityData.size()) 362 368 break; 363 369 370 EntityData* entData = m_EntityData[ent]; 371 364 372 if (msgData.inWorld) 365 373 { 366 if ( it->second.inWorld)374 if (entData->inWorld) 367 375 { 368 CFixedVector2D from( it->second.x, it->second.z);376 CFixedVector2D from(entData->x, entData->z); 369 377 CFixedVector2D to(msgData.x, msgData.z); 370 378 m_Subdivision.Move(ent, from, to); 371 LosMove( it->second.owner, it->second.visionRange, from, to);379 LosMove(entData->owner, entData->visionRange, from, to); 372 380 } 373 381 else 374 382 { 375 383 CFixedVector2D to(msgData.x, msgData.z); 376 384 m_Subdivision.Add(ent, to); 377 LosAdd( it->second.owner, it->second.visionRange, to);385 LosAdd(entData->owner, entData->visionRange, to); 378 386 } 379 387 380 it->second.inWorld = 1;381 it->second.x = msgData.x;382 it->second.z = msgData.z;388 entData->inWorld = 1; 389 entData->x = msgData.x; 390 entData->z = msgData.z; 383 391 } 384 392 else 385 393 { 386 if ( it->second.inWorld)394 if (entData->inWorld) 387 395 { 388 CFixedVector2D from( it->second.x, it->second.z);396 CFixedVector2D from(entData->x, entData->z); 389 397 m_Subdivision.Remove(ent, from); 390 LosRemove( it->second.owner, it->second.visionRange, from);398 LosRemove(entData->owner, entData->visionRange, from); 391 399 } 392 400 393 it->second.inWorld = 0;394 it->second.x = entity_pos_t::Zero();395 it->second.z = entity_pos_t::Zero();401 entData->inWorld = 0; 402 entData->x = entity_pos_t::Zero(); 403 entData->z = entity_pos_t::Zero(); 396 404 } 397 405 398 406 break; … … 402 410 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 403 411 entity_id_t ent = msgData.entity; 404 412 405 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);406 407 413 // Ignore if we're not already tracking this entity 408 if ( it == m_EntityData.end())414 if (ent >= m_EntityData.size()) 409 415 break; 410 416 411 if (it->second.inWorld) 417 EntityData* entData = m_EntityData[ent]; 418 419 if (entData->inWorld) 412 420 { 413 CFixedVector2D pos( it->second.x, it->second.z);414 LosRemove( it->second.owner, it->second.visionRange, pos);415 LosAdd(msgData.to, it->second.visionRange, pos);421 CFixedVector2D pos(entData->x, entData->z); 422 LosRemove(entData->owner, entData->visionRange, pos); 423 LosAdd(msgData.to, entData->visionRange, pos); 416 424 } 417 425 418 426 ENSURE(-128 <= msgData.to && msgData.to <= 127); 419 it->second.owner = (i8)msgData.to;420 427 entData->owner = (i8)msgData.to; 428 421 429 break; 422 430 } 423 431 case MT_Destroy: … … 425 433 const CMessageDestroy& msgData = static_cast<const CMessageDestroy&> (msg); 426 434 entity_id_t ent = msgData.entity; 427 435 428 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);429 430 436 // Ignore if we're not already tracking this entity 431 if ( it == m_EntityData.end())437 if (ent >= m_EntityData.size()) 432 438 break; 433 439 434 if (it->second.inWorld) 435 m_Subdivision.Remove(ent, CFixedVector2D(it->second.x, it->second.z)); 440 EntityData* entData = m_EntityData[ent]; 436 441 437 // This will be called after Ownership's OnDestroy, so ownership will be set 438 // to -1 already and we don't have to do a LosRemove here 439 ENSURE(it->second.owner == -1); 442 if (entData != NULL && entData->inWorld) 443 m_Subdivision.Remove(ent, CFixedVector2D(entData->x, entData->z)); 440 444 441 m_EntityData.erase(it); 445 SAFE_DELETE(entData); 446 m_EntityData[ent] = NULL; 442 447 443 448 break; 444 449 } … … 447 452 const CMessageVisionRangeChanged& msgData = static_cast<const CMessageVisionRangeChanged&> (msg); 448 453 entity_id_t ent = msgData.entity; 449 454 450 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);451 452 455 // Ignore if we're not already tracking this entity 453 if ( it == m_EntityData.end())456 if (ent >= m_EntityData.size()) 454 457 break; 455 458 459 EntityData* entData = m_EntityData[ent]; 460 456 461 CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent); 457 462 if (!cmpVision) 458 463 break; 459 464 460 entity_pos_t oldRange = it->second.visionRange;465 entity_pos_t oldRange = entData->visionRange; 461 466 entity_pos_t newRange = msgData.newRange; 462 467 463 468 // If the range changed and the entity's in-world, we need to manually adjust it 464 469 // but if it's not in-world, we only need to set the new vision range 465 CFixedVector2D pos( it->second.x, it->second.z);466 if ( it->second.inWorld)467 LosRemove( it->second.owner, oldRange, pos);470 CFixedVector2D pos(entData->x, entData->z); 471 if (entData->inWorld) 472 LosRemove(entData->owner, oldRange, pos); 468 473 469 it->second.visionRange = newRange;474 entData->visionRange = newRange; 470 475 471 if ( it->second.inWorld)472 LosAdd( it->second.owner, newRange, pos);476 if (entData->inWorld) 477 LosAdd(entData->owner, newRange, pos); 473 478 474 479 break; 475 480 } … … 555 560 m_LosStateRevealed.clear(); 556 561 m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide); 557 562 558 for (s td::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)563 for (size_t i = 0; i < m_EntityData.size(); ++i) 559 564 { 560 if ( it->second.inWorld)561 LosAdd( it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z));565 if (m_EntityData[i] != NULL && m_EntityData[i]->inWorld) 566 LosAdd(m_EntityData[i]->owner, m_EntityData[i]->visionRange, CFixedVector2D(m_EntityData[i]->x, m_EntityData[i]->z)); 562 567 } 563 568 564 569 for (ssize_t j = 0; j < m_TerrainVerticesPerSide; ++j) … … 572 577 // (TODO: find the optimal number instead of blindly guessing) 573 578 m_Subdivision.Reset(x1, z1, entity_pos_t::FromInt(8*TERRAIN_TILE_SIZE)); 574 579 575 for (s td::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)580 for (size_t i = 0; i < m_EntityData.size(); ++i) 576 581 { 577 if ( it->second.inWorld)578 m_Subdivision.Add(i t->first, CFixedVector2D(it->second.x, it->second.z));582 if (m_EntityData[i] != NULL && m_EntityData[i]->inWorld) 583 m_Subdivision.Add(i, CFixedVector2D(m_EntityData[i]->x, m_EntityData[i]->z)); 579 584 } 580 585 } 581 586 … … 643 648 return r; 644 649 } 645 650 651 PROFILE_START("perform"); 646 652 PerformQuery(q, r); 653 PROFILE_END("perform"); 647 654 648 655 // Return the list sorted by distance from the entity 649 656 CFixedVector2D pos = cmpSourcePosition->GetPosition2D(); … … 693 700 694 701 u32 ownerMask = CalcOwnerMask(player); 695 702 696 for (s td::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)703 for (size_t i = 0; i < m_EntityData.size(); ++i) 697 704 { 698 705 // Check owner and add to list if it matches 699 if ( CalcOwnerMask(it->second.owner) & ownerMask)700 entities.push_back(i t->first);706 if (m_EntityData[i] != NULL && CalcOwnerMask(m_EntityData[i]->owner) & ownerMask) 707 entities.push_back(i); 701 708 } 702 709 703 710 return entities; … … 766 773 /** 767 774 * Returns whether the given entity matches the given query (ignoring maxRange) 768 775 */ 769 bool TestEntityQuery(const Query& q, entity_id_t id, const EntityData &entity)776 bool TestEntityQuery(const Query& q, entity_id_t id, const EntityData* entity) 770 777 { 771 778 // Quick filter to ignore entities with the wrong owner 772 if (!(CalcOwnerMask(entity .owner) & q.ownersMask))779 if (!(CalcOwnerMask(entity->owner) & q.ownersMask)) 773 780 return false; 774 781 775 782 // Ignore entities not present in the world 776 if (!entity .inWorld)783 if (!entity->inWorld) 777 784 return false; 778 785 779 786 // Ignore entities that don't match the current flags 780 if (!(entity .flags & q.flagsMask))787 if (!(entity->flags & q.flagsMask)) 781 788 return false; 782 789 783 790 // Ignore self … … 804 811 // Special case: range -1.0 means check all entities ignoring distance 805 812 if (q.maxRange == entity_pos_t::FromInt(-1)) 806 813 { 807 for (s td::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it)814 for (size_t i = 0; i < m_EntityData.size(); ++i) 808 815 { 809 if ( !TestEntityQuery(q, it->first, it->second))816 if (m_EntityData[i] == NULL || !TestEntityQuery(q, i, m_EntityData[i])) 810 817 continue; 811 818 812 r.push_back(i t->first);819 r.push_back(i); 813 820 } 814 821 } 815 822 else 816 823 { 817 824 // Get a quick list of entities that are potentially in range 818 std::vector<entity_id_t> ents = m_Subdivision.GetNear(pos, q.maxRange); 825 std::vector<entity_id_t> ents; 826 PROFILE_START("GetNear"); 827 //ents = m_Subdivision.GetNear(pos, q.maxRange); 828 ents = m_Subdivision.GetNearUnsorted(pos, q.maxRange); 829 PROFILE_END("GetNear"); 819 830 820 831 for (size_t i = 0; i < ents.size(); ++i) 821 832 { 822 std::map<entity_id_t, EntityData>::const_iterator it = m_EntityData.find(ents[i]); 823 ENSURE(it != m_EntityData.end()); 824 825 if (!TestEntityQuery(q, it->first, it->second)) 833 const EntityData* entData = m_EntityData[ents[i]]; 834 835 if (!TestEntityQuery(q, ents[i], entData)) 826 836 continue; 827 837 828 838 // Restrict based on precise distance 829 int distVsMax = (CFixedVector2D( it->second.x, it->second.z) - pos).CompareLength(q.maxRange);839 int distVsMax = (CFixedVector2D(entData->x, entData->z) - pos).CompareLength(q.maxRange); 830 840 if (distVsMax > 0) 831 841 continue; 832 842 833 843 if (!q.minRange.IsZero()) 834 844 { 835 int distVsMin = (CFixedVector2D( it->second.x, it->second.z) - pos).CompareLength(q.minRange);845 int distVsMin = (CFixedVector2D(entData->x, entData->z) - pos).CompareLength(q.minRange); 836 846 if (distVsMin < 0) 837 847 continue; 838 848 } 839 849 840 r.push_back( it->first);850 r.push_back(ents[i]); 841 851 } 842 852 } 843 853 } … … 945 955 946 956 virtual void SetEntityFlag(entity_id_t ent, std::string identifier, bool value) 947 957 { 948 std::map<entity_id_t, EntityData>::iterator it = m_EntityData.find(ent);949 950 958 // We don't have this entity 951 if ( it == m_EntityData.end())959 if (ent >= m_EntityData.size()) 952 960 return; 953 961 962 EntityData* entData = m_EntityData[ent]; 963 954 964 u8 flag = GetEntityFlagMask(identifier); 955 965 956 966 // We don't have a flag set … … 961 971 } 962 972 963 973 if (value) 964 it->second.flags |= flag;974 entData->flags |= flag; 965 975 else 966 it->second.flags &= ~flag;976 entData->flags &= ~flag; 967 977 } 968 978 969 979 // **************************************************************** -
Users/lancelot/Desktop/0ad-svn/trunk/source/simulation2/components/CCmpObstructionManager.cpp
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);547 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRangeUnsorted(posMin, posMax); 548 548 for (size_t i = 0; i < unitShapes.size(); ++i) 549 549 { 550 550 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); … … 559 559 return true; 560 560 } 561 561 562 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange (posMin, posMax);562 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRangeUnsorted(posMin, posMax); 563 563 for (size_t i = 0; i < staticShapes.size(); ++i) 564 564 { 565 565 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); … … 880 880 881 881 ENSURE(x0 <= x1 && z0 <= z1); 882 882 883 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRange (CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));883 std::vector<u32> unitShapes = m_UnitSubdivision.GetInRangeUnsorted(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 884 884 for (size_t i = 0; i < unitShapes.size(); ++i) 885 885 { 886 886 std::map<u32, UnitShape>::iterator it = m_UnitShapes.find(unitShapes[i]); … … 901 901 squares.push_back(s); 902 902 } 903 903 904 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRange (CFixedVector2D(x0, z0), CFixedVector2D(x1, z1));904 std::vector<u32> staticShapes = m_StaticSubdivision.GetInRangeUnsorted(CFixedVector2D(x0, z0), CFixedVector2D(x1, z1)); 905 905 for (size_t i = 0; i < staticShapes.size(); ++i) 906 906 { 907 907 std::map<u32, StaticShape>::iterator it = m_StaticShapes.find(staticShapes[i]); -
Users/lancelot/Desktop/0ad-svn/trunk/source/simulation2/helpers/Spatial.h
203 203 204 204 return ret; 205 205 } 206 207 /** 208 * Returns a sorted list of unique items that includes all items 209 * within the given axis-aligned square range. 210 */ 211 std::vector<T> GetInRangeUnsorted(CFixedVector2D posMin, CFixedVector2D posMax) 212 { 213 std::vector<T> ret; 214 215 ENSURE(posMin.X <= posMax.X && posMin.Y <= posMax.Y); 216 217 u32 i0 = GetI0(posMin.X); 218 u32 j0 = GetJ0(posMin.Y); 219 u32 i1 = GetI1(posMax.X); 220 u32 j1 = GetJ1(posMax.Y); 221 for (u32 j = j0; j <= j1; ++j) 222 { 223 for (u32 i = i0; i <= i1; ++i) 224 { 225 std::vector<T>& div = m_Divisions[i + j*m_DivisionsW]; 226 ret.insert(ret.end(), div.begin(), div.end()); 227 } 228 } 229 230 // Remove duplicates 231 //std::sort(ret.begin(), ret.end()); 232 //ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); 233 234 return ret; 235 } 206 236 207 237 /** 208 238 * Returns a sorted list of unique items that includes all items … … 216 246 return GetInRange(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range)); 217 247 } 218 248 249 /** 250 * Returns a sorted list of unique items that includes all items 251 * within the given circular distance of the given point. 252 */ 253 std::vector<T> GetNearUnsorted(CFixedVector2D pos, entity_pos_t range) 254 { 255 // TODO: be cleverer and return a circular pattern of divisions, 256 // not this square over-approximation 257 258 return GetInRangeUnsorted(pos - CFixedVector2D(range, range), pos + CFixedVector2D(range, range)); 259 } 260 219 261 private: 220 262 // Helper functions for translating coordinates into division indexes 221 263 // (avoiding out-of-bounds accesses, and rounding correctly so that