Changeset 25071

Timestamp:
Mar 17, 2021, 6:04:51 PM (3 years ago)
Author:
wraitii
Message:

Implement a Motion Manager around UnitMotion.

This new MotionManager handles movement for UnitMotion components (not UnitMotionFlying).
This is a first step towards unit pushing, by giving a central place for the relevant units to collide.

One important side-effect is that movement is effectively synchronous - the positions are not actually updated until all units have moved for a turn (refs rP24798).

As a side-effect, it's an optimisation: fewer messages are being sent overall, which leads to a slight speedup (negligible without a lot of units though).

This is a first step - ideally, the movement functions called from UnitMotionManager would actually be moved there.

Differential Revision: https://code.wildfiregames.com/D3509

Location:
ps/trunk/source/simulation2
Files:
3 added
5 edited

Legend:

Unmodified
Added
Removed
  • ps/trunk/source/simulation2/TypeList.h

    r24161 r25071  
    1 /* Copyright (C) 2020 Wildfire Games.
     1/* Copyright (C) 202 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
     
    197197COMPONENT(UnitMotionScripted)
    198198
     199
     200
     201
    199202INTERFACE(UnitRenderer)
    200203COMPONENT(UnitRenderer)
  • ps/trunk/source/simulation2/components/CCmpUnitMotion.cpp

    r25017 r25071  
    120120    static void ClassInit(CComponentManager& componentManager)
    121121    {
    122         componentManager.SubscribeToMessageType(MT_TurnStart);
    123         componentManager.SubscribeToMessageType(MT_Update_MotionFormation);
    124         componentManager.SubscribeToMessageType(MT_Update_MotionUnit);
     122        componentManager.SubscribeToMessageType(MT_Create);
     123        componentManager.SubscribeToMessageType(MT_Destroy);
    125124        componentManager.SubscribeToMessageType(MT_PathResult);
    126125        componentManager.SubscribeToMessageType(MT_OwnershipChanged);
     
    207206    WaypointPath m_LongPath;
    208207    WaypointPath m_ShortPath;
    209 
    210     // Hack - units move one-at-a-time, so they may need to interplate their target position.
    211     // However, some computations are not doing during the motion messages, and those shouldn't (e.g. turn start).
    212     // This is true if and only if the calls take place during handling of the entity's MT_Motion* messages.
    213     // NB: this won't be true if we end up in UnitMotion because of another entity's motion messages,
    214     // but I think it fixes the issue of interpolating target position OK for current needs,
    215     // without having to add parameters everywhere.
    216     // No need for serialisation, it's just a transient boolean.
    217     bool m_InMotionMessage = false;
    218208
    219209    static std::string GetSchema()
     
    322312        switch (msg.GetType())
    323313        {
    324         case MT_TurnStart:
    325         {
    326             TurnStart();
    327             break;
    328         }
    329         case MT_Update_MotionFormation:
    330         {
    331             if (m_FormationController)
    332             {
    333                 m_InMotionMessage = true;
    334                 fixed dt = static_cast<const CMessageUpdate_MotionFormation&> (msg).turnLength;
    335                 Move(dt);
    336                 m_InMotionMessage = false;
    337             }
    338             break;
    339         }
    340         case MT_Update_MotionUnit:
    341         {
    342             if (!m_FormationController)
    343             {
    344                 m_InMotionMessage = true;
    345                 fixed dt = static_cast<const CMessageUpdate_MotionUnit&> (msg).turnLength;
    346                 Move(dt);
    347                 m_InMotionMessage = false;
    348             }
    349             break;
    350         }
    351314        case MT_RenderSubmit:
    352315        {
     
    362325            break;
    363326        }
     327
     328
     329
     330
     331
     332
     333
     334
     335
     336
     337
     338
    364339        case MT_ValueModification:
    365340        {
     
    370345        }
    371346        case MT_OwnershipChanged:
     347
     348
     349
     350
    372351        case MT_Deserialized:
    373352        {
    374             CmpPtr<ICmpValueModificationManager> cmpValueModificationManager(GetSystemEntity());
    375             if (!cmpValueModificationManager)
    376                 break;
    377 
    378             m_WalkSpeed = cmpValueModificationManager->ApplyModifications(L"UnitMotion/WalkSpeed", m_TemplateWalkSpeed, GetEntityId());
    379             m_RunMultiplier = cmpValueModificationManager->ApplyModifications(L"UnitMotion/RunMultiplier", m_TemplateRunMultiplier, GetEntityId());
    380 
    381             // For MT_Deserialize compute m_Speed from the serialized m_SpeedMultiplier.
    382             // For MT_ValueModification and MT_OwnershipChanged, adjust m_SpeedMultiplier if needed
    383             // (in case then new m_RunMultiplier value is lower than the old).
    384             SetSpeedMultiplier(m_SpeedMultiplier);
    385 
     353            OnValueModification();
     354            if (!ENTITY_IS_LOCAL(GetEntityId()))
     355                CmpPtr<ICmpUnitMotionManager>(GetSystemEntity())->Register(GetEntityId(), m_FormationController);
    386356            break;
    387357        }
     
    652622    void PathResult(u32 ticket, const WaypointPath& path);
    653623
     624
     625
     626
     627
     628
     629
     630
     631
     632
     633
     634
     635
     636
     637
     638
    654639    /**
    655640     * Check if we are at destination early in the turn, this both lets units react faster
     
    657642     * (otherwise they won't be commutative).
    658643     */
    659     void TurnStart();
    660 
    661     /**
    662      * Do the per-turn movement and other updates.
    663      */
    664     void Move(fixed dt);
     644    virtual void OnTurnStart();
     645
     646    virtual void PreMove(ICmpUnitMotionManager::MotionState& state);
     647
     648    virtual void Move(ICmpUnitMotionManager::MotionState& state, fixed dt);
     649
     650    virtual void PostMove(ICmpUnitMotionManager::MotionState& state, fixed dt);
    665651
    666652    /**
     
    909895}
    910896
    911 void CCmpUnitMotion::TurnStart()
     897void CCmpUnitMotion::TurnStart()
    912898{
    913899    if (PossiblyAtDestination())
     
    927913}
    928914
    929 void CCmpUnitMotion::Move(fixed dt)
     915void CCmpUnitMotion::PreMove(ICmpUnitMotionManager::MotionState& state)
     916{
     917    // If we were idle and will still be, no need for an update.
     918    state.needUpdate = m_CurSpeed != fixed::Zero() || m_MoveRequest.m_Type != MoveRequest::NONE;
     919}
     920
     921void CCmpUnitMotion::Move(ICmpUnitMotionManager::MotionState& state, fixed dt)
    930922{
    931923    PROFILE("Move");
    932 
    933     // If we were idle and will still be, we can return.
    934     // TODO: this will need to be removed if pushing is implemented.
    935     if (m_CurSpeed == fixed::Zero() && m_MoveRequest.m_Type == MoveRequest::NONE)
    936         return;
    937 
    938     CmpPtr<ICmpPosition> cmpPosition(GetEntityHandle());
    939     if (!cmpPosition || !cmpPosition->IsInWorld())
    940         return;
    941 
    942     CFixedVector2D initialPos = cmpPosition->GetPosition2D();
    943     entity_angle_t initialAngle = cmpPosition->GetRotation().Y;
    944 
    945     // Keep track of the current unit's position and rotation during the update.
    946     CFixedVector2D pos = initialPos;
    947     entity_angle_t angle = initialAngle;
    948924
    949925    // If we're chasing a potentially-moving unit and are currently close
    950926    // enough to its current position, and we can head in a straight line
    951     // to it, then throw away our current path and go straight to it
    952     bool wentStraight = TryGoingStraightToTarget(initialPos);
    953 
    954     bool wasObstructed = PerformMove(dt, cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, pos, angle);
    955 
     927    // to it, then throw away our current path and go straight to it.
     928    state.wentStraight = TryGoingStraightToTarget(state.initialPos);
     929
     930    state.wasObstructed = PerformMove(dt, state.cmpPosition->GetTurnRate(), m_ShortPath, m_LongPath, state.pos, state.angle);
     931}
     932
     933void CCmpUnitMotion::PostMove(ICmpUnitMotionManager::MotionState& state, fixed dt)
     934{
    956935    // Update our speed over this turn so that the visual actor shows the correct animation.
    957     if (pos == initialPos)
    958     {
    959         if (angle != initialAngle)
    960             cmpPosition->TurnTo(angle);
     936    if (initialPos)
     937    {
     938        if (initialAngle)
     939            angle);
    961940        UpdateMovementState(fixed::Zero());
    962941    }
     
    965944        // Update the Position component after our movement (if we actually moved anywhere)
    966945        // When moving always set the angle in the direction of the movement.
    967         CFixedVector2D offset = pos - initialPos;
    968         angle = atan2_approx(offset.X, offset.Y);
    969         cmpPosition->MoveAndTurnTo(pos.X, pos.Y, angle);
     946        CFixedVector2D offset = initialPos;
     947        angle = atan2_approx(offset.X, offset.Y);
     948        angle);
    970949
    971950        // Calculate the mean speed over this past turn.
     
    973952    }
    974953
    975     if (wasObstructed && HandleObstructedMove(pos != initialPos))
     954    if (initialPos))
    976955        return;
    977     else if (!wasObstructed && pos != initialPos)
     956    else if (!initialPos)
    978957        m_FailedMovements = 0;
    979958
    980959    // We may need to recompute our path sometimes (e.g. if our target moves).
    981960    // Since we request paths asynchronously anyways, this does not need to be done before moving.
    982     if (!wentStraight && PathingUpdateNeeded(pos))
     961    if (!pos))
    983962    {
    984963        PathGoal goal;
    985964        if (ComputeGoal(goal, m_MoveRequest))
    986             ComputePathToGoal(pos, goal);
     965            ComputePathToGoal(pos, goal);
    987966    }
    988967    else if (m_FollowKnownImperfectPathCountdown > 0)
     
    12771256        // TODO: This does not really aim many turns in advance, with orthogonal trajectories it probably should.
    12781257        CmpPtr<ICmpUnitMotion> cmpUnitMotion(GetSimContext(), moveRequest.m_Entity);
    1279         bool needInterpolation = cmpUnitMotion && cmpUnitMotion->IsMoveRequested() && m_InMotionMessage;
     1258        CmpPtr<ICmpUnitMotionManager> cmpUnitMotionManager(GetSystemEntity());
     1259        bool needInterpolation = cmpUnitMotion && cmpUnitMotion->IsMoveRequested() && cmpUnitMotionManager->ComputingMotion();
    12801260        if (needInterpolation && GetEntityId() < moveRequest.m_Entity)
    12811261        {
  • ps/trunk/source/simulation2/components/ICmpUnitMotion.cpp

    r24707 r25071  
    4848public:
    4949    DEFAULT_SCRIPT_WRAPPER(UnitMotionScripted)
     50
     51
     52
     53
     54
     55
     56
     57
    5058
    5159    virtual bool MoveToPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t minRange, entity_pos_t maxRange)
  • ps/trunk/source/simulation2/components/ICmpUnitMotion.h

    r24701 r25071  
    2323#include "simulation2/components/ICmpPathfinder.h" // for pass_class_t
    2424#include "simulation2/components/ICmpPosition.h" // for entity_pos_t
     25
     26
     27
    2528
    2629/**
     
    3437class ICmpUnitMotion : public IComponent
    3538{
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
    3650public:
    3751
  • ps/trunk/source/simulation2/system/ComponentManager.cpp

    r24969 r25071  
    678678    AddComponent(m_SystemEntity, CID_Terrain, noParam);
    679679    AddComponent(m_SystemEntity, CID_TerritoryManager, noParam);
     680
    680681    AddComponent(m_SystemEntity, CID_UnitRenderer, noParam);
    681682    AddComponent(m_SystemEntity, CID_WaterManager, noParam);
Note: See TracChangeset for help on using the changeset viewer.