#788 Eliminate delay in path finding (and therefore moving)

This was SVN commit r9665.
This commit is contained in:
Chakakhan 2011-06-26 07:03:08 +00:00
parent 5bc125a91f
commit 2aedf48304
5 changed files with 128 additions and 0 deletions

View File

@ -1,6 +1,25 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Pathfinder> <Pathfinder>
<!--
Previously all move commands during a turn were
queued up and processed asynchronously at the start
of the next turn. Now we are processing queued up
events several times duing the turn. This improves
responsiveness and units move more smoothly especially.
when in formation. There is still a call at the
beginning of a turn to process all outstanding moves -
this will handle any moves above the MaxSameTurnMoves
threshold.
TODO - The moves processed at the beginning of the
turn do not count against the maximum moves per turn
currently. The thinking is that this will eventually
happen in another thread. Either way this probably
will require some adjustment and rethinking.
-->
<MaxSameTurnMoves>64</MaxSameTurnMoves>
<PassabilityClasses> <PassabilityClasses>
<!-- Unit pathfinding classes: --> <!-- Unit pathfinding classes: -->

View File

@ -229,6 +229,10 @@ bool CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
if (!cmpCommandQueue.null()) if (!cmpCommandQueue.null())
cmpCommandQueue->FlushTurn(commands); cmpCommandQueue->FlushTurn(commands);
// Process newly generated move commands so the UI feels snappy
if (!cmpPathfinder.null())
cmpPathfinder->ProcessSameTurnMoves();
// Send all the update phases // Send all the update phases
{ {
CMessageUpdate msgUpdate(turnLengthFixed); CMessageUpdate msgUpdate(turnLengthFixed);
@ -238,6 +242,11 @@ bool CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
CMessageUpdate_MotionFormation msgUpdate(turnLengthFixed); CMessageUpdate_MotionFormation msgUpdate(turnLengthFixed);
m_ComponentManager.BroadcastMessage(msgUpdate); m_ComponentManager.BroadcastMessage(msgUpdate);
} }
// Process move commands for formations (group proxy)
if (!cmpPathfinder.null())
cmpPathfinder->ProcessSameTurnMoves();
{ {
CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed); CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed);
m_ComponentManager.BroadcastMessage(msgUpdate); m_ComponentManager.BroadcastMessage(msgUpdate);
@ -247,6 +256,11 @@ bool CSimulation2Impl::Update(int turnLength, const std::vector<SimulationComman
m_ComponentManager.BroadcastMessage(msgUpdate); m_ComponentManager.BroadcastMessage(msgUpdate);
} }
// Process moves resulting from group proxy movement (unit needs to catch up or realign) and any others
if (!cmpPathfinder.null())
cmpPathfinder->ProcessSameTurnMoves();
// Clean up any entities destroyed during the simulation update // Clean up any entities destroyed during the simulation update
m_ComponentManager.FlushDestroyedComponents(); m_ComponentManager.FlushDestroyedComponents();

View File

@ -58,6 +58,9 @@ void CCmpPathfinder::Init(const CParamNode& UNUSED(paramNode))
CParamNode externalParamNode; CParamNode externalParamNode;
CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml"); CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml");
const CParamNode pathingSettings = externalParamNode.GetChild("Pathfinder");
m_MaxSameTurnMoves = pathingSettings.GetChild("MaxSameTurnMoves").ToInt();
const CParamNode::ChildrenMap& passClasses = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses").GetChildren(); const CParamNode::ChildrenMap& passClasses = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses").GetChildren();
for (CParamNode::ChildrenMap::const_iterator it = passClasses.begin(); it != passClasses.end(); ++it) for (CParamNode::ChildrenMap::const_iterator it = passClasses.begin(); it != passClasses.end(); ++it)
@ -199,6 +202,11 @@ void CCmpPathfinder::HandleMessage(const CMessage& msg, bool UNUSED(global))
m_TerrainDirty = true; m_TerrainDirty = true;
break; break;
} }
case MT_TurnStart:
{
m_SameTurnMovesCount = 0;
break;
}
} }
} }
@ -435,6 +443,12 @@ void CCmpPathfinder::FinishAsyncRequests()
// TODO: this computation should be done incrementally, spread // TODO: this computation should be done incrementally, spread
// across multiple frames (or even multiple turns) // across multiple frames (or even multiple turns)
ProcessLongRequests(longRequests);
ProcessShortRequests(shortRequests);
}
void CCmpPathfinder::ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests)
{
for (size_t i = 0; i < longRequests.size(); ++i) for (size_t i = 0; i < longRequests.size(); ++i)
{ {
const AsyncLongPathRequest& req = longRequests[i]; const AsyncLongPathRequest& req = longRequests[i];
@ -443,7 +457,10 @@ void CCmpPathfinder::FinishAsyncRequests()
CMessagePathResult msg(req.ticket, path); CMessagePathResult msg(req.ticket, path);
GetSimContext().GetComponentManager().PostMessage(req.notify, msg); GetSimContext().GetComponentManager().PostMessage(req.notify, msg);
} }
}
void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests)
{
for (size_t i = 0; i < shortRequests.size(); ++i) for (size_t i = 0; i < shortRequests.size(); ++i)
{ {
const AsyncShortPathRequest& req = shortRequests[i]; const AsyncShortPathRequest& req = shortRequests[i];
@ -454,3 +471,63 @@ void CCmpPathfinder::FinishAsyncRequests()
GetSimContext().GetComponentManager().PostMessage(req.notify, msg); GetSimContext().GetComponentManager().PostMessage(req.notify, msg);
} }
} }
void CCmpPathfinder::ProcessSameTurnMoves()
{
u32 moveCount;
if (m_AsyncLongPathRequests.size() > 0)
{
// Figure out how many moves we can do this time
moveCount = m_MaxSameTurnMoves - m_SameTurnMovesCount;
if (moveCount <= 0)
return;
// Copy the long request elements we are going to process into a new array
std::vector<AsyncLongPathRequest> longRequests;
if (m_AsyncLongPathRequests.size() <= moveCount)
{
m_AsyncLongPathRequests.swap(longRequests);
moveCount = longRequests.size();
}
else
{
longRequests.resize(moveCount);
copy(m_AsyncLongPathRequests.begin(), m_AsyncLongPathRequests.begin() + moveCount, longRequests.begin());
m_AsyncLongPathRequests.erase(m_AsyncLongPathRequests.begin(), m_AsyncLongPathRequests.begin() + moveCount);
}
ProcessLongRequests(longRequests);
m_SameTurnMovesCount += moveCount;
}
if (m_AsyncShortPathRequests.size() > 0)
{
// Figure out how many moves we can do now
moveCount = m_MaxSameTurnMoves - m_SameTurnMovesCount;
if (moveCount <= 0)
return;
// Copy the short request elements we are going to process into a new array
std::vector<AsyncShortPathRequest> shortRequests;
if (m_AsyncShortPathRequests.size() <= moveCount)
{
m_AsyncShortPathRequests.swap(shortRequests);
moveCount = shortRequests.size();
}
else
{
shortRequests.resize(moveCount);
copy(m_AsyncShortPathRequests.begin(), m_AsyncShortPathRequests.begin() + moveCount, shortRequests.begin());
m_AsyncShortPathRequests.erase(m_AsyncShortPathRequests.begin(), m_AsyncShortPathRequests.begin() + moveCount);
}
ProcessShortRequests(shortRequests);
m_SameTurnMovesCount += moveCount;
}
}

View File

@ -161,6 +161,7 @@ public:
componentManager.SubscribeToMessageType(MT_Update); componentManager.SubscribeToMessageType(MT_Update);
componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
componentManager.SubscribeToMessageType(MT_TerrainChanged); componentManager.SubscribeToMessageType(MT_TerrainChanged);
componentManager.SubscribeToMessageType(MT_TurnStart);
} }
DEFAULT_COMPONENT_ALLOCATOR(Pathfinder) DEFAULT_COMPONENT_ALLOCATOR(Pathfinder)
@ -187,8 +188,14 @@ public:
Grid<TerrainTile>* m_Grid; // terrain/passability information Grid<TerrainTile>* m_Grid; // terrain/passability information
Grid<u8>* m_ObstructionGrid; // cached obstruction information (TODO: we shouldn't bother storing this, it's redundant with LSBs of m_Grid) Grid<u8>* m_ObstructionGrid; // cached obstruction information (TODO: we shouldn't bother storing this, it's redundant with LSBs of m_Grid)
bool m_TerrainDirty; // indicates if m_Grid has been updated since terrain changed bool m_TerrainDirty; // indicates if m_Grid has been updated since terrain changed
// For responsiveness we will procees some moves in the same turn they were generated in
u16 m_MaxSameTurnMoves; // max number of moves that can be created and processed in the same turn
u16 m_SameTurnMovesCount; // current number of same turn moves we have processed this turn
// Debugging - output from last pathfind operation: // Debugging - output from last pathfind operation:
PathfindTileGrid* m_DebugGrid; PathfindTileGrid* m_DebugGrid;
u32 m_DebugSteps; u32 m_DebugSteps;
Path* m_DebugPath; Path* m_DebugPath;
@ -242,6 +249,12 @@ public:
virtual void FinishAsyncRequests(); virtual void FinishAsyncRequests();
virtual void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests);
virtual void ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests);
virtual void ProcessSameTurnMoves();
/** /**
* Returns the tile containing the given position * Returns the tile containing the given position
*/ */

View File

@ -159,6 +159,11 @@ public:
*/ */
virtual void FinishAsyncRequests() = 0; virtual void FinishAsyncRequests() = 0;
/**
* Process moves during the same turn they were created in to improve responsiveness.
*/
virtual void ProcessSameTurnMoves() = 0;
DECLARE_INTERFACE_TYPE(Pathfinder) DECLARE_INTERFACE_TYPE(Pathfinder)
}; };