Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
159 lines
5.8 KiB
Diff
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);
|