Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 03 Jul 2026 01:13:20 +0000
From:      Olivier Cochard <olivier@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   git: a1df7f2494b8 - main - games/CWR-CE: Fix some game logic bugs
Message-ID:  <6a470cb0.31963.59ca5142@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by olivier:

URL: https://cgit.FreeBSD.org/ports/commit/?id=a1df7f2494b8da920925adf9e8cb44a4c21d87f6

commit a1df7f2494b8da920925adf9e8cb44a4c21d87f6
Author:     Olivier Cochard <olivier@FreeBSD.org>
AuthorDate: 2026-07-03 00:55:45 +0000
Commit:     Olivier Cochard <olivier@FreeBSD.org>
CommitDate: 2026-07-03 01:11:33 +0000

    games/CWR-CE: Fix some game logic bugs
---
 games/CWR-CE/Makefile                              |   4 +-
 games/CWR-CE/distinfo                              |   8 +-
 .../files/patch-engine_Poseidon_AI_AIGroupImpl.cpp | 118 +++++++++++++++++++++
 ...idon_World_Entities_Infantry_SoldierOldMove.cpp |  15 +++
 ..._Poseidon_World_Entities_Vehicles_Transport.cpp |  16 +++
 ...eidon_World_Entities_Vehicles_TransportCore.cpp |  39 +++++++
 6 files changed, 193 insertions(+), 7 deletions(-)

diff --git a/games/CWR-CE/Makefile b/games/CWR-CE/Makefile
index 614406cd3e5c..40bc1ff79861 100644
--- a/games/CWR-CE/Makefile
+++ b/games/CWR-CE/Makefile
@@ -1,11 +1,11 @@
 PORTNAME=	CWR-CE
 DISTVERSIONPREFIX=	v
 DISTVERSION=	3.01
+PORTREVISION=	1
 CATEGORIES=	games
 
 PATCH_SITES=	https://github.com/ocochard/CWR-CE/compare/
-PATCHFILES=	9abbdf2769f3008d76c47ac0af219388ff0323dc..b6c9690f03cf0abb6af577db7294b00c30f4172c.patch:-p1 \
-		b6c9690f03cf0abb6af577db7294b00c30f4172c..85dd554fc9e21312ee52d7f9eced6b171a6a892b.patch:-p1
+PATCHFILES=	9abbdf2769f3008d76c47ac0af219388ff0323dc..55e703228bf5649a6a847d724e94b97d94d7057f.patch:-p1
 
 MAINTAINER=	olivier@FreeBSD.org
 COMMENT=	Arma: Cold War Assault - Remastered Community Edition
diff --git a/games/CWR-CE/distinfo b/games/CWR-CE/distinfo
index 670262e54b4a..290b2c2de3e3 100644
--- a/games/CWR-CE/distinfo
+++ b/games/CWR-CE/distinfo
@@ -1,7 +1,5 @@
-TIMESTAMP = 1782950316
+TIMESTAMP = 1783002492
 SHA256 (ofpisnotdead-com-CWR-CE-v3.01-9abbdf2769f3008d76c47ac0af219388ff0323dc_GH0.tar.gz) = 87df6297ed74993d56d3ceec9d90fb9287cebc58f47030a285a2eafb61c3ce22
 SIZE (ofpisnotdead-com-CWR-CE-v3.01-9abbdf2769f3008d76c47ac0af219388ff0323dc_GH0.tar.gz) = 4944610
-SHA256 (9abbdf2769f3008d76c47ac0af219388ff0323dc..b6c9690f03cf0abb6af577db7294b00c30f4172c.patch) = 8add6877aae7534967c2f609026cd4c4aa861a41f27d6cd68ec89c052e56d31d
-SIZE (9abbdf2769f3008d76c47ac0af219388ff0323dc..b6c9690f03cf0abb6af577db7294b00c30f4172c.patch) = 23346
-SHA256 (b6c9690f03cf0abb6af577db7294b00c30f4172c..85dd554fc9e21312ee52d7f9eced6b171a6a892b.patch) = d87ab832d44d46ae761c8a920463a70b5e8369477a0eda327b4be6995b139e7f
-SIZE (b6c9690f03cf0abb6af577db7294b00c30f4172c..85dd554fc9e21312ee52d7f9eced6b171a6a892b.patch) = 18184
+SHA256 (9abbdf2769f3008d76c47ac0af219388ff0323dc..55e703228bf5649a6a847d724e94b97d94d7057f.patch) = c744b9b9bf7b1917ac159b8af41cfe354d2f8e646eb7b6722953f56583053df8
+SIZE (9abbdf2769f3008d76c47ac0af219388ff0323dc..55e703228bf5649a6a847d724e94b97d94d7057f.patch) = 41794
diff --git a/games/CWR-CE/files/patch-engine_Poseidon_AI_AIGroupImpl.cpp b/games/CWR-CE/files/patch-engine_Poseidon_AI_AIGroupImpl.cpp
new file mode 100644
index 000000000000..9c4ce16cee2e
--- /dev/null
+++ b/games/CWR-CE/files/patch-engine_Poseidon_AI_AIGroupImpl.cpp
@@ -0,0 +1,118 @@
+diff --git engine/Poseidon/AI/AIGroupImpl.cpp engine/Poseidon/AI/AIGroupImpl.cpp
+index eeaffd9..22d895b 100644
+--- engine/Poseidon/AI/AIGroupImpl.cpp
++++ engine/Poseidon/AI/AIGroupImpl.cpp
+@@ -41,6 +41,22 @@ namespace Poseidon
+ {
+ using namespace Foundation;
+ 
++// Diagnostic for msgCmd->GetFrom() == this invariant violations in the radio
++// queue scans below. Returns the result of the check so call sites can be
++// written as `if (!CheckMsgCmdFrom(...)) continue;` in future patches.
++static bool CheckMsgCmdFrom(const AIGroup* self, RadioMessageCommand* msgCmd, const char* callSite)
++{
++    if (msgCmd->GetFrom() == self)
++    {
++        return true;
++    }
++    LOG_ERROR(AI, "AIGroup radio queue holds foreign command at {}: this={} ({}), from={} ({}), msgType={}", callSite,
++              self ? (const char*)self->GetDebugName() : "null", (const void*)self,
++              msgCmd->GetFrom() ? (const char*)msgCmd->GetFrom()->GetDebugName() : "null",
++              (const void*)msgCmd->GetFrom(), msgCmd->GetType());
++    return false;
++}
++
+ // Parameters
+ 
+ bool AIGroup::CommandSent(bool channelCenter)
+@@ -72,7 +88,10 @@ bool AIGroup::CommandSent(bool channelCenter)
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        if (!channelCenter)
++        {
++            CheckMsgCmdFrom(this, msgCmd, "CommandSent(bool)/FindPrevMessage");
++        }
+         if (msgCmd->IsToMainSubgroup())
+         {
+             return true;
+@@ -86,7 +105,10 @@ bool AIGroup::CommandSent(bool channelCenter)
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        if (!channelCenter)
++        {
++            CheckMsgCmdFrom(this, msgCmd, "CommandSent(bool)/GetActualMessage");
++        }
+         if (msgCmd->IsToMainSubgroup())
+         {
+             return true;
+@@ -139,7 +161,10 @@ bool AIGroup::CommandSent(Command::Message message, bool channelCenter)
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        if (!channelCenter)
++        {
++            CheckMsgCmdFrom(this, msgCmd, "CommandSent(msg,bool)/FindPrevMessage");
++        }
+         if (msgCmd->GetCmdMessage() == message)
+         {
+             return true;
+@@ -152,7 +177,10 @@ bool AIGroup::CommandSent(Command::Message message, bool channelCenter)
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        if (!channelCenter)
++        {
++            CheckMsgCmdFrom(this, msgCmd, "CommandSent(msg,bool)/GetActualMessage");
++        }
+         if (msgCmd->GetCmdMessage() == message)
+         {
+             return true;
+@@ -200,7 +228,10 @@ bool AIGroup::CommandSent(AIUnit* to, Command::Message message, bool channelCent
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        if (!channelCenter)
++        {
++            CheckMsgCmdFrom(this, msgCmd, "CommandSent(to,msg,bool)/FindPrevMessage");
++        }
+         if (msgCmd->IsTo(to) && msgCmd->GetCmdMessage() == message)
+         {
+             return true;
+@@ -213,7 +244,10 @@ bool AIGroup::CommandSent(AIUnit* to, Command::Message message, bool channelCent
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        if (!channelCenter)
++        {
++            CheckMsgCmdFrom(this, msgCmd, "CommandSent(to,msg,bool)/GetActualMessage");
++        }
+         if (msgCmd->IsTo(to) && msgCmd->GetCmdMessage() == message)
+         {
+             return true;
+@@ -237,7 +271,7 @@ void AIGroup::ClearGetInCommands(AIUnit* to)
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        CheckMsgCmdFrom(this, msgCmd, "ClearGetInCommands/FindPrevMessage");
+         if (msgCmd->IsTo(to) && msgCmd->GetCmdMessage() == Command::GetIn &&
+             (msgCmd->GetContext() == Command::CtxAuto || msgCmd->GetContext() == Command::CtxAutoSilent))
+         {
+@@ -252,8 +286,7 @@ void AIGroup::ClearGetInCommands(AIUnit* to)
+         AI_ERROR(dynamic_cast<RadioMessageCommand*>(msg));
+         RadioMessageCommand* msgCmd = static_cast<RadioMessageCommand*>(msg);
+         AI_ERROR(msgCmd);
+-        AI_ERROR(msgCmd->GetFrom() == this);
+-        AI_ERROR(msgCmd->GetFrom() == this);
++        CheckMsgCmdFrom(this, msgCmd, "ClearGetInCommands/GetActualMessage");
+         if (msgCmd->IsTo(to) && msgCmd->GetCmdMessage() == Command::GetIn &&
+             (msgCmd->GetContext() == Command::CtxAuto || msgCmd->GetContext() == Command::CtxAutoSilent))
+         {
diff --git a/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Infantry_SoldierOldMove.cpp b/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Infantry_SoldierOldMove.cpp
new file mode 100644
index 000000000000..0997c5ae7df3
--- /dev/null
+++ b/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Infantry_SoldierOldMove.cpp
@@ -0,0 +1,15 @@
+diff --git engine/Poseidon/World/Entities/Infantry/SoldierOldMove.cpp engine/Poseidon/World/Entities/Infantry/SoldierOldMove.cpp
+index 87c660d..7ac63e8 100644
+--- engine/Poseidon/World/Entities/Infantry/SoldierOldMove.cpp
++++ engine/Poseidon/World/Entities/Infantry/SoldierOldMove.cpp
+@@ -1006,7 +1006,9 @@ namespace Poseidon
+ 
+ void Man::KilledBy(EntityAI* owner)
+ {
+-    PoseidonAssert(_brain);
++    // _brain is null on respawn transfer (NetworkClient.cpp moves the brain
++    // to the new Soldier and nulls the old body's brain). A brainless
++    // corpse taking damage lands here; nothing to do.
+     if (!_brain)
+     {
+         return;
diff --git a/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Vehicles_Transport.cpp b/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Vehicles_Transport.cpp
new file mode 100644
index 000000000000..7910fd3863ec
--- /dev/null
+++ b/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Vehicles_Transport.cpp
@@ -0,0 +1,16 @@
+diff --git engine/Poseidon/World/Entities/Vehicles/Transport.cpp engine/Poseidon/World/Entities/Vehicles/Transport.cpp
+index eb2d624..44da61b 100644
+--- engine/Poseidon/World/Entities/Vehicles/Transport.cpp
++++ engine/Poseidon/World/Entities/Vehicles/Transport.cpp
+@@ -1591,7 +1591,10 @@ void VehicleSupply::SupplyStarted(AIUnit* unit)
+ {
+     LOG_DEBUG(Physics, "{} SupplyStarted for {}", (const char*)GetDebugName(), (const char*)unit->GetDebugName());
+ 
+-    PoseidonAssert(_supplyUnits.Find(unit) < 0);
++    // A re-entry of the supply FSM state (e.g. Supply->Move->Supply when the
++    // client drifts out of range and comes back) can call SupplyStarted for
++    // a unit that never emitted a matching SupplyFinished. AddUnique below
++    // handles the duplicate; the assert is stale.
+     _supplyUnits.AddUnique(unit);
+ }
+ 
diff --git a/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Vehicles_TransportCore.cpp b/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Vehicles_TransportCore.cpp
new file mode 100644
index 000000000000..18575224684a
--- /dev/null
+++ b/games/CWR-CE/files/patch-engine_Poseidon_World_Entities_Vehicles_TransportCore.cpp
@@ -0,0 +1,39 @@
+diff --git engine/Poseidon/World/Entities/Vehicles/TransportCore.cpp engine/Poseidon/World/Entities/Vehicles/TransportCore.cpp
+index df48f09..c6fb37b 100644
+--- engine/Poseidon/World/Entities/Vehicles/TransportCore.cpp
++++ engine/Poseidon/World/Entities/Vehicles/TransportCore.cpp
+@@ -350,7 +350,8 @@ void Transport::DammageCrew(EntityAI* killer, float howMuch, RString ammo)
+         }
+         if (CrewDammage(this, man, killer, howMuch, ammo))
+         {
+-            if (man)
++            // Skip brainless corpses (post-respawn bodies still riding as cargo).
++            if (man && man->Brain())
+             {
+                 man->KilledBy(killer);
+             }
+@@ -358,21 +359,21 @@ void Transport::DammageCrew(EntityAI* killer, float howMuch, RString ammo)
+     }
+     if (CrewDammage(this, _driver, killer, howMuch, ammo))
+     {
+-        if (_driver)
++        if (_driver && _driver->Brain())
+         {
+             _driver->KilledBy(killer);
+         }
+     }
+     if (CrewDammage(this, _gunner, killer, howMuch, ammo))
+     {
+-        if (_gunner)
++        if (_gunner && _gunner->Brain())
+         {
+             _gunner->KilledBy(killer);
+         }
+     }
+     if (CrewDammage(this, _commander, killer, howMuch, ammo))
+     {
+-        if (_commander)
++        if (_commander && _commander->Brain())
+         {
+             _commander->KilledBy(killer);
+         }


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a470cb0.31963.59ca5142>