Ticket #788: SameTurnMovesPatch2.patch

File SameTurnMovesPatch2.patch, 9.8 KB (added by Kenny Long, 13 years ago)
  • binaries/data/mods/public/simulation/data/pathfinder.xml

     
    11<?xml version="1.0" encoding="utf-8"?>
    22<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 
    47  <PassabilityClasses>
    58
    69    <!-- Unit pathfinding classes: -->
  • source/simulation2/components/CCmpPathfinder.cpp

     
    5252    m_DebugGrid = NULL;
    5353    m_DebugPath = NULL;
    5454
     55    m_SameTurnMovesCount = 0;
     56
    5557    // Since this is used as a system component (not loaded from an entity template),
    5658    // we can't use the real paramNode (it won't get handled properly when deserializing),
    5759    // so load the data from a special XML file.
    5860    CParamNode externalParamNode;
    5961    CParamNode::LoadXML(externalParamNode, L"simulation/data/pathfinder.xml");
    6062
     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();
    6180
     81
    6282    const CParamNode::ChildrenMap& passClasses = externalParamNode.GetChild("Pathfinder").GetChild("PassabilityClasses").GetChildren();
    6383    for (CParamNode::ChildrenMap::const_iterator it = passClasses.begin(); it != passClasses.end(); ++it)
    6484    {
     
    172192    SerializeVector<SerializeLongRequest>()(serialize, "long requests", m_AsyncLongPathRequests);
    173193    SerializeVector<SerializeShortRequest>()(serialize, "short requests", m_AsyncShortPathRequests);
    174194    serialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket);
     195    serialize.NumberU16_Unbounded("same turn moves count", m_SameTurnMovesCount);
    175196}
    176197
    177198void CCmpPathfinder::Deserialize(const CParamNode& paramNode, IDeserializer& deserialize)
     
    181202    SerializeVector<SerializeLongRequest>()(deserialize, "long requests", m_AsyncLongPathRequests);
    182203    SerializeVector<SerializeShortRequest>()(deserialize, "short requests", m_AsyncShortPathRequests);
    183204    deserialize.NumberU32_Unbounded("next ticket", m_NextAsyncTicket);
     205    deserialize.NumberU16_Unbounded("same turn moves count", m_SameTurnMovesCount);
    184206}
    185207
    186208void CCmpPathfinder::HandleMessage(const CMessage& msg, bool UNUSED(global))
     
    199221        m_TerrainDirty = true;
    200222        break;
    201223    }
     224    case MT_TurnStart:
     225    {
     226        m_SameTurnMovesCount = 0;
     227        break;
    202228    }
     229    }
    203230}
    204231
    205232void CCmpPathfinder::RenderSubmit(SceneCollector& collector)
     
    435462    // TODO: this computation should be done incrementally, spread
    436463    // across multiple frames (or even multiple turns)
    437464
     465    ProcessLongRequests(longRequests);
     466    ProcessShortRequests(shortRequests);
     467}
     468
     469void CCmpPathfinder::ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests)
     470{
    438471    for (size_t i = 0; i < longRequests.size(); ++i)
    439472    {
    440473        const AsyncLongPathRequest& req = longRequests[i];
     
    443476        CMessagePathResult msg(req.ticket, path);
    444477        GetSimContext().GetComponentManager().PostMessage(req.notify, msg);
    445478    }
     479}
    446480
     481void CCmpPathfinder::ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests)
     482{
    447483    for (size_t i = 0; i < shortRequests.size(); ++i)
    448484    {
    449485        const AsyncShortPathRequest& req = shortRequests[i];
     
    454490        GetSimContext().GetComponentManager().PostMessage(req.notify, msg);
    455491    }
    456492}
     493
     494void 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

     
    161161        componentManager.SubscribeToMessageType(MT_Update);
    162162        componentManager.SubscribeToMessageType(MT_RenderSubmit); // for debug overlays
    163163        componentManager.SubscribeToMessageType(MT_TerrainChanged);
     164        componentManager.SubscribeToMessageType(MT_TurnStart);
    164165    }
    165166
    166167    DEFAULT_COMPONENT_ALLOCATOR(Pathfinder)
     
    180181    std::vector<AsyncLongPathRequest> m_AsyncLongPathRequests;
    181182    std::vector<AsyncShortPathRequest> m_AsyncShortPathRequests;
    182183    u32 m_NextAsyncTicket; // unique IDs for asynchronous path requests
     184    u16 m_SameTurnMovesCount; // current number of same turn moves we have processed this turn
    183185
    184186    // Lazily-constructed dynamic state (not serialized):
    185187
     
    187189    Grid<TerrainTile>* m_Grid; // terrain/passability information
    188190    Grid<u8>* m_ObstructionGrid; // cached obstruction information (TODO: we shouldn't bother storing this, it's redundant with LSBs of m_Grid)
    189191    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
    190196
    191197    // Debugging - output from last pathfind operation:
     198
    192199    PathfindTileGrid* m_DebugGrid;
    193200    u32 m_DebugSteps;
    194201    Path* m_DebugPath;
     
    242249
    243250    virtual void FinishAsyncRequests();
    244251
     252    void ProcessLongRequests(const std::vector<AsyncLongPathRequest>& longRequests);
     253   
     254    void ProcessShortRequests(const std::vector<AsyncShortPathRequest>& shortRequests);
     255
     256    virtual void ProcessSameTurnMoves();
     257
    245258    /**
    246259     * Returns the tile containing the given position
    247260     */
  • source/simulation2/components/ICmpPathfinder.h

     
    159159     */
    160160    virtual void FinishAsyncRequests() = 0;
    161161
     162    /**
     163     * Process moves during the same turn they were created in to improve responsiveness.
     164     */
     165    virtual void ProcessSameTurnMoves() = 0;
     166
    162167    DECLARE_INTERFACE_TYPE(Pathfinder)
    163168};
    164169
  • source/simulation2/Simulation2.cpp

     
    229229    if (!cmpCommandQueue.null())
    230230        cmpCommandQueue->FlushTurn(commands);
    231231
     232    // Process newly generated move commands so the UI feels snappy
     233    if (!cmpPathfinder.null())
     234        cmpPathfinder->ProcessSameTurnMoves();
     235
    232236    // Send all the update phases
    233237    {
    234238        CMessageUpdate msgUpdate(turnLengthFixed);
     
    238242        CMessageUpdate_MotionFormation msgUpdate(turnLengthFixed);
    239243        m_ComponentManager.BroadcastMessage(msgUpdate);
    240244    }
     245
     246    // Process move commands for formations (group proxy)
     247    if (!cmpPathfinder.null())
     248        cmpPathfinder->ProcessSameTurnMoves();
     249
    241250    {
    242251        CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed);
    243252        m_ComponentManager.BroadcastMessage(msgUpdate);
     
    247256        m_ComponentManager.BroadcastMessage(msgUpdate);
    248257    }
    249258
     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
    250264    // Clean up any entities destroyed during the simulation update
    251265    m_ComponentManager.FlushDestroyedComponents();
    252266