From 2ccd1ba280cb8aaee796fd9052c3132f2b011aed Mon Sep 17 00:00:00 2001 From: wraitii Date: Mon, 9 May 2022 17:29:15 +0000 Subject: [PATCH] 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. --- .../simulation2/components/CCmpUnitMotion.h | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/source/simulation2/components/CCmpUnitMotion.h b/source/simulation2/components/CCmpUnitMotion.h index e74027b4e0..c182fa67d7 100644 --- a/source/simulation2/components/CCmpUnitMotion.h +++ b/source/simulation2/components/CCmpUnitMotion.h @@ -300,20 +300,12 @@ public: m_TemplateWeight = paramNode.GetChild("Weight").ToFixed(); - CmpPtr 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 cmpObstruction(GetEntityHandle()); - if (cmpObstruction) - { - cmpObstruction->SetUnitClearance(m_Clearance); - m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true); - } - } + CmpPtr cmpObstruction(GetEntityHandle()); + if (cmpObstruction) + m_BlockMovement = cmpObstruction->GetBlockMovementFlag(true); SetParticipateInPushing(!paramNode.GetChild("DisablePushing").IsOk() || !paramNode.GetChild("DisablePushing").ToBool()); @@ -327,6 +319,7 @@ public: template 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 cmpPathfinder(GetSystemEntity()); - if (cmpPathfinder) - m_PassClass = cmpPathfinder->GetPassabilityClass(m_PassClassName); + SetPassabilityData(m_PassClassName); CmpPtr cmpObstruction(GetEntityHandle()); if (cmpObstruction) @@ -519,10 +510,12 @@ public: void SetPassabilityClassName(const std::string& passClassName) override { - m_PassClassName = passClassName; - CmpPtr 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 cmpPathfinder(GetSystemEntity()); + if (cmpPathfinder) + { + m_PassClass = cmpPathfinder->GetPassabilityClass(passClassName); + m_Clearance = cmpPathfinder->GetClearance(m_PassClass); + + CmpPtr 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