Ticket #599: proxy.diff
File proxy.diff, 39.9 KB (added by , 12 years ago) |
---|
-
binaries/data/mods/public/simulation/components/BuildRestrictions.js
commit 2c8283a0c38acf3315bf9620d1ae66aa5509356f Author: Josh Matthews <josh@joshmatthews.net> Date: Mon Aug 13 02:12:01 2012 -0400 Woo proxy diff --git a/binaries/data/mods/public/simulation/components/BuildRestrictions.js b/binaries/data/mods/public/simulation/components/BuildRestrictions.js index dcaab94..6bf2b2a 100644
a b BuildRestrictions.prototype.CheckPlacement = function(player) 90 90 default: 91 91 passClassName = "building-land"; 92 92 } 93 94 // Proxies for other players should never be obstructions 95 var cmpVisual = Engine.QueryInterface(this.entity, IID_Visual); 96 var isIgnoreable = cmpVisual && 97 cmpVisual.GetProxiedEntity() != INVALID_ENTITY && 98 cmpVisual.GetProxyPlayerTarget() != player; 93 99 94 100 var cmpObstruction = Engine.QueryInterface(this.entity, IID_Obstruction); 95 if (!cmpObstruction || !cmpObstruction.CheckFoundation(passClassName)) 101 if (!isIgnoreable && 102 (!cmpObstruction || !cmpObstruction.CheckFoundation(passClassName))) 96 103 { 97 104 return false; // Fail 98 105 } -
binaries/data/mods/public/simulation/components/BuildingAI.js
diff --git a/binaries/data/mods/public/simulation/components/BuildingAI.js b/binaries/data/mods/public/simulation/components/BuildingAI.js index a2c5985..8139cbb 100644
a b BuildingAI.prototype.Schema = 17 17 */ 18 18 BuildingAI.prototype.Init = function() 19 19 { 20 if (IsProxyEntity(this.entity)) 21 return; 22 20 23 if (this.GetDefaultArrowCount() > 0 || this.GetGarrisonArrowMultiplier() > 0) 21 24 { 22 25 var cmpTimer = Engine.QueryInterface(SYSTEM_ENTITY, IID_Timer); … … BuildingAI.prototype.OnOwnershipChanged = function(msg) 38 41 this.SetupGaiaRangeQuery(msg.to); 39 42 }; 40 43 44 BuildingAI.prototype.OnVisibilityChanged = function(msg) 45 { 46 if (msg.source != this.entity) 47 return; 48 var cmpOwnHealth = Engine.QueryInterface(this.entity, IID_Health); 49 var cmpProxyHealth = Engine.QueryInterface(msg.proxy, IID_Health); 50 cmpProxyHealth.SetHitpoints(cmpOwnHealth.GetHitpoints()); 51 } 52 41 53 /** 42 54 * Cleanup on destroy 43 55 */ … … BuildingAI.prototype.OnDestroy = function() 63 75 */ 64 76 BuildingAI.prototype.SetupRangeQuery = function(owner) 65 77 { 78 if (IsProxyEntity(this.entity)) 79 return; 80 66 81 var cmpRangeManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_RangeManager); 67 82 var cmpPlayerManager = Engine.QueryInterface(SYSTEM_ENTITY, IID_PlayerManager); 68 83 if (this.enemyUnitsQuery) -
binaries/data/mods/public/simulation/components/Foundation.js
diff --git a/binaries/data/mods/public/simulation/components/Foundation.js b/binaries/data/mods/public/simulation/components/Foundation.js index e7fc336..3060656 100644
a b Foundation.prototype.IsFinished = function() 63 63 return (this.buildProgress >= 1.0); 64 64 }; 65 65 66 Foundation.prototype.OnVisibilityChanged = function(msg) 67 { 68 if (msg.source != this.entity) 69 return; 70 var cmpOwnHealth = Engine.QueryInterface(this.entity, IID_Health); 71 var cmpProxyHealth = Engine.QueryInterface(msg.proxy, IID_Health); 72 cmpProxyHealth.SetHitpoints(cmpOwnHealth.GetHitpoints()); 73 } 74 66 75 Foundation.prototype.OnDestroy = function() 67 76 { 68 77 // Refund a portion of the construction cost, proportional to the amount of build progress remaining -
binaries/data/mods/public/simulation/components/GuiInterface.js
diff --git a/binaries/data/mods/public/simulation/components/GuiInterface.js b/binaries/data/mods/public/simulation/components/GuiInterface.js index 9be9f46..bdd50e5 100644
a b GuiInterface.prototype.Init = function() 23 23 this.rallyPoints = undefined; 24 24 this.notifications = []; 25 25 this.renamedEntities = []; 26 this.proxiedEntities = {}; 26 27 }; 27 28 28 29 /* … … GuiInterface.prototype.GetExtendedSimulationState = function(player) 124 125 125 126 GuiInterface.prototype.GetRenamedEntities = function(player) 126 127 { 127 return this.renamedEntities; 128 var proxied = []; 129 if (player in this.proxiedEntities) 130 proxied = this.proxiedEntities[player]; 131 return this.renamedEntities.concat(proxied); 128 132 }; 129 133 130 134 GuiInterface.prototype.ClearRenamedEntities = function(player) 131 135 { 132 136 this.renamedEntities = []; 137 this.proxiedEntities[player] = []; 133 138 }; 134 139 135 140 GuiInterface.prototype.GetEntityState = function(player, ent) … … GuiInterface.prototype.OnGlobalEntityRenamed = function(msg) 1614 1619 this.renamedEntities.push(msg); 1615 1620 } 1616 1621 1622 // Ensure that any GUI code interacting with proxies can continue 1623 // to interact with the original entity if the proxy is destroyed 1624 // (ie. the original entity becomes visible). 1625 GuiInterface.prototype.OnGlobalDestroy = function(msg) 1626 { 1627 var proxy = GetProxiedEntity(msg.entity); 1628 if (proxy == INVALID_ENTITY) 1629 return; 1630 this.renamedEntities.push({"type": "EntityRenamed", "entity": msg.entity, "newentity": proxy}); 1631 } 1632 1633 GuiInterface.prototype.OnGlobalVisibilityChanged = function(msg) 1634 { 1635 if (msg.source == INVALID_ENTITY) 1636 return; 1637 if (!(msg.player in this.proxiedEntities)) 1638 this.proxiedEntities[msg.player] = []; 1639 this.proxiedEntities[msg.player].push({"type": "EntityRenamed", "entity": msg.source, "newentity": msg.proxy}); 1640 } 1641 1617 1642 // List the GuiInterface functions that can be safely called by GUI scripts. 1618 1643 // (GUI scripts are non-deterministic and untrusted, so these functions must be 1619 1644 // appropriately careful. They are called with a first argument "player", which is -
binaries/data/mods/public/simulation/components/ResourceSupply.js
diff --git a/binaries/data/mods/public/simulation/components/ResourceSupply.js b/binaries/data/mods/public/simulation/components/ResourceSupply.js index 2dbf4e4..4f15946 100644
a b ResourceSupply.prototype.GetType = function() 77 77 return { "generic": type, "specific": subtype }; 78 78 }; 79 79 80 ResourceSupply.prototype.OnVisibilityChanged = function(msg) 81 { 82 if (msg.source != this.entity) 83 return; 84 var entity = msg.proxy; 85 var supply = Engine.QueryInterface(entity, IID_ResourceSupply); 86 supply.amount = this.amount; 87 } 88 80 89 Engine.RegisterComponentType(IID_ResourceSupply, "ResourceSupply", ResourceSupply); -
binaries/data/mods/public/simulation/components/UnitAI.js
diff --git a/binaries/data/mods/public/simulation/components/UnitAI.js b/binaries/data/mods/public/simulation/components/UnitAI.js index 455a688..820a8e5 100644
a b var UnitFsmSpec = { 997 997 }, 998 998 999 999 "GATHER": { 1000 "EntityRenamed": function(msg) { 1001 if (this.order.data.target == msg.entity) 1002 this.order.data.target = msg.newentity; 1003 }, 1004 1000 1005 "APPROACHING": { 1001 1006 "enter": function() { 1002 1007 this.SelectAnimation("move"); … … UnitAI.prototype.OnDestroy = function() 1925 1930 // Wrapper function that sets up the normal, healer, and Gaia range queries. 1926 1931 UnitAI.prototype.SetupRangeQueries = function() 1927 1932 { 1933 if (IsProxyEntity(this.entity)) 1934 return; 1935 1928 1936 this.SetupRangeQuery(); 1929 1937 1930 1938 if (this.IsHealer()) … … UnitAI.prototype.SetupRangeQueries = function() 1934 1942 this.SetupGaiaRangeQuery(); 1935 1943 } 1936 1944 1945 // Ensure that any orders focused on a proxy are correctly 1946 // transferred to the original entity when the proxy is destroyed 1947 // (ie. the original entity becomes visible). 1948 UnitAI.prototype.OnGlobalDestroy = function(msg) 1949 { 1950 var orig = GetProxiedEntity(msg.entity); 1951 if (orig == INVALID_ENTITY) 1952 return; 1953 this.OnGlobalEntityRenamed({entity: msg.entity, newentity: orig}); 1954 } 1955 1937 1956 // Set up a range query for all enemy units within LOS range 1938 1957 // which can be attacked. 1939 1958 // This should be called whenever our ownership changes. … … UnitAI.prototype.OnGlobalEntityRenamed = function(msg) 2280 2299 UnitFsm.ProcessMessage(this, {"type": "EntityRenamed", "entity": msg.entity, "newentity": msg.newentity}); 2281 2300 }; 2282 2301 2302 // If a proxy appears and it's targeted at this unit's owner, 2303 // pretend the original actor has been renamed to the proxy. 2304 UnitAI.prototype.OnGlobalVisibilityChanged = function(msg) 2305 { 2306 if (msg.source == INVALID_ENTITY) 2307 return; 2308 var cmpVisual = Engine.QueryInterface(msg.proxy, IID_Visual); 2309 var cmpOwner = Engine.QueryInterface(this.entity, IID_Ownership); 2310 if (cmpVisual.GetProxyPlayerTarget() == cmpOwner.GetOwner()) 2311 this.OnGlobalEntityRenamed({entity: msg.source, newentity: msg.proxy}); 2312 } 2313 2283 2314 UnitAI.prototype.OnAttacked = function(msg) 2284 2315 { 2285 2316 UnitFsm.ProcessMessage(this, {"type": "Attacked", "data": msg}); … … UnitAI.prototype.FindNearbyFoundation = function() 2430 2461 if (cmpFoundation.IsFinished()) 2431 2462 continue; 2432 2463 2464 if (IsProxyEntity(ent)) 2465 continue; 2433 2466 return ent; 2434 2467 } 2435 2468 -
new file inaries/data/mods/public/simulation/helpers/Proxy.js
diff --git a/binaries/data/mods/public/simulation/helpers/Proxy.js b/binaries/data/mods/public/simulation/helpers/Proxy.js new file mode 100644 index 0000000..be12585
- + 1 function IsProxyEntity(entity) 2 { 3 return GetProxiedEntity(entity) != INVALID_ENTITY; 4 } 5 6 function GetProxiedEntity(entity) 7 { 8 var cmpVisual = Engine.QueryInterface(entity, IID_Visual); 9 if (!cmpVisual) 10 return INVALID_ENTITY; 11 return cmpVisual.GetProxiedEntity(); 12 } 13 14 Engine.RegisterGlobal("IsProxyEntity", IsProxyEntity); 15 Engine.RegisterGlobal("GetProxiedEntity", GetProxiedEntity); -
source/network/NetTurnManager.cpp
diff --git a/source/network/NetTurnManager.cpp b/source/network/NetTurnManager.cpp index 0eb332d..1eec386 100644
a b 32 32 #include "ps/SavedGame.h" 33 33 #include "scriptinterface/ScriptInterface.h" 34 34 #include "simulation2/Simulation2.h" 35 #include "simulation2/system/SimContext.h" 35 36 36 37 #include <sstream> 37 38 #include <fstream> … … void CNetTurnManager::OnSyncError(u32 turn, const std::string& expectedHash) 232 233 bool ok = m_Simulation2.ComputeStateHash(hash, quick); 233 234 ENSURE(ok); 234 235 235 OsPath path = psLogDir()/"oos_dump.txt"; 236 std::stringstream fname; 237 fname << "oos_dump_" << m_Simulation2.GetSimContext().GetCurrentDisplayedPlayer() << ".txt"; 238 OsPath path = psLogDir()/fname.str(); 236 239 std::ofstream file (OsString(path).c_str(), std::ofstream::out | std::ofstream::trunc); 237 240 m_Simulation2.DumpDebugState(file); 238 241 file.close(); -
source/simulation2/MessageTypes.h
diff --git a/source/simulation2/MessageTypes.h b/source/simulation2/MessageTypes.h index f149f50..10ba220 100644
a b 24 24 25 25 #include "simulation2/helpers/Player.h" 26 26 #include "simulation2/helpers/Position.h" 27 #include "simulation2/helpers/Player.h" 27 28 28 29 #include "simulation2/components/ICmpPathfinder.h" 29 30 … … public: 100 101 fixed turnLength; 101 102 }; 102 103 104 class CMessageUpdate_Visibility : public CMessage 105 { 106 public: 107 DEFAULT_MESSAGE_IMPL(Update_Visibility) 108 109 CMessageUpdate_Visibility() 110 { 111 } 112 }; 113 103 114 /** 104 115 * Final update phase, after all other updates. 105 116 */ … … public: 380 391 player_id_t player; 381 392 }; 382 393 394 /** 395 * Sent by range manager every simulation update to every entity that might have 396 * changed visibility states in the current frame. 397 * 398 * Also broadcast by visual actors for every new proxy created. 399 */ 400 class CMessageVisibilityChanged : public CMessage 401 { 402 public: 403 DEFAULT_MESSAGE_IMPL(VisibilityChanged) 404 405 CMessageVisibilityChanged(entity_id_t source, entity_id_t proxy) : 406 source(source), proxy(proxy) 407 { 408 } 409 410 CMessageVisibilityChanged() : 411 source(INVALID_ENTITY), proxy(INVALID_ENTITY) 412 { 413 } 414 415 // source: entity being proxied, or INVALID_ENTITY when indicating a visibility change 416 // proxy: new proxy entity, or INVALID_ENTITY when indicating a visibility change 417 entity_id_t source, proxy; 418 }; 419 383 420 #endif // INCLUDED_MESSAGETYPES -
source/simulation2/Simulation2.cpp
diff --git a/source/simulation2/Simulation2.cpp b/source/simulation2/Simulation2.cpp index 0021e59..bc6c5c9 100644
a b void CSimulation2Impl::UpdateComponents(CSimContext& simContext, fixed turnLengt 501 501 componentManager.BroadcastMessage(msgUpdate); 502 502 } 503 503 { 504 CMessageUpdate_Visibility msgUpdate; 505 componentManager.BroadcastMessage(msgUpdate); 506 } 507 { 504 508 CMessageUpdate_Final msgUpdate(turnLengthFixed); 505 509 componentManager.BroadcastMessage(msgUpdate); 506 510 } -
source/simulation2/TypeList.h
diff --git a/source/simulation2/TypeList.h b/source/simulation2/TypeList.h index 758b67b..a6ba356 100644
a b MESSAGE(TurnStart) 34 34 MESSAGE(Update) 35 35 MESSAGE(Update_MotionFormation) 36 36 MESSAGE(Update_MotionUnit) 37 MESSAGE(Update_Visibility) 37 38 MESSAGE(Update_Final) 38 39 MESSAGE(Interpolate) // non-deterministic (use with caution) 39 40 MESSAGE(RenderSubmit) // non-deterministic (use with caution) … … MESSAGE(TerrainChanged) 48 49 MESSAGE(TerritoriesChanged) 49 50 MESSAGE(PathResult) 50 51 MESSAGE(TechnologyModification) 52 MESSAGE(VisibilityChanged) 51 53 52 54 // TemplateManager must come before all other (non-test) components, 53 55 // so that it is the first to be (de)serialized -
source/simulation2/components/CCmpRangeManager.cpp
diff --git a/source/simulation2/components/CCmpRangeManager.cpp b/source/simulation2/components/CCmpRangeManager.cpp index 1363b1f..4a5a949 100644
a b 18 18 #include "precompiled.h" 19 19 20 20 #include "simulation2/system/Component.h" 21 #include "simulation2/Simulation2.h" 21 22 #include "ICmpRangeManager.h" 22 23 23 24 #include "simulation2/MessageTypes.h" 24 25 #include "simulation2/components/ICmpPosition.h" 25 26 #include "simulation2/components/ICmpTerritoryManager.h" 26 27 #include "simulation2/components/ICmpVision.h" 28 #include "simulation2/components/ICmpVisual.h" 27 29 #include "simulation2/helpers/Render.h" 28 30 #include "simulation2/helpers/Spatial.h" 29 31 … … 34 36 #include "ps/CLogger.h" 35 37 #include "ps/Overlay.h" 36 38 #include "ps/Profile.h" 39 #include "ps/Game.h" 37 40 #include "renderer/Scene.h" 38 41 39 42 #define DEBUG_RANGE_MANAGER_BOUNDS 0 … … public: 190 193 componentManager.SubscribeGloballyToMessageType(MT_Destroy); 191 194 192 195 componentManager.SubscribeToMessageType(MT_Update); 196 componentManager.SubscribeToMessageType(MT_Update_Visibility); 193 197 194 198 componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays 195 199 } … … public: 212 216 std::map<entity_id_t, EntityData> m_EntityData; 213 217 SpatialSubdivision<entity_id_t> m_Subdivision; // spatial index of m_EntityData 214 218 215 // LOS state: 219 // Set of entities that could have changed visibility status in the 220 // current simulation frame 221 std::set<entity_id_t> m_DirtyVisibility; 216 222 223 // LOS state: 217 224 std::map<player_id_t, bool> m_LosRevealAll; 218 225 bool m_LosCircular; 219 226 i32 m_TerrainVerticesPerSide; … … public: 331 338 if (!cmpPosition) 332 339 break; 333 340 341 // XXXjdm On the surface this seems sensible, since proxy entities 342 // should only exist in fogged areas. Are there any uses of 343 // the range manager where we would care about fogged proxies? 344 CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), ent); 345 if (cmpVisual && cmpVisual->GetProxiedEntity() != INVALID_ENTITY) 346 break; 347 334 348 // The newly-created entity will have owner -1 and position out-of-world 335 349 // (any initialisation of those values will happen later), so we can just 336 350 // use the default-constructed EntityData here … … public: 448 462 ExecuteActiveQueries(); 449 463 break; 450 464 } 465 case MT_Update_Visibility: 466 { 467 CMessageVisibilityChanged msg; 468 for (std::set<entity_id_t>::iterator it = m_DirtyVisibility.begin(); it != m_DirtyVisibility.end(); ++it) 469 { 470 g_Game->GetSimulation2()->PostMessage(*it, msg); 471 } 472 m_DirtyVisibility.clear(); 473 break; 474 } 451 475 case MT_RenderSubmit: 452 476 { 453 477 const CMessageRenderSubmit& msgData = static_cast<const CMessageRenderSubmit&> (msg); … … public: 949 973 virtual ELosVisibility GetLosVisibility(entity_id_t ent, player_id_t player, bool forceRetainInFog) 950 974 { 951 975 // (We can't use m_EntityData since this needs to handle LOCAL entities too) 976 bool blankProxyExists = false; 977 978 CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), ent); 979 if (cmpVisual) 980 { 981 // Proxy entities for other players are never visible 982 player_id_t target = cmpVisual->GetProxyPlayerTarget(); 983 if (target != INVALID_PLAYER && target != player) 984 return VIS_HIDDEN; 985 986 // If a regular proxy exists, we should never show this actor. 987 // If an empty proxy exists (ie. an invisible proxy for something 988 // created inside FoW), we want to show this actor if it would be 989 // visible, and show nothing if it's fogged. 990 entity_id_t proxy = cmpVisual->GetProxyForPlayer(player); 991 if (proxy == SYSTEM_ENTITY) 992 blankProxyExists = true; 993 else if (proxy != INVALID_ENTITY) 994 return VIS_HIDDEN; 995 } 952 996 953 997 // Entities not with positions in the world are never visible 954 998 CmpPtr<ICmpPosition> cmpPosition(GetSimContext(), ent); … … public: 976 1020 return VIS_VISIBLE; 977 1021 978 1022 // Fogged if the 'retain in fog' flag is set, and in a non-visible explored region 979 if ( los.IsExplored(i, j))1023 if (!blankProxyExists && los.IsExplored(i, j)) 980 1024 { 981 1025 CmpPtr<ICmpVision> cmpVision(GetSimContext(), ent); 982 1026 if (forceRetainInFog || (cmpVision && cmpVision->GetRetainInFog())) … … public: 1057 1101 m_LosState[i+1 + j*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1))); 1058 1102 m_LosState[i + (j+1)*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1))); 1059 1103 m_LosState[i+1 + (j+1)*m_TerrainVerticesPerSide] |= (LOS_EXPLORED << (2*(p-1))); 1104 1105 // Add any entities in this tile to the dirty visibility map 1106 CFixedVector2D start(fixed::FromInt(i*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)); 1107 CFixedVector2D end(fixed::FromInt((i+1)*TERRAIN_TILE_SIZE), fixed::FromInt((j+1)*TERRAIN_TILE_SIZE)); 1108 std::vector<entity_id_t> ents = m_Subdivision.GetInRange(start, end); 1109 m_DirtyVisibility.insert(ents.begin(), ents.end()); 1060 1110 } 1061 1111 } 1062 1112 } … … public: 1117 1167 ASSERT(counts[idx] < 65535); 1118 1168 counts[idx] = (u16)(counts[idx] + 1); // ignore overflow; the player should never have 64K units 1119 1169 } 1170 1171 // Add any entities in this strip to the dirty visibility map 1172 CFixedVector2D start(fixed::FromInt(i0*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)); 1173 CFixedVector2D end(fixed::FromInt(i1*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)); 1174 std::vector<entity_id_t> ents = m_Subdivision.GetInRange(start, end); 1175 m_DirtyVisibility.insert(ents.begin(), ents.end()); 1120 1176 } 1121 1177 1122 1178 /** … … public: 1142 1198 m_LosState[idx] &= ~(LOS_VISIBLE << (2*(owner-1))); 1143 1199 } 1144 1200 } 1201 1202 // Add any entities in this strip to the dirty visibility map 1203 CFixedVector2D start(fixed::FromInt(i0*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)); 1204 CFixedVector2D end(fixed::FromInt(i1*TERRAIN_TILE_SIZE), fixed::FromInt(j*TERRAIN_TILE_SIZE)); 1205 std::vector<entity_id_t> ents = m_Subdivision.GetInRange(start, end); 1206 m_DirtyVisibility.insert(ents.begin(), ents.end()); 1145 1207 } 1146 1208 1147 1209 /** -
source/simulation2/components/CCmpTerritoryInfluence.cpp
diff --git a/source/simulation2/components/CCmpTerritoryInfluence.cpp b/source/simulation2/components/CCmpTerritoryInfluence.cpp index dcf5057..562114b 100644
a b 23 23 #include "simulation2/components/ICmpOwnership.h" 24 24 #include "simulation2/components/ICmpPlayerManager.h" 25 25 #include "simulation2/components/ICmpTechnologyManager.h" 26 #include "simulation2/components/ICmpVisual.h" 26 27 27 28 class CCmpTerritoryInfluence : public ICmpTerritoryInfluence 28 29 { … … public: 109 110 CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); 110 111 entity_id_t playerEnt = cmpPlayerManager->GetPlayerByID(cmpOwnership->GetOwner()); 111 112 112 if (playerEnt != INVALID_ENTITY) 113 //XXXjdm This might be the same as just checking for being a proxy; 114 // it's hard to envision a proxy targetted at its owner. 115 CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), GetEntityId()); 116 bool isIgnorable = cmpVisual && 117 cmpVisual->GetProxiedEntity() != INVALID_ENTITY && 118 cmpVisual->GetProxyPlayerTarget() != cmpOwnership->GetOwner(); 119 120 if (playerEnt != INVALID_ENTITY && !isIgnorable) 113 121 { 114 122 CmpPtr<ICmpTechnologyManager> cmpTechnologyManager(GetSimContext(), playerEnt); 115 123 if (cmpTechnologyManager) -
source/simulation2/components/CCmpTerritoryManager.cpp
diff --git a/source/simulation2/components/CCmpTerritoryManager.cpp b/source/simulation2/components/CCmpTerritoryManager.cpp index c8b1ec7..d0d1838 100644
a b 41 41 #include "simulation2/components/ICmpSettlement.h" 42 42 #include "simulation2/components/ICmpTerrain.h" 43 43 #include "simulation2/components/ICmpTerritoryInfluence.h" 44 #include "simulation2/components/ICmpVisual.h" 44 45 #include "simulation2/helpers/Geometry.h" 45 46 #include "simulation2/helpers/Grid.h" 46 47 #include "simulation2/helpers/PriorityQueue.h" … … void CCmpTerritoryManager::CalculateTerritories() 378 379 // Allow influence entities to override the terrain costs 379 380 RasteriseInfluences(influences, influenceGrid); 380 381 382 player_id_t currentPlayer = GetSimContext().GetCurrentDisplayedPlayer(); 383 381 384 // Split influence entities into per-player lists, ignoring any with invalid properties 382 385 std::map<player_id_t, std::vector<entity_id_t> > influenceEntities; 383 386 std::vector<entity_id_t> rootInfluenceEntities; … … void CCmpTerritoryManager::CalculateTerritories() 406 409 if (!cmpPosition || !cmpPosition->IsInWorld()) 407 410 continue; 408 411 412 // Ignore if a proxy for any other player but the current one, or 413 // if a proxy for this entity exists for the current entity. 414 CmpPtr<ICmpVisual> cmpVisual(GetSimContext(), it->first); 415 if (cmpVisual && 416 (cmpVisual->GetProxiedEntity() != INVALID_ENTITY && 417 cmpVisual->GetProxyPlayerTarget() != currentPlayer) || 418 (cmpVisual->GetProxyForPlayer(currentPlayer) != INVALID_ENTITY)) 419 continue; 420 409 421 influenceEntities[owner].push_back(it->first); 410 422 411 423 if (cmpTerritoryInfluence->IsRoot()) -
source/simulation2/components/CCmpVisualActor.cpp
diff --git a/source/simulation2/components/CCmpVisualActor.cpp b/source/simulation2/components/CCmpVisualActor.cpp index 643c200..911152c 100644
a b 17 17 18 18 #include "precompiled.h" 19 19 20 #include <sstream> 21 22 #include "simulation2/Simulation2.h" 20 23 #include "simulation2/system/Component.h" 21 24 #include "ICmpVisual.h" 22 25 23 26 #include "ICmpOwnership.h" 27 #include "ICmpPlayerManager.h" 24 28 #include "ICmpPosition.h" 25 29 #include "ICmpRangeManager.h" 26 30 #include "ICmpVision.h" 31 #include "ICmpTemplateManager.h" 27 32 #include "simulation2/MessageTypes.h" 28 33 #include "simulation2/components/ICmpFootprint.h" 29 34 #include "simulation2/components/ICmpSelectable.h" 35 #include "simulation2/serialization/SerializeTemplates.h" 30 36 31 37 #include "graphics/Frustum.h" 32 38 #include "graphics/Model.h" … … 37 43 #include "graphics/UnitManager.h" 38 44 #include "maths/Matrix3D.h" 39 45 #include "maths/Vector3D.h" 46 #include "network/NetTurnManager.h" 40 47 #include "ps/CLogger.h" 48 #include "ps/Game.h" 41 49 #include "renderer/Scene.h" 50 #include "lib/utf8.h" 42 51 43 52 class CCmpVisualActor : public ICmpVisual 44 53 { … … public: 49 58 componentManager.SubscribeToMessageType(MT_Interpolate); 50 59 componentManager.SubscribeToMessageType(MT_RenderSubmit); 51 60 componentManager.SubscribeToMessageType(MT_OwnershipChanged); 61 componentManager.SubscribeToMessageType(MT_VisibilityChanged); 52 62 componentManager.SubscribeGloballyToMessageType(MT_TerrainChanged); 53 63 } 54 64 … … public: 60 70 fixed m_R, m_G, m_B; // shading colour 61 71 62 72 ICmpRangeManager::ELosVisibility m_Visibility; // only valid between Interpolate and RenderSubmit 73 std::vector<ICmpRangeManager::ELosVisibility> m_LastVisibility; 74 bool m_FirstVisUpdate; 75 76 typedef std::map<player_id_t, entity_id_t> ProxyEntityMap; 77 ProxyEntityMap m_ProxyEntities; 78 entity_id_t m_ProxiedEntity; 79 player_id_t m_ProxyPlayerTarget; 80 81 int32_t m_ActorSeed; 63 82 64 83 // Current animation state 65 84 fixed m_AnimRunThreshold; // if non-zero this is the special walk/run mode … … public: 141 160 142 161 m_R = m_G = m_B = fixed::FromInt(1); 143 162 163 m_FirstVisUpdate = true; 164 CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); 165 for (int32_t i = 0; i < cmpPlayerManager->GetNumPlayers(); i++) 166 m_LastVisibility.push_back(ICmpRangeManager::VIS_FOGGED); 167 168 m_ProxyPlayerTarget = INVALID_PLAYER; 169 m_ProxiedEntity = INVALID_ENTITY; 170 171 m_ActorSeed = GetEntityId(); 172 144 173 if (!GetSimContext().HasUnitManager()) 145 174 return; // do nothing further if graphics are disabled 146 175 … … public: 151 180 else 152 181 m_ActorName = paramNode.GetChild("Actor").ToString(); 153 182 154 std::set<CStr> selections; 155 m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections); 156 if (m_Unit) 157 { 158 CModelAbstract& model = m_Unit->GetModel(); 159 if (model.ToCModel()) 160 { 161 u32 modelFlags = 0; 162 163 if (paramNode.GetChild("SilhouetteDisplay").ToBool()) 164 modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY; 165 166 if (paramNode.GetChild("SilhouetteOccluder").ToBool()) 167 modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER; 168 169 CmpPtr<ICmpVision> cmpVision(GetSimContext(), GetEntityId()); 170 if (cmpVision && cmpVision->GetAlwaysVisible()) 171 modelFlags |= MODELFLAG_IGNORE_LOS; 172 173 model.ToCModel()->AddFlagsRec(modelFlags); 174 } 175 176 // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the 177 // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint 178 // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in 179 // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just 180 // initialize the selection shape descriptor on-demand. 181 InitSelectionShapeDescriptor(model, paramNode); 182 183 m_Unit->SetID(GetEntityId()); 184 } 183 ResetUnitSeed(m_ActorSeed, paramNode); 185 184 186 185 SelectAnimation("idle", false, fixed::FromInt(1), L""); 187 186 } … … public: 217 216 serialize.NumberFixed_Unbounded("anim desync", m_AnimDesync); 218 217 serialize.NumberFixed_Unbounded("anim sync repeat time", m_AnimSyncRepeatTime); 219 218 219 serialize.NumberI32_Unbounded("seed", m_ActorSeed); 220 serialize.Bool("first vis update", m_FirstVisUpdate); 221 SerializeVector<SerializeU8_Enum<ICmpRangeManager::ELosVisibility, ICmpRangeManager::VIS_VISIBLE> >()(serialize, "last visibility state", m_LastVisibility); 222 serialize.NumberU32_Unbounded("proxied entity", m_ProxiedEntity); 223 serialize.NumberI32_Unbounded("proxy player target", m_ProxyPlayerTarget); 224 SerializeMap<SerializeI32_Unbounded, SerializeU32_Unbounded>()(serialize, "per-player proxy entities", m_ProxyEntities); 220 225 // TODO: store actor variables? 221 226 } 222 227 … … public: 257 262 258 263 virtual void HandleMessage(const CMessage& msg, bool UNUSED(global)) 259 264 { 265 if (msg.GetType() == MT_VisibilityChanged) 266 { 267 const CMessageVisibilityChanged& msgData = static_cast<const CMessageVisibilityChanged&> (msg); 268 if (msgData.source == INVALID_ENTITY) 269 VisibilityChanged(); 270 return; 271 } 272 else if (msg.GetType() == MT_Update_Final) 273 { 274 const CMessageUpdate_Final& msgData = static_cast<const CMessageUpdate_Final&> (msg); 275 Update(msgData.turnLength); 276 return; 277 } 278 260 279 // Quick exit for running in non-graphical mode 261 280 if (m_Unit == NULL) 262 281 return; 263 282 264 283 switch (msg.GetType()) 265 284 { 266 case MT_Update_Final:267 {268 const CMessageUpdate_Final& msgData = static_cast<const CMessageUpdate_Final&> (msg);269 Update(msgData.turnLength);270 break;271 }272 285 case MT_Interpolate: 273 286 { 274 287 const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); … … public: 285 298 { 286 299 const CMessageOwnershipChanged& msgData = static_cast<const CMessageOwnershipChanged&> (msg); 287 300 m_Unit->GetModel().SetPlayerID(msgData.to); 301 //XXXjdm do we need to update the ownership of proxies too? 288 302 break; 289 303 } 290 304 case MT_TerrainChanged: … … public: 468 482 // TODO: should copy/reset silhouette flags 469 483 } 470 484 485 virtual entity_id_t GetProxyForPlayer(player_id_t player) 486 { 487 ProxyEntityMap::iterator result = m_ProxyEntities.find(player); 488 if (result != m_ProxyEntities.end()) { 489 return result->second; 490 } 491 return INVALID_ENTITY; 492 } 493 494 virtual void UnlinkProxyForPlayer(player_id_t player) 495 { 496 m_ProxyEntities.erase(player); 497 } 498 499 virtual entity_id_t GetProxiedEntity() 500 { 501 return m_ProxiedEntity; 502 } 503 504 virtual player_id_t GetProxyPlayerTarget() 505 { 506 return m_ProxyPlayerTarget; 507 } 508 509 virtual void SetProxyData(entity_id_t entity, player_id_t player) 510 { 511 m_ProxiedEntity = entity; 512 m_ProxyPlayerTarget = player; 513 } 514 515 void ResetUnitSeed(int32_t seed, const CParamNode& paramNode) 516 { 517 m_ActorSeed = seed; 518 if (!GetSimContext().HasUnitManager()) 519 return; 520 if (m_Unit) 521 GetSimContext().GetUnitManager().DeleteUnit(m_Unit); 522 523 std::set<CStr> selections; 524 m_Unit = GetSimContext().GetUnitManager().CreateUnit(m_ActorName, GetActorSeed(), selections); 525 if (!m_Unit) 526 return; 527 528 CModelAbstract& model = m_Unit->GetModel(); 529 if (model.ToCModel()) 530 { 531 u32 modelFlags = 0; 532 533 if (paramNode.GetChild("SilhouetteDisplay").ToBool()) 534 modelFlags |= MODELFLAG_SILHOUETTE_DISPLAY; 535 536 if (paramNode.GetChild("SilhouetteOccluder").ToBool()) 537 modelFlags |= MODELFLAG_SILHOUETTE_OCCLUDER; 538 539 CmpPtr<ICmpVision> cmpVision(GetSimContext(), GetEntityId()); 540 if (cmpVision && cmpVision->GetAlwaysVisible()) 541 modelFlags |= MODELFLAG_IGNORE_LOS; 542 543 model.ToCModel()->AddFlagsRec(modelFlags); 544 } 545 546 // Initialize the model's selection shape descriptor. This currently relies on the component initialization order; the 547 // Footprint component must be initialized before this component (VisualActor) to support the ability to use the footprint 548 // shape for the selection box (instead of the default recursive bounding box). See TypeList.h for the order in 549 // which components are initialized; if for whatever reason you need to get rid of this dependency, you can always just 550 // initialize the selection shape descriptor on-demand. 551 InitSelectionShapeDescriptor(model, paramNode); 552 553 m_Unit->SetID(GetEntityId()); 554 } 555 556 virtual void ResetUnitSeed(int32_t seed, const std::string& templateName) 557 { 558 CSimulation2& simulation = *g_Game->GetSimulation2(); 559 CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY); 560 const CParamNode* rootNode = cmpTemplateManager->GetTemplate(templateName); 561 const CParamNode& paramNode = rootNode->GetChild("VisualActor"); 562 ResetUnitSeed(seed, paramNode); 563 } 564 471 565 private: 472 566 /// Whether the visual actor has been rendered at least once. 473 567 /// Necessary because the visibility update runs on simulation update, … … private: 476 570 477 571 int32_t GetActorSeed() 478 572 { 479 return GetEntityId();573 return m_ActorSeed; 480 574 } 481 575 482 576 /// Helper method; initializes the model selection shape descriptor from XML. Factored out for readability of @ref Init. … … private: 488 582 489 583 void Update(fixed turnLength); 490 584 void UpdateVisibility(); 585 void VisibilityChanged(); 491 586 void Interpolate(float frameTime, float frameOffset); 492 587 void RenderSubmit(SceneCollector& collector, const CFrustum& frustum, bool culling); 493 588 }; … … void CCmpVisualActor::Update(fixed turnLength) 572 667 return; 573 668 574 669 UpdateVisibility(); 670 if (m_FirstVisUpdate) 671 VisibilityChanged(); 575 672 576 673 // If we're in the special movement mode, select an appropriate animation 577 674 if (!m_AnimRunThreshold.IsZero()) … … void CCmpVisualActor::UpdateVisibility() 638 735 } 639 736 } 640 737 738 void CCmpVisualActor::VisibilityChanged() 739 { 740 CmpPtr<ICmpPlayerManager> cmpPlayerManager(GetSimContext(), SYSTEM_ENTITY); 741 for (int32_t i = 0; i < cmpPlayerManager->GetNumPlayers() - 1; i++) 742 { 743 player_id_t player = i + 1; 744 CmpPtr<ICmpRangeManager> cmpRangeManager(GetSimContext(), SYSTEM_ENTITY); 745 ICmpRangeManager::ELosVisibility vis = cmpRangeManager->GetLosVisibility(GetEntityId(), player); 746 747 bool forceProxy = false; 748 if (m_FirstVisUpdate) 749 { 750 m_LastVisibility[i] = vis; 751 if (vis == ICmpRangeManager::VIS_FOGGED) 752 { 753 forceProxy = true; 754 } 755 } 756 757 // We need to create proxies for existing entities that are sitting just outside the starting 758 // visible territory at the beginning of the game. However, any entities created after game start 759 // inside fogged territory should not be visible. 760 if (vis != m_LastVisibility[i] || (forceProxy && g_Game->GetTurnManager()->GetCurrentTurn() == 1)) 761 { 762 // We only care about entities that become fogged or visible. 763 // In the first case, we want to create a proxy entity for a particular player that retains 764 // a snapshot of this entity at this current moment. 765 // In the second case, we only care if a proxy entity becomes visible, at which point it 766 // should be destroyed (proxies can outlive their proxied entities). 767 768 CSimulation2& simulation = *g_Game->GetSimulation2(); 769 // If this actor is fogged, and is not a proxy, then create a proxy 770 if (vis == ICmpRangeManager::VIS_FOGGED && m_ProxiedEntity == INVALID_ENTITY) 771 { 772 // Spawn a new entity that is identical to the one being proxied 773 CmpPtr<ICmpTemplateManager> cmpTemplateManager(simulation, SYSTEM_ENTITY); 774 std::string templ = cmpTemplateManager->GetCurrentTemplateName(GetEntityId()); 775 std::wstring wtempl = wstring_from_utf8(templ); 776 entity_id_t proxy = simulation.AddEntity(wtempl); 777 CmpPtr<ICmpVisual> proxyVis(simulation, proxy); 778 proxyVis->SetProxyData(GetEntityId(), player); 779 // Ensure any random seed is overwritten with this entity's seed 780 proxyVis->ResetUnitSeed(GetActorSeed(), templ); 781 m_ProxyEntities[player] = proxy; 782 783 // Ownership and position information are common among all relevant actors 784 CmpPtr<ICmpPosition> ownPos(GetSimContext(), GetEntityId()); 785 if (ownPos) 786 { 787 CmpPtr<ICmpPosition> proxyPos(GetSimContext(), proxy); 788 CFixedVector3D pos = ownPos->GetPosition(); 789 proxyPos->JumpTo(pos.X, pos.Z); 790 CFixedVector3D rot = ownPos->GetRotation(); 791 proxyPos->SetYRotation(rot.Y); 792 proxyPos->SetXZRotation(rot.X, rot.Z); 793 } 794 CmpPtr<ICmpOwnership> ownOwnership(GetSimContext(), GetEntityId()); 795 if (ownOwnership) 796 { 797 CmpPtr<ICmpOwnership> proxyOwnership(GetSimContext(), proxy); 798 proxyOwnership->SetOwner(ownOwnership->GetOwner()); 799 } 800 801 // Broadcast this proxy creation so the relevant components can duplicate all 802 // component-specific properties 803 CMessageVisibilityChanged msg(GetEntityId(), proxy); 804 simulation.BroadcastMessage(msg); 805 } 806 else if (vis == ICmpRangeManager::VIS_VISIBLE) 807 { 808 if (m_ProxiedEntity != INVALID_ENTITY) 809 { 810 // Does the proxied actor still exist? 811 CmpPtr<ICmpVisual> proxyVis(simulation, m_ProxiedEntity); 812 if (proxyVis) 813 { 814 // Notify the original that this proxy no longer exists 815 proxyVis->UnlinkProxyForPlayer(player); 816 } 817 // The proxied actor should now be visible, so this proxy should die 818 simulation.DestroyEntity(GetEntityId()); 819 break; 820 } 821 m_ProxyEntities.erase(player); 822 } 823 } 824 else if (forceProxy && m_ProxiedEntity == INVALID_ENTITY) 825 { 826 // This feels like a hack, but it's the easiest way to avoid rendering a physical proxy 827 // for a newly-created fogged entitiy. 828 m_ProxyEntities[player] = SYSTEM_ENTITY; 829 } 830 m_LastVisibility[i] = vis; 831 } 832 833 m_FirstVisUpdate = false; 834 } 835 641 836 void CCmpVisualActor::Interpolate(float frameTime, float frameOffset) 642 837 { 643 838 if (m_Unit == NULL) … … void CCmpVisualActor::Interpolate(float frameTime, float frameOffset) 650 845 else if (!m_PreviouslyRendered) 651 846 { 652 847 UpdateVisibility(); 848 VisibilityChanged(); 653 849 m_PreviouslyRendered = true; 654 850 } 655 851 -
source/simulation2/components/ICmpVisual.cpp
diff --git a/source/simulation2/components/ICmpVisual.cpp b/source/simulation2/components/ICmpVisual.cpp index 2a6e580..aa986c3 100644
a b DEFINE_INTERFACE_METHOD_1("SetAnimationSyncRepeat", void, ICmpVisual, SetAnimati 28 28 DEFINE_INTERFACE_METHOD_1("SetAnimationSyncOffset", void, ICmpVisual, SetAnimationSyncOffset, fixed) 29 29 DEFINE_INTERFACE_METHOD_4("SetShadingColour", void, ICmpVisual, SetShadingColour, fixed, fixed, fixed, fixed) 30 30 DEFINE_INTERFACE_METHOD_2("SetVariable", void, ICmpVisual, SetVariable, std::string, float) 31 DEFINE_INTERFACE_METHOD_0("GetProxyPlayerTarget", player_id_t, ICmpVisual, GetProxyPlayerTarget) 32 DEFINE_INTERFACE_METHOD_0("GetProxiedEntity", entity_id_t, ICmpVisual, GetProxiedEntity) 31 33 END_INTERFACE_WRAPPER(Visual) -
source/simulation2/components/ICmpVisual.h
diff --git a/source/simulation2/components/ICmpVisual.h b/source/simulation2/components/ICmpVisual.h index ade286e..e19923c 100644
a b 19 19 #define INCLUDED_ICMPVISUAL 20 20 21 21 #include "simulation2/system/Interface.h" 22 #include "simulation2/helpers/Player.h" 22 23 23 24 #include "ps/CStr.h" 24 25 #include "maths/BoundingBoxOriented.h" … … public: 138 139 */ 139 140 virtual void Hotload(const VfsPath& name) = 0; 140 141 141 DECLARE_INTERFACE_TYPE(Visual) 142 /** 143 * Return the ID of the corresponding proxy entity for the given player. 144 * Returns INVALID_ENTITY if no such proxy exists. 145 */ 146 virtual entity_id_t GetProxyForPlayer(player_id_t player) = 0; 147 148 /** 149 * Remove any knowledge of a proxy entity for the given player. Called by proxy 150 * entities on the source entity when the proxy is destroying itself. 151 */ 152 virtual void UnlinkProxyForPlayer(player_id_t player) = 0; 153 154 /** 155 * Get the ID of the source entity for this entity. Returns INVALID_ENTITY if this 156 * entity is not a proxy. 157 */ 158 virtual entity_id_t GetProxiedEntity() = 0; 159 160 /** 161 * Get the ID of the player for whom this proxy entity is visible. Returns INVALID_PLAYER 162 * if this entity is not a proxy. 163 */ 164 virtual player_id_t GetProxyPlayerTarget() = 0; 165 166 /** 167 * Initialize this entity as a proxy for the given source entity, visible only to the 168 * given player. 169 */ 170 virtual void SetProxyData(entity_id_t entity, player_id_t player) = 0; 171 172 /** 173 * Set the actor seed of this entity and recreate the actor's unit appropriately. 174 */ 175 virtual void ResetUnitSeed(int32_t seed, const std::string& templateName) = 0; 176 177 DECLARE_INTERFACE_TYPE(Visual) 142 178 }; 143 179 144 180 // TODO: rename this to VisualActor, because the interface is actor-specific, maybe? -
source/simulation2/scripting/MessageTypeConversions.cpp
diff --git a/source/simulation2/scripting/MessageTypeConversions.cpp b/source/simulation2/scripting/MessageTypeConversions.cpp index 21ed454..d5400e2 100644
a b MESSAGE_1(Update_MotionFormation, fixed, turnLength) 90 90 MESSAGE_1(Update_MotionUnit, fixed, turnLength) 91 91 MESSAGE_1(Update_Final, fixed, turnLength) 92 92 93 jsval CMessageUpdate_Visibility::ToJSVal(ScriptInterface& scriptInterface) const 94 { 95 TOJSVAL_SETUP(); 96 return OBJECT_TO_JSVAL(obj); 97 } 98 99 CMessage* CMessageUpdate_Visibility::FromJSVal(ScriptInterface& UNUSED(scriptInterface), jsval UNUSED(val)) 100 { 101 return NULL; 102 } 103 93 104 //////////////////////////////// 94 105 95 106 jsval CMessageInterpolate::ToJSVal(ScriptInterface& scriptInterface) const … … CMessage* CMessageTechnologyModification::FromJSVal(ScriptInterface& scriptInter 316 327 return new CMessageTechnologyModification(component, player); 317 328 } 318 329 330 //////////////////////////////// 331 332 jsval CMessageVisibilityChanged::ToJSVal(ScriptInterface& scriptInterface) const 333 { 334 TOJSVAL_SETUP(); 335 SET_MSG_PROPERTY(source); 336 SET_MSG_PROPERTY(proxy); 337 return OBJECT_TO_JSVAL(obj); 338 } 339 340 CMessage* CMessageVisibilityChanged::FromJSVal(ScriptInterface& UNUSED(scriptInterface), jsval UNUSED(val)) 341 { 342 LOGWARNING(L"CMessageVisibilityChanged::FromJSVal not implemented"); 343 return NULL; 344 } 345 319 346 //////////////////////////////////////////////////////////////// 320 347 321 348 CMessage* CMessageFromJSVal(int mtid, ScriptInterface& scriptingInterface, jsval val)