Ticket #599: update_visibility.patch
File update_visibility.patch, 12.4 KB (added by , 10 years ago) |
---|
-
source/simulation2/components/CCmpRangeManager.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 39 39 #include "renderer/Scene.h" 40 40 #include "lib/ps_stl.h" 41 41 42 42 #define LOS_TILES_RATIO 8 43 43 #define DEBUG_RANGE_MANAGER_BOUNDS 0 44 44 45 45 /** … … 138 138 EntityData() : retainInFog(0), owner(-1), inWorld(0), flags(1) { } 139 139 entity_pos_t x, z; 140 140 entity_pos_t visionRange; 141 u32 visibilities; // 2-bit visibility, per player 141 142 u8 retainInFog; // boolean 142 143 i8 owner; 143 144 u8 inWorld; // boolean … … 144 145 u8 flags; // See GetEntityFlagMask 145 146 }; 146 147 147 cassert(sizeof(EntityData) == 16);148 cassert(sizeof(EntityData) == 20); 148 149 149 150 /** 150 151 * Serialization helper template for Query … … 197 198 serialize.NumberFixed_Unbounded("z", value.z); 198 199 serialize.NumberFixed_Unbounded("vision", value.visionRange); 199 200 serialize.NumberU8("retain in fog", value.retainInFog, 0, 1); 201 serialize.NumberU32_Unbounded("visibilities", value.visibilities); 200 202 serialize.NumberI8_Unbounded("owner", value.owner); 201 203 serialize.NumberU8("in world", value.inWorld, 0, 1); 202 204 serialize.NumberU8_Unbounded("flags", value.flags); … … 283 285 bool m_LosCircular; 284 286 i32 m_TerrainVerticesPerSide; 285 287 size_t m_TerritoriesDirtyID; 288 289 // Cache for visibility tracking (not serialized) 290 i32 m_LosTilesPerSide; 291 bool* m_DirtyVisibility; 292 std::vector<std::set<entity_id_t>> m_LosTiles; 293 // List of entities that must be updated, regardless of the status of their tile 294 std::vector<entity_id_t> m_ModifiedEntities; 286 295 287 296 // Counts of units seeing vertex, per vertex, per player (starting with player 0). 288 297 // Use u16 to avoid overflows when we have very large (but not infeasibly large) numbers … … 332 341 m_LosCircular = false; 333 342 m_TerrainVerticesPerSide = 0; 334 343 344 m_DirtyVisibility = NULL; 345 335 346 m_TerritoriesDirtyID = 0; 336 347 } 337 348 338 349 virtual void Deinit() 339 350 { 351 delete[] m_DirtyVisibility; 340 352 } 341 353 342 354 template<typename S> … … 355 367 serialize.Bool("los circular", m_LosCircular); 356 368 serialize.NumberI32_Unbounded("terrain verts per side", m_TerrainVerticesPerSide); 357 369 358 // We don't serialize m_Subdivision or m_LosPlayerCounts 370 SerializeVector<SerializeU32_Unbounded>()(serialize, "modified entities", m_ModifiedEntities); 371 372 // We don't serialize m_Subdivision, m_LosPlayerCounts or m_LosTiles 359 373 // since they can be recomputed from the entity data when deserializing; 360 374 // m_LosState must be serialized since it depends on the history of exploration 361 375 … … 432 446 CFixedVector2D to(msgData.x, msgData.z); 433 447 m_Subdivision.Move(ent, from, to); 434 448 LosMove(it->second.owner, it->second.visionRange, from, to); 449 i32 oldLosTile = PosToLosTilesHelper(it->second.x, it->second.z); 450 i32 newLosTile = PosToLosTilesHelper(msgData.x, msgData.z); 451 if (oldLosTile != newLosTile) 452 { 453 RemoveFromTile(oldLosTile, ent); 454 AddToTile(newLosTile, ent); 455 } 435 456 } 436 457 else 437 458 { … … 438 459 CFixedVector2D to(msgData.x, msgData.z); 439 460 m_Subdivision.Add(ent, to); 440 461 LosAdd(it->second.owner, it->second.visionRange, to); 462 AddToTile(PosToLosTilesHelper(msgData.x, msgData.z), ent); 441 463 } 442 464 443 465 it->second.inWorld = 1; … … 451 473 CFixedVector2D from(it->second.x, it->second.z); 452 474 m_Subdivision.Remove(ent, from); 453 475 LosRemove(it->second.owner, it->second.visionRange, from); 476 RemoveFromTile(PosToLosTilesHelper(it->second.x, it->second.z), ent); 454 477 } 455 478 456 479 it->second.inWorld = 0; … … 458 481 it->second.z = entity_pos_t::Zero(); 459 482 } 460 483 484 m_ModifiedEntities.push_back(ent); 485 461 486 break; 462 487 } 463 488 case MT_OwnershipChanged: … … 495 520 break; 496 521 497 522 if (it->second.inWorld) 523 { 498 524 m_Subdivision.Remove(ent, CFixedVector2D(it->second.x, it->second.z)); 525 RemoveFromTile(PosToLosTilesHelper(it->second.x, it->second.z), ent); 526 } 499 527 500 528 // This will be called after Ownership's OnDestroy, so ownership will be set 501 529 // to -1 already and we don't have to do a LosRemove here … … 539 567 case MT_Update: 540 568 { 541 569 m_DebugOverlayDirty = true; 570 UpdateVisibilityData(); 542 571 UpdateTerritoriesLos(); 543 572 ExecuteActiveQueries(); 544 573 break; … … 559 588 m_WorldX1 = x1; 560 589 m_WorldZ1 = z1; 561 590 m_TerrainVerticesPerSide = (i32)vertices; 591 592 m_LosTilesPerSide = (m_TerrainVerticesPerSide - 1)/LOS_TILES_RATIO; 562 593 563 594 ResetDerivedData(false); 564 595 } … … 639 670 } 640 671 m_LosStateRevealed.clear(); 641 672 m_LosStateRevealed.resize(m_TerrainVerticesPerSide*m_TerrainVerticesPerSide); 673 674 delete[] m_DirtyVisibility; 675 m_DirtyVisibility = new bool[m_LosTilesPerSide*m_LosTilesPerSide](); 676 m_LosTiles.clear(); 677 m_LosTiles.resize(m_LosTilesPerSide*m_LosTilesPerSide); 642 678 643 679 for (EntityMap<EntityData>::const_iterator it = m_EntityData.begin(); it != m_EntityData.end(); ++it) 644 680 { 645 681 if (it->second.inWorld) 682 { 646 683 LosAdd(it->second.owner, it->second.visionRange, CFixedVector2D(it->second.x, it->second.z)); 684 AddToTile(PosToLosTilesHelper(it->second.x, it->second.z), it->first); 685 } 647 686 } 648 687 649 688 m_TotalInworldVertices = 0; … … 1384 1423 return GetLosVisibility(handle, player, forceRetainInFog); 1385 1424 } 1386 1425 1426 i32 PosToLosTilesHelper(entity_pos_t x, entity_pos_t z) 1427 { 1428 i32 i = Clamp( 1429 (x/(entity_pos_t::FromInt(TERRAIN_TILE_SIZE * LOS_TILES_RATIO))).ToInt_RoundToZero(), 1430 0, 1431 m_LosTilesPerSide - 1); 1432 i32 j = Clamp( 1433 (z/(entity_pos_t::FromInt(TERRAIN_TILE_SIZE * LOS_TILES_RATIO))).ToInt_RoundToZero(), 1434 0, 1435 m_LosTilesPerSide - 1); 1436 return j*m_LosTilesPerSide + i; 1437 } 1387 1438 1439 void AddToTile(i32 tile, entity_id_t ent) 1440 { 1441 m_LosTiles[tile].insert(ent); 1442 } 1443 1444 void RemoveFromTile(i32 tile, entity_id_t ent) 1445 { 1446 for (std::set<entity_id_t>::iterator tileIt = m_LosTiles[tile].begin(); 1447 tileIt != m_LosTiles[tile].end(); 1448 ++tileIt) 1449 { 1450 if (*tileIt == ent) 1451 { 1452 m_LosTiles[tile].erase(tileIt); 1453 return; 1454 } 1455 } 1456 } 1457 1458 void UpdateVisibilityData() 1459 { 1460 PROFILE("UpdateVisibilityData"); 1461 1462 for (i32 n = 0; n < m_LosTilesPerSide*m_LosTilesPerSide; ++n) 1463 { 1464 if (m_DirtyVisibility[n]) 1465 { 1466 for (std::set<entity_id_t>::iterator it = m_LosTiles[n].begin(); 1467 it != m_LosTiles[n].end(); 1468 ++it) 1469 { 1470 UpdateVisibility(*it); 1471 } 1472 m_DirtyVisibility[n] = false; 1473 } 1474 } 1475 1476 for (std::vector<entity_id_t>::iterator it = m_ModifiedEntities.begin(); it != m_ModifiedEntities.end(); ++it) 1477 { 1478 UpdateVisibility(*it); 1479 } 1480 m_ModifiedEntities.clear(); 1481 } 1482 1483 void UpdateVisibility(entity_id_t ent) 1484 { 1485 EntityMap<EntityData>::iterator itEnts = m_EntityData.find(ent); 1486 if (itEnts == m_EntityData.end()) 1487 return; 1488 1489 for (player_id_t player = 1; player <= MAX_LOS_PLAYER_ID; ++player) 1490 { 1491 u8 oldVis = (itEnts->second.visibilities >> (2*player)) & 0x3; 1492 u8 newVis = GetLosVisibility(itEnts->first, player, false); 1493 1494 if (oldVis != newVis) 1495 { 1496 CMessageVisibilityChanged msg(player, ent, oldVis, newVis); 1497 GetSimContext().GetComponentManager().PostMessage(ent, msg); 1498 itEnts->second.visibilities = (itEnts->second.visibilities & ~(0x3 << 2*player)) | (newVis << 2*player); 1499 } 1500 } 1501 } 1502 1388 1503 virtual void SetLosRevealAll(player_id_t player, bool enabled) 1389 1504 { 1390 1505 if (player == -1) … … 1532 1647 explored += !(m_LosState[idx] & (LOS_EXPLORED << (2*(owner-1)))); 1533 1648 m_LosState[idx] |= ((LOS_VISIBLE | LOS_EXPLORED) << (2*(owner-1))); 1534 1649 } 1650 m_DirtyVisibility[(j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO] = true; 1535 1651 } 1536 1652 1537 1653 ASSERT(counts[idx] < 65535); … … 1559 1675 { 1560 1676 // (If LosIsOffWorld then this is a no-op, so don't bother doing the check) 1561 1677 m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1))); 1678 1679 i32 i = i0 + idx - idx0; 1680 m_DirtyVisibility[(j/LOS_TILES_RATIO)*m_LosTilesPerSide + i/LOS_TILES_RATIO] = true; 1562 1681 } 1563 1682 } 1564 1683 } -
source/simulation2/components/ICmpRangeManager.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify -
source/simulation2/components/ICmpRangeManager.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 216 216 217 217 enum ELosVisibility 218 218 { 219 VIS_HIDDEN ,220 VIS_FOGGED ,221 VIS_VISIBLE 219 VIS_HIDDEN = 0, 220 VIS_FOGGED = 1, 221 VIS_VISIBLE = 2 222 222 }; 223 223 224 224 /** … … 326 326 virtual ELosVisibility GetLosVisibility(CEntityHandle ent, player_id_t player, bool forceRetainInFog = false) = 0; 327 327 virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player, bool forceRetainInFog = false) = 0; 328 328 329 329 330 /** 330 331 * GetLosVisibility wrapped for script calls. 331 332 * Returns "hidden", "fogged" or "visible". -
source/simulation2/MessageTypes.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 362 362 }; 363 363 364 364 /** 365 * Sent, at most once per turn, when the visibility of an entity changed 366 */ 367 class CMessageVisibilityChanged : public CMessage 368 { 369 public: 370 DEFAULT_MESSAGE_IMPL(VisibilityChanged) 371 372 CMessageVisibilityChanged(player_id_t player, entity_id_t ent, int oldVisibility, int newVisibility) : 373 player(player), ent(ent), oldVisibility(oldVisibility), newVisibility(newVisibility) 374 { 375 } 376 377 player_id_t player; 378 entity_id_t ent; 379 int oldVisibility; 380 int newVisibility; 381 }; 382 383 /** 365 384 * Sent when ObstructionManager's view of the shape of the world has changed 366 385 * (changing the TILE_OUTOFBOUNDS tiles returned by Rasterise). 367 386 */ -
source/simulation2/scripting/MessageTypeConversions.cpp
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 310 310 311 311 //////////////////////////////// 312 312 313 jsval CMessageVisibilityChanged::ToJSVal(ScriptInterface& scriptInterface) const 314 { 315 TOJSVAL_SETUP(); 316 SET_MSG_PROPERTY(player); 317 SET_MSG_PROPERTY(ent); 318 SET_MSG_PROPERTY(oldVisibility); 319 SET_MSG_PROPERTY(newVisibility); 320 return OBJECT_TO_JSVAL(obj); 321 } 322 323 CMessage* CMessageVisibilityChanged::FromJSVal(ScriptInterface& scriptInterface, jsval val) 324 { 325 FROMJSVAL_SETUP(); 326 GET_MSG_PROPERTY(player_id_t, player); 327 GET_MSG_PROPERTY(entity_id_t, ent); 328 GET_MSG_PROPERTY(int, oldVisibility); 329 GET_MSG_PROPERTY(int, newVisibility); 330 return new CMessageVisibilityChanged(player, ent, oldVisibility, newVisibility); 331 } 332 333 //////////////////////////////// 334 313 335 jsval CMessageWaterChanged::ToJSVal(ScriptInterface& scriptInterface) const 314 336 { 315 337 TOJSVAL_SETUP(); -
source/simulation2/TypeList.h
1 /* Copyright (C) 201 3Wildfire Games.1 /* Copyright (C) 2014 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 48 48 MESSAGE(MotionChanged) 49 49 MESSAGE(RangeUpdate) 50 50 MESSAGE(TerrainChanged) 51 MESSAGE(VisibilityChanged) 51 52 MESSAGE(WaterChanged) 52 53 MESSAGE(ObstructionMapShapeChanged) 53 54 MESSAGE(TerritoriesChanged)