UnitMotion - Fix Clearance serialization and only allow changing passability of formation controllers.

Fixes 5de50c447c

Changing the passability class at runtime breaks some UnitMotion
assumptions in unrecoverable ways and will lead to units getting into
impassable terrain.
Formation controllers can tolerate it since units still check their own
obstruction.
Until some code is added to recover from the above bad case,
de-activated changing passability class for non-formation controllers.

This also fixes serialization issues related to clearance & passability
classes following that diff.

Reviewed By: Freagarach
Differential Revision: https://code.wildfiregames.com/D4629
This was SVN commit r26865.
This commit is contained in:
wraitii 2022-05-09 17:29:15 +00:00
parent db8d251a8b
commit 2ccd1ba280

View file

@ -300,20 +300,12 @@ public:
m_TemplateWeight = paramNode.GetChild("Weight").ToFixed();
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
{
m_PassClassName = paramNode.GetChild("PassabilityClass").ToString();
m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName);
m_Clearance = cmpPathfinder->GetClearance(m_PassClass);
m_PassClassName = paramNode.GetChild("PassabilityClass").ToString();
SetPassabilityData(m_PassClassName);
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
if (cmpObstruction)
{
cmpObstruction->SetUnitClearance(m_Clearance);
m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true);
}
}
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
if (cmpObstruction)
m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true);
SetParticipateInPushing(!paramNode.GetChild("DisablePushing").IsOk() || !paramNode.GetChild("DisablePushing").ToBool());
@ -327,6 +319,7 @@ public:
template<typename S>
void SerializeCommon(S& serialize)
{
// m_Clearance and m_PassClass are constructed from this.
serialize.StringASCII("pass class", m_PassClassName, 0, 64);
serialize.NumberU32_Unbounded("ticket", m_ExpectedPathTicket.m_Ticket);
@ -371,9 +364,7 @@ public:
SerializeCommon(deserialize);
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName);
SetPassabilityData(m_PassClassName);
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
if (cmpObstruction)
@ -519,10 +510,12 @@ public:
void SetPassabilityClassName(const std::string& passClassName) override
{
m_PassClassName = passClassName;
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
m_PassClass = cmpPathfinder->GetPassabilityClass(passClassName);
if (!m_IsFormationController)
{
LOGWARNING("Only formation controllers can change their passability class");
return;
}
SetPassabilityData(passClassName);
}
fixed GetCurrentSpeed() const override
@ -628,6 +621,21 @@ private:
m_Pushing = pushing && cmpUnitMotionManager->IsPushingActivated();
}
void SetPassabilityData(const std::string& passClassName)
{
m_PassClassName = passClassName;
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity());
if (cmpPathfinder)
{
m_PassClass = cmpPathfinder->GetPassabilityClass(passClassName);
m_Clearance = cmpPathfinder->GetClearance(m_PassClass);
CmpPtr<ICmpObstruction> cmpObstruction(GetEntityHandle());
if (cmpObstruction)
cmpObstruction->SetUnitClearance(m_Clearance);
}
}
/**
* Warns other components that our current movement will likely fail (e.g. we won't be able to reach our target)
* This should only be called before the actual movement in a given turn, or units might both move and try to do things