Files
EscapistsReintroduced/docs/evidence/native-2026-09-29-camera-pose-diagnostic/diagnostic-probe.c.txt
T
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

213 lines
14 KiB
Plaintext

#ifdef WORKBENCH
modded class SCR_CharacterControllerComponent
{
bool m_ERRViewInput;
vector m_ERRViewAim, m_ERRViewLook;
float m_ERRViewLean;
override protected void OnApplyControls(IEntity owner, float timeSlice)
{
super.OnApplyControls(owner, timeSlice);
if (!m_ERRViewInput) return;
CharacterInputContext input = GetInputContext();
input.SetAimingAngles(m_ERRViewAim);
input.SetFreelook(m_ERRViewLook != vector.Zero);
input.SetLookAtAngles(m_ERRViewLook);
input.SetLean(m_ERRViewLean);
}
}
// The local native runner has one real player. A physical stand-in tests camera
// tracking; canonical multiplayer target selection is tested separately.
modded class SCR_PlayerController
{
protected IEntity m_ERRCameraProbeTarget;
void ERR_ProbeCameraTarget(IEntity target) { m_ERRCameraProbeTarget = target; }
override IEntity ERR_ObservedEntity()
{
string outcome;
if (m_ERRCameraProbeTarget && System.GetCLIParam("errSmokeOutcome", outcome) && outcome == "unconscious-camera") return m_ERRCameraProbeTarget;
return super.ERR_ObservedEntity();
}
ERR_FollowSurvivorCameraComponent ERR_ProbeFollowComponent()
{
if (!m_ERRObserverCamera) return null;
return ERR_FollowSurvivorCameraComponent.Cast(m_ERRObserverCamera.FindCameraComponent(ERR_FollowSurvivorCameraComponent));
}
bool ERR_ProbeCameraActive()
{
return m_ERRObserverCamera && GetGame().GetCameraManager().CurrentCamera() == m_ERRObserverCamera;
}
}
modded class ERR_GameMode
{
protected int m_ERRCameraStage = -2;
protected int m_ERRCameraDeadline;
protected IEntity m_ERRCameraWeapon;
protected float m_ERRCameraWait;
protected IEntity m_ERRCameraBody, m_ERRCameraTarget;
protected SCR_CharacterDamageManagerComponent m_ERRCameraDamage;
protected SCR_ManualCamera m_ERRCameraOther;
protected int m_ERRViewSample;
protected override void EOnInit(IEntity owner)
{
super.EOnInit(owner);
string outcome;
if (SCR_Global.IsEditMode() || !Replication.IsServer() || !System.GetCLIParam("errSmokeOutcome", outcome) || outcome != "unconscious-camera") return;
m_ERRCameraDeadline = System.GetTickCount() + 180000;
GetGame().GetCallqueue().CallLater(ERR_CameraProbeTick, 500, true);
}
protected bool ERR_CameraCheck(bool ok, string message)
{
if (ok) { Print("ERR SMOKE PASS: unconscious camera " + message); return true; }
Print("ERR SMOKE FAIL: unconscious camera " + message, LogLevel.ERROR);
GetGame().GetCallqueue().Remove(ERR_CameraProbeTick); return false;
}
protected void ERR_CameraKnockout()
{
m_ERRCameraDamage.ForceUnconsciousness();
array<ref SCR_PersistentDamageEffect> effects = m_ERRCameraDamage.GetAllPersistentEffectsOfType(SCR_PassiveHitZoneRegenDamageEffect);
foreach (SCR_PersistentDamageEffect effect : effects) m_ERRCameraDamage.TerminateDamageEffect(effect);
m_ERRCameraDamage.SetGroupIsBeingHealed(ECharacterHitZoneGroup.RIGHTARM, true);
}
protected void ERR_CameraProbeTick()
{
if (System.GetTickCount() >= m_ERRCameraDeadline || !PreparationError().IsEmpty()) { ERR_CameraCheck(false, "deadline/preparation " + PreparationError()); return; }
if (!Active()) return;
SCR_PlayerController pc = SCR_PlayerController.Cast(GetGame().GetPlayerController());
if (!pc || !pc.GetControlledEntity()) return;
float now = GetWorld().GetWorldTime();
if (now < m_ERRCameraWait) return;
if (m_ERRCameraStage == -2)
{
if (!ERR_CameraCheck(Settings().Get("keepWeaponOnUnconscious") == 1, "weapon retention defaults to enabled")) return;
m_ERRCameraBody = pc.GetControlledEntity();
InventoryStorageManagerComponent inventory = InventoryStorageManagerComponent.Cast(m_ERRCameraBody.FindComponent(InventoryStorageManagerComponent));
m_ERRCameraWeapon = ERR_Actors.Spawn("{FA5C25BF66A53DCF}Prefabs/Weapons/Rifles/AK74/Rifle_AK74.et", m_ERRCameraBody.GetOrigin()); Own(m_ERRCameraWeapon);
if (!ERR_CameraCheck(m_ERRCameraWeapon && inventory && inventory.TryInsertItem(m_ERRCameraWeapon, EStoragePurpose.PURPOSE_WEAPON_PROXY), "one physical rifle granted to the player")) return;
m_ERRCameraStage = -1; m_ERRCameraWait = now + 1500; return;
}
SCR_CharacterControllerComponent character = SCR_CharacterControllerComponent.Cast(m_ERRCameraBody.FindComponent(SCR_CharacterControllerComponent));
InventoryStorageManagerComponent playerInventory = character.GetInventoryStorageManager();
if (m_ERRCameraStage == -1)
{
BaseWeaponComponent weapon = BaseWeaponComponent.Cast(m_ERRCameraWeapon.FindComponent(BaseWeaponComponent));
if (!ERR_CameraCheck(playerInventory.Contains(m_ERRCameraWeapon) && character.SelectWeapon(weapon), "rifle selected with native equip animation")) return;
CameraHandlerComponent.Cast(m_ERRCameraBody.FindComponent(CameraHandlerComponent)).SetThirdPerson(false);
character.m_ERRViewInput = true;
character.m_ERRViewAim = "0.6 0.15 0";
m_ERRCameraStage = -10; m_ERRCameraWait = now + 2000; return;
}
if (m_ERRCameraStage == -10)
{
vector actual[4], observed[4], world[4];
pc.GetPlayerCamera().GetWorldTransform(actual);
ERR_FollowSurvivorCameraComponent.PlayerView(m_ERRCameraBody, observed);
m_ERRCameraBody.GetWorldTransform(world);
ChimeraCharacter body = ChimeraCharacter.Cast(m_ERRCameraBody);
vector pose = body.GetAimRotationModel();
vector poseDirection = (pose * Math.RAD2DEG).AnglesToVector().Multiply3(world);
PrintFormat("ERR VIEW POSE: sample=%1 native=%2 current=%3 pose=%4 look=%5 aim=%6 head=%7", m_ERRViewSample, actual[2], observed[2], poseDirection, character.GetHeadAimingComponent().GetLookAngles(), pose, character.GetHeadAimingComponent().GetAimingRotation());
PrintFormat("ERR VIEW STATE: freeLook=%1 lean=%2 nativePosition=%3 headViewPosition=%4", character.IsFreeLookEnabled(), character.GetLeaning(), actual[3], observed[3]);
m_ERRViewSample++;
if (m_ERRViewSample == 2) character.m_ERRViewLook = "0.5 -0.2 0";
if (m_ERRViewSample == 4) { character.m_ERRViewLook = vector.Zero; character.m_ERRViewLean = 1; }
if (m_ERRViewSample == 6) character.m_ERRViewLean = -1;
if (m_ERRViewSample == 8)
{
character.m_ERRViewLean = 0;
m_ERRCameraBody.SetYawPitchRoll("90 0 0");
}
if (m_ERRViewSample >= 10)
{
character.m_ERRViewInput = false;
m_ERRCameraStage = 0;
}
m_ERRCameraWait = now + 2000;
return;
}
if (m_ERRCameraStage == 0)
{
if (!ERR_CameraCheck(character.GetWeaponManagerComponent().GetCurrentWeapon() && character.GetWeaponManagerComponent().GetCurrentWeapon().GetOwner() == m_ERRCameraWeapon, "original rifle actually in hand before knockout")) return;
m_ERRCameraBody = pc.GetControlledEntity();
m_ERRCameraDamage = SCR_CharacterDamageManagerComponent.Cast(m_ERRCameraBody.FindComponent(SCR_CharacterDamageManagerComponent));
if (!ERR_CameraCheck(m_ERRCameraDamage && m_ERRCameraDamage.ERR_IsRevivablePlayer(), "admitted player retains treatable body")) return;
ERR_CameraKnockout(); m_ERRCameraStage = 1; m_ERRCameraWait = now + 3000; return;
}
if (m_ERRCameraStage == 1)
{
if (!ERR_CameraCheck(pc.ERR_ObserverState() == ERR_ObserverReason.UNCONSCIOUS && pc.ERR_ProbeCameraActive(), "native knockout automatically opens the manual third-person camera")) return;
if (!ERR_CameraCheck(pc.GetControlledEntity() == m_ERRCameraBody && ERR_Actors.Alive(m_ERRCameraBody) && !ERR_Actors.CanFight(m_ERRCameraBody), "possession and living unconscious body unchanged")) return;
if (!ERR_CameraCheck(!pc.ERR_ObservedEntity() && vector.DistanceXZ(pc.ERR_ObserverAnchor(), m_ERRCameraBody.GetOrigin()) < 1, "no teammate falls back to the casualty body")) return;
if (!ERR_CameraCheck(playerInventory.Contains(m_ERRCameraWeapon), "enabled retention keeps the exact rifle with the unconscious player")) return;
vector point = ERR_Actors.Ground(m_ERRCameraBody.GetOrigin() + "25 0 25");
m_ERRCameraTarget = ERR_Actors.Spawn(Factions().PrisonerPrefab, point); Own(m_ERRCameraTarget);
if (!ERR_CameraCheck(m_ERRCameraTarget != null, "physical follow-target stand-in created")) return;
pc.ERR_ProbeCameraTarget(m_ERRCameraTarget);
m_ERRCameraStage = 2; m_ERRCameraWait = now + 1500; return;
}
if (m_ERRCameraStage == 2)
{
vector camera = GetGame().GetCameraManager().CurrentCamera().GetOrigin();
PrintFormat("ERR CAMERA TRACK: camera=%1 target=%2 body=%3 active=%4 conscious=%5 reason=%6", camera, m_ERRCameraTarget.GetOrigin(), m_ERRCameraBody.GetOrigin(), pc.ERR_ProbeCameraActive(), ERR_Actors.CanFight(m_ERRCameraBody), pc.ERR_ObserverState());
if (!ERR_CameraCheck(vector.Distance(camera, m_ERRCameraTarget.GetOrigin()) < 13 && vector.Distance(camera, m_ERRCameraBody.GetOrigin()) > 15, "camera follows target in 3D without moving the casualty")) return;
m_ERRCameraTarget.SetOrigin(ERR_Actors.Ground(m_ERRCameraTarget.GetOrigin() + "15 0 0"));
m_ERRCameraStage = 3; m_ERRCameraWait = now + 1500; return;
}
if (m_ERRCameraStage == 3)
{
if (!ERR_CameraCheck(vector.Distance(GetGame().GetCameraManager().CurrentCamera().GetOrigin(), m_ERRCameraTarget.GetOrigin()) < 13, "camera tracks a moving target")) return;
InputManager input = GetGame().GetInputManager();
ERR_FollowSurvivorCameraComponent follow = pc.ERR_ProbeFollowComponent();
if (!ERR_CameraCheck(follow != null, "follow component exists")) return;
ResourceName configuredInput;
GameProject.GetModuleConfig("InputManagerSettings").Get("Default", configuredInput);
PrintFormat("ERR CAMERA INPUT: default=%1 context=%2 previous=%3 next=%4 view=%5 orbit=%6", configuredInput, input.IsContextActive("ERR_ObserverContext"), input.IsActionActive("ERR_ObserverPrevious"), input.IsActionActive("ERR_ObserverNext"), input.IsActionActive("ERR_ObserverView"), input.IsActionActive("ManualCameraRotateYaw"));
for (int inputIndex = 0; inputIndex < input.GetActionCount(); inputIndex++)
{
string inputName = input.GetActionName(inputIndex);
if (inputName.Contains("Observer") || inputName == "ManualCameraRotateYaw") Print("ERR CAMERA INPUT REGISTERED: " + inputName);
}
if (!ERR_CameraCheck(follow.InputContextActive() && input.IsActionActive("ERR_ObserverPrevious") && input.IsActionActive("ERR_ObserverNext") && input.IsActionActive("ERR_ObserverView") && input.IsActionActive("ManualCameraRotateYaw"), "dedicated arrow/Enter actions and inherited orbit inputs loaded and active")) return;
follow.Input(true, false, false, true);
if (!ERR_CameraCheck(follow.IsPlayerView(), "Enter handler selects player view")) return;
follow.Input(true, false, false, true);
if (!ERR_CameraCheck(follow.IsPlayerView(), "held Enter does not toggle again")) return;
follow.Input(true, false, false, false);
m_ERRCameraStage = 30; m_ERRCameraWait = now + 1000; return;
}
if (m_ERRCameraStage == 30)
{
vector expected[4];
if (!ERR_CameraCheck(ERR_FollowSurvivorCameraComponent.PlayerView(m_ERRCameraTarget, expected) && vector.Distance(GetGame().GetCameraManager().CurrentCamera().GetOrigin(), expected[3]) < 0.1, "native camera follows teammate head in player view")) return;
pc.ERR_ProbeFollowComponent().Input(true, false, false, true);
pc.ERR_ProbeFollowComponent().Input(true, false, false, false);
m_ERRCameraStage = 31; m_ERRCameraWait = now + 1000; return;
}
if (m_ERRCameraStage == 31)
{
if (!ERR_CameraCheck(!pc.ERR_ProbeFollowComponent().IsPlayerView() && vector.Distance(GetGame().GetCameraManager().CurrentCamera().GetOrigin(), m_ERRCameraTarget.GetOrigin()) > 2, "second Enter restores orbit view")) return;
Resource otherResource = Resource.Load("{EB1210AAE1BB8F54}Prefabs/ERR/SpectatorCamera.et");
m_ERRCameraOther = SCR_ManualCamera.Cast(GetGame().SpawnEntityPrefab(otherResource, GetWorld()));
if (!ERR_CameraCheck(m_ERRCameraOther && GetGame().GetCameraManager().CurrentCamera() == m_ERRCameraOther && !pc.ERR_ProbeCameraActive(), "separate manual camera takes over before recovery")) return;
pc.ERR_ProbeCameraTarget(null); ERR_Actors.DeleteSpawned(m_ERRCameraTarget); m_ERRCameraTarget = null;
m_ERRCameraDamage.SetGroupIsBeingHealed(ECharacterHitZoneGroup.RIGHTARM, false);
m_ERRCameraDamage.FullHeal(); m_ERRCameraStage = 4; m_ERRCameraWait = now + 4000; return;
}
if (m_ERRCameraStage == 4)
{
if (!ERR_CameraCheck(ERR_Actors.CanFight(m_ERRCameraBody) && pc.GetControlledEntity() == m_ERRCameraBody && pc.ERR_ObserverState() == ERR_ObserverReason.NONE && !pc.ERR_HasObserverCamera(), "native healing closes spectator and retains the original conscious player")) return;
if (!ERR_CameraCheck(GetGame().GetCameraManager().CurrentCamera() == pc.GetPlayerCamera(), "normal player camera restored")) return;
if (m_ERRCameraOther) { m_ERRCameraOther.Terminate(); delete m_ERRCameraOther; m_ERRCameraOther = null; }
if (!ERR_CameraCheck(character.GetWeaponManagerComponent().GetCurrentWeapon() && character.GetWeaponManagerComponent().GetCurrentWeapon().GetOwner() == m_ERRCameraWeapon, "revival equips the same rifle without ground pickup")) return;
if (!ERR_CameraCheck(Settings().Set("keepWeaponOnUnconscious", 0), "retention disabled through persistent setting")) return;
ERR_CameraKnockout(); m_ERRCameraStage = 5; m_ERRCameraWait = now + 3000; return;
}
if (!ERR_CameraCheck(pc.ERR_ProbeCameraActive(), "second knockout reopens camera without stale target")) return;
if (!ERR_CameraCheck(!playerInventory.Contains(m_ERRCameraWeapon), "disabled retention leaves normal native weapon drop on ground")) return;
m_ERRCameraDamage.SetGroupIsBeingHealed(ECharacterHitZoneGroup.RIGHTARM, false);
m_ERRCameraDamage.FullHeal();
GetGame().GetCallqueue().Remove(ERR_CameraProbeTick);
Print("ERR SMOKE COMPLETE: unconscious spectator camera, physical tracking, retained treatment body, recovery and repeated knockout; target stand-in, not multiplayer proof");
}
}
#endif