Ticket #788: SameTurnMovesPatch2.patch
File SameTurnMovesPatch2.patch, 9.8 KB (added by , 13 years ago) |
---|
-
binaries/data/mods/public/simulation/data/pathfinder.xml
1 1 <?xml version="1.0" encoding="utf-8"?> 2 2 <Pathfinder> 3 3 <!-- Sets limit on the number of same turns moves we will process --> 4 <!-- Setting the value to 0 disable this functionality --> 5 <MaxSameTurnMoves>16</MaxSameTurnMoves> 6 4 7 <PassabilityClasses> 5 8 6 9 <!-- Unit pathfinding classes: --> -
source/simulation2/components/CCmpPathfinder.cpp
52 52 m_DebugGrid = NULL; 53 53 m_DebugPath = NULL; 54 54 55 m_SameTurnMovesCount = 0; 56 55 57 // Since this is used as a system component (not loaded from an entity template), 56 58 // we can't use the real paramNode (it won't get handled properly when deserializing), 57 59 // so load the data from a special XML file. 58 60 CParamNode externalParamNode; 59 61 CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml"); 60 62 63 // Previously all move commands during a turn were 64 // queued up and processed asynchronously at the start 65 // of the next turn. Now we are processing queued up 66 // events several times duing the turn. This improves 67 // responsiveness and units move more smoothly especially. 68 // when in formation. There is still a call at the 69 // beginning of a turn to process all outstanding moves - 70 // this will handle any moves above the MaxSameTurnMoves 71 // threshold. 72 // 73 // TODO - The moves processed at the beginning of the 74 // turn do not count against the maximum moves per turn 75 // currently. The thinking is that this will eventually 76 // happen in another thread. Either way this probably 77 // will require some adjustment and rethinking. 78 const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder"); 79 m_MaxSameTurnMoves = pathingSettings.GetChild("MaxSameTurnMoves").ToInt(); 61 80 81 62 82 const CParamNode::ChildrenMap& passClasses = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses").GetChildren(); 63 83 for (CParamNode::ChildrenMap::const_iterator it = passClasses.begin(); it != passClasses.end(); ++it) 64 84 { … … 172 192 SerializeVector<SerializeLongRequest>()(serialize, "long requests", m_AsyncLongPathRequests); 173 193 SerializeVector<SerializeShortRequest>()(serialize, "short requests", m_AsyncShortPathRequests); 174 194 serialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket); 195 serialize.NumberU16_Unbounded("same turn moves count", m_SameTurnMovesCount); 175 196 } 176 197 177 198 void CCmpPathfinder::Deserialize(const CParamNode& paramNode, IDeserializer& deserialize) … … 181 202 SerializeVector<SerializeLongRequest>()(deserialize, "long requests", m_AsyncLongPathRequests); 182 203 SerializeVector<SerializeShortRequest>()(deserialize, "short requests", m_AsyncShortPathRequests); 183 204 deserialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket); 205 deserialize.NumberU16_Unbounded("same turn moves count", m_SameTurnMovesCount); 184 206 } 185 207 186 208 void CCmpPathfinder::HandleMessage(const CMessage& msg, bool UNUSED(global)) … … 199 221 m_TerrainDirty = true; 200 222 break; 201 223 } 224 case MT_TurnStart: 225 { 226 m_SameTurnMovesCount = 0; 227 break; 202 228 } 229 } 203 230 } 204 231 205 232 void CCmpPathfinder::RenderSubmit(SceneCollector& collector) … … 435 462 // TODO: this computation should be done incrementally, spread 436 463 // across multiple frames (or even multiple turns) 437 464 465 ProcessLongRequests(longRequests); 466 ProcessShortRequests(shortRequests); 467 } 468 469 void CCmpPathfinder::ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests) 470 { 438 471 for (size_t i = 0; i < longRequests.size(); ++i) 439 472 { 440 473 const AsyncLongPathRequest& req = longRequests[i]; … … 443 476 CMessagePathResult msg(req.ticket, path); 444 477 GetSimContext().GetComponentManager().PostMessage(req.notify, msg); 445 478 } 479 } 446 480 481 void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests) 482 { 447 483 for (size_t i = 0; i < shortRequests.size(); ++i) 448 484 { 449 485 const AsyncShortPathRequest& req = shortRequests[i]; … … 454 490 GetSimContext().GetComponentManager().PostMessage(req.notify, msg); 455 491 } 456 492 } 493 494 void CCmpPathfinder::ProcessSameTurnMoves() 495 { 496 u32 moveCount; 497 498 if (!m_AsyncLongPathRequests.empty()) 499 { 500 // Figure out how many moves we can do this time 501 moveCount = m_MaxSameTurnMoves - m_SameTurnMovesCount; 502 503 if (moveCount <= 0) 504 return; 505 506 // Copy the long request elements we are going to process into a new array 507 std::vector<AsyncLongPathRequest> longRequests; 508 if (m_AsyncLongPathRequests.size() <= moveCount) 509 { 510 m_AsyncLongPathRequests.swap(longRequests); 511 moveCount = longRequests.size(); 512 } 513 else 514 { 515 longRequests.resize(moveCount); 516 copy(m_AsyncLongPathRequests.begin(), m_AsyncLongPathRequests.begin() + moveCount, longRequests.begin()); 517 m_AsyncLongPathRequests.erase(m_AsyncLongPathRequests.begin(), m_AsyncLongPathRequests.begin() + moveCount); 518 } 519 520 ProcessLongRequests(longRequests); 521 522 m_SameTurnMovesCount += moveCount; 523 } 524 525 if (!m_AsyncShortPathRequests.empty()) 526 { 527 // Figure out how many moves we can do now 528 moveCount = m_MaxSameTurnMoves - m_SameTurnMovesCount; 529 530 if (moveCount <= 0) 531 return; 532 533 // Copy the short request elements we are going to process into a new array 534 std::vector<AsyncShortPathRequest> shortRequests; 535 if (m_AsyncShortPathRequests.size() <= moveCount) 536 { 537 m_AsyncShortPathRequests.swap(shortRequests); 538 moveCount = shortRequests.size(); 539 } 540 else 541 { 542 shortRequests.resize(moveCount); 543 copy(m_AsyncShortPathRequests.begin(), m_AsyncShortPathRequests.begin() + moveCount, shortRequests.begin()); 544 m_AsyncShortPathRequests.erase(m_AsyncShortPathRequests.begin(), m_AsyncShortPathRequests.begin() + moveCount); 545 } 546 547 ProcessShortRequests(shortRequests); 548 549 m_SameTurnMovesCount += moveCount; 550 } 551 } 552 -
source/simulation2/components/CCmpPathfinder_Common.h
161 161 componentManager.SubscribeToMessageType(MT_Update); 162 162 componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays 163 163 componentManager.SubscribeToMessageType(MT_TerrainChanged); 164 componentManager.SubscribeToMessageType(MT_TurnStart); 164 165 } 165 166 166 167 DEFAULT_COMPONENT_ALLOCATOR(Pathfinder) … … 180 181 std::vector<AsyncLongPathRequest> m_AsyncLongPathRequests; 181 182 std::vector<AsyncShortPathRequest> m_AsyncShortPathRequests; 182 183 u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests 184 u16 m_SameTurnMovesCount; // current number of same turn moves we have processed this turn 183 185 184 186 // Lazily-constructed dynamic state (not serialized): 185 187 … … 187 189 Grid<TerrainTile>* m_Grid; // terrain/passability information 188 190 Grid<u8>* m_ObstructionGrid; // cached obstruction information (TODO: we shouldn't bother storing this, it's redundant with LSBs of m_Grid) 189 191 bool m_TerrainDirty; // indicates if m_Grid has been updated since terrain changed 192 193 // For responsiveness we will process some moves in the same turn they were generated in 194 195 u16 m_MaxSameTurnMoves; // max number of moves that can be created and processed in the same turn 190 196 191 197 // Debugging - output from last pathfind operation: 198 192 199 PathfindTileGrid* m_DebugGrid; 193 200 u32 m_DebugSteps; 194 201 Path* m_DebugPath; … … 242 249 243 250 virtual void FinishAsyncRequests(); 244 251 252 void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests); 253 254 void ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests); 255 256 virtual void ProcessSameTurnMoves(); 257 245 258 /** 246 259 * Returns the tile containing the given position 247 260 */ -
source/simulation2/components/ICmpPathfinder.h
159 159 */ 160 160 virtual void FinishAsyncRequests() = 0; 161 161 162 /** 163 * Process moves during the same turn they were created in to improve responsiveness. 164 */ 165 virtual void ProcessSameTurnMoves() = 0; 166 162 167 DECLARE_INTERFACE_TYPE(Pathfinder) 163 168 }; 164 169 -
source/simulation2/Simulation2.cpp
229 229 if (!cmpCommandQueue.null()) 230 230 cmpCommandQueue->FlushTurn(commands); 231 231 232 // Process newly generated move commands so the UI feels snappy 233 if (!cmpPathfinder.null()) 234 cmpPathfinder->ProcessSameTurnMoves(); 235 232 236 // Send all the update phases 233 237 { 234 238 CMessageUpdate msgUpdate(turnLengthFixed); … … 238 242 CMessageUpdate_MotionFormation msgUpdate(turnLengthFixed); 239 243 m_ComponentManager.BroadcastMessage(msgUpdate); 240 244 } 245 246 // Process move commands for formations (group proxy) 247 if (!cmpPathfinder.null()) 248 cmpPathfinder->ProcessSameTurnMoves(); 249 241 250 { 242 251 CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed); 243 252 m_ComponentManager.BroadcastMessage(msgUpdate); … … 247 256 m_ComponentManager.BroadcastMessage(msgUpdate); 248 257 } 249 258 259 // Process moves resulting from group proxy movement (unit needs to catch up or realign) and any others 260 if (!cmpPathfinder.null()) 261 cmpPathfinder->ProcessSameTurnMoves(); 262 263 250 264 // Clean up any entities destroyed during the simulation update 251 265 m_ComponentManager.FlushDestroyedComponents(); 252 266