Files
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

159 lines
5.8 KiB
Diff

--- a/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c
+++ b/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeSmoke.c
@@ -1,5 +1,36 @@
// Explicit, local Workbench diagnostic only. Never compiled into game/server builds.
#ifdef WORKBENCH
+class ERR_DeathDiagnostic
+{
+ static bool Enabled()
+ {
+ string smoke;
+ string outcome;
+ if (!System.GetCLIParam("errSmoke", smoke) || smoke != "1") return false;
+ return System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "player-death";
+ }
+ static void Event(string stage)
+ {
+ if (Enabled()) PrintFormat("ERR DEATH DIAGNOSTIC: %1", stage);
+ }
+ static void Actor(string stage, IEntity actor)
+ {
+ if (!Enabled()) return;
+ bool revivable;
+ bool unconscious;
+ SCR_CharacterDamageManagerComponent medical;
+ CharacterControllerComponent controller;
+ if (actor)
+ {
+ medical = SCR_CharacterDamageManagerComponent.Cast(actor.FindComponent(SCR_CharacterDamageManagerComponent));
+ controller = CharacterControllerComponent.Cast(actor.FindComponent(CharacterControllerComponent));
+ }
+ if (medical) revivable = medical.ERR_IsRevivablePlayer();
+ if (controller) unconscious = controller.IsUnconscious();
+ PrintFormat("ERR DEATH DIAGNOSTIC: %1 actor=%2 alive=%3 revivable=%4 unconscious=%5", stage, actor, ERR_Actors.Alive(actor), revivable, unconscious);
+ }
+}
+
modded class ERR_GameMode
{
protected bool m_ERRTestPatrolHQ;
@@ -756,7 +787,10 @@
if (m_ERRTestPlayerDeath)
{
m_ERRSmokeStep = 9;
+ ERR_DeathDiagnostic.Actor("fixture before Kill", m_ERRSmokePlayer);
SCR_CharacterDamageManagerComponent.Cast(m_ERRSmokePlayer.FindComponent(SCR_CharacterDamageManagerComponent)).Kill(Instigator.CreateInstigator(m_ERRSmokePlayer));
+ ERR_DeathDiagnostic.Actor("fixture after Kill", m_ERRSmokePlayer);
+ if (ERR_DeathDiagnostic.Enabled()) GetGame().GetCallqueue().CallLater(ERR_DeathSample, 250, false);
m_ERRSmokeWait = now + 4000;
return;
}
@@ -1048,10 +1082,15 @@
m_ERRSmokeWait = now + 5000;
}
}
+ protected void ERR_DeathSample()
+ {
+ ERR_DeathDiagnostic.Actor("fixture queued 250ms sample", m_ERRSmokePlayer);
+ }
void ~ERR_GameMode()
{
if (GetGame())
{
+ GetGame().GetCallqueue().Remove(ERR_DeathSample);
GetGame().GetCallqueue().Remove(ERR_SmokeTick);
GetGame().GetCallqueue().Remove(ERR_PrisonScreenshot);
GetGame().GetCallqueue().Remove(ERR_EndScreenshot);
--- a/addons/core/Scripts/Game/ERR/00_Core/ERR_PlayerMedical.c
+++ b/addons/core/Scripts/Game/ERR/00_Core/ERR_PlayerMedical.c
@@ -27,6 +27,9 @@
// the native damage pipeline. The lethal damage itself is clamped synchronously.
void ERR_RequestKnockout()
{
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Actor("RequestKnockout entry", GetOwner());
+#endif
if (!Replication.IsServer() || !m_ERRRevivablePlayer || m_ERRKnockoutPending) return;
CharacterControllerComponent controller = CharacterControllerComponent.Cast(GetOwner().FindComponent(CharacterControllerComponent));
if (controller && controller.IsUnconscious()) return;
@@ -35,13 +38,22 @@
}
protected void ERR_ApplyKnockout()
{
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Actor("ApplyKnockout entry", GetOwner());
+#endif
m_ERRKnockoutPending = false;
if (!m_ERRRevivablePlayer || !ERR_Actors.Alive(GetOwner())) return;
ForceUnconsciousness();
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Actor("ApplyKnockout after ForceUnconsciousness", GetOwner());
+#endif
ERR_HQ.Event("PLAYER CASUALTY", "Lethal injury prevented; prisoner remains alive and can receive medical treatment.");
}
override void Kill(notnull Instigator instigator)
{
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Actor("Kill override entry", GetOwner());
+#endif
if (!m_ERRRevivablePlayer) { super.Kill(instigator); return; }
ERR_RequestKnockout();
}
--- a/addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnLogic.c
+++ b/addons/core/Scripts/Game/ERR/00_Core/ERR_SpawnLogic.c
@@ -318,12 +318,30 @@
}
protected void ObserveAfterLoss(int playerId, UUID identity, SCR_PlayerController expectedController)
{
- if (!expectedController || !m_Identities.Contains(playerId) || m_Identities.Get(playerId) != identity) return;
- if (GetGame().GetPlayerManager().GetPlayerController(playerId) != expectedController || ERR_Actors.Alive(expectedController.GetControlledEntity())) return;
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Event("ObserveAfterLoss entry");
+#endif
+ if (!expectedController || !m_Identities.Contains(playerId) || m_Identities.Get(playerId) != identity)
+ {
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Event("ObserveAfterLoss rejected controller/account");
+#endif
+ return;
+ }
+ if (GetGame().GetPlayerManager().GetPlayerController(playerId) != expectedController || ERR_Actors.Alive(expectedController.GetControlledEntity()))
+ {
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Event("ObserveAfterLoss rejected controller/body");
+#endif
+ return;
+ }
ERR_GameMode mode = ERR_GameMode.Get();
ERR_PlayerLife life;
if (mode) life = mode.Players().Get(playerId);
if (life && life.UsedLife) Observe(playerId, ERR_ObserverReason.SPENT_LIFE);
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Event("ObserveAfterLoss completed");
+#endif
}
override void OnPlayerSpawned_S(int playerId, IEntity entity)
{
--- a/addons/core/Scripts/Game/ERR/00_Core/ERR_GameMode.c
+++ b/addons/core/Scripts/Game/ERR/00_Core/ERR_GameMode.c
@@ -568,6 +568,9 @@
// Transition(). Close the successor before vanilla publishes/restarts the round.
protected override void OnGameModeEnd(SCR_GameModeEndData endData)
{
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Event("OnGameModeEnd entry");
+#endif
if (m_NativeEndHandled) return;
m_NativeEndHandled = true;
StopLocalViewDistance();
@@ -619,6 +622,9 @@
void ~ERR_GameMode()
{
+#ifdef WORKBENCH
+ ERR_DeathDiagnostic.Event("GameMode destructor entry");
+#endif
if (GetGame())
{
GetGame().GetCallqueue().Remove(StartScenario);