Harden participant and map ownership and validate bounded physical flight

This commit is contained in:
2026-09-19 12:17:01 +02:00
parent dfd7cc49e2
commit 4125018d04
120 changed files with 20043 additions and 47 deletions
@@ -31,6 +31,7 @@ class ERRM_SharedMapComponent : SCR_MapGadgetComponent
protected Widget m_ESMRootWidget;
protected RTTextureWidget m_ESMRenderTarget;
protected SCR_MapEntity m_ESMMapEntity;
protected ref MapConfiguration m_ESMMapConfig;
protected IEntity m_ESMCharacterOwner;
protected bool m_bESMInHand;
protected bool m_bESMOwnsMapRenderer;
@@ -107,12 +108,21 @@ class ERRM_SharedMapComponent : SCR_MapGadgetComponent
MapConfiguration mapConfig = m_ESMMapEntity.SetupMapConfig(EMapEntityMode.PLAIN, MAP_CONFIG, m_ESMRootWidget);
if (!mapConfig)
{
ReleaseMapCapture();
CompleteMapModeSwitch();
return;
}
m_ESMMapEntity.OpenMap(mapConfig);
m_ESMMapConfig = mapConfig;
m_bESMOwnsMapRenderer = true;
m_ESMMapEntity.OpenMap(mapConfig);
if (!OwnsMapCapture())
{
ReleaseMapCapture();
if (m_bESMInHand && GetGame())
GetGame().GetCallqueue().CallLater(TryCaptureMapSurface, MAP_RETRY_DELAY_MS, false);
return;
}
RestoreCharacterCamera();
GetGame().GetCallqueue().CallLater(CenterMapOnHolder, MAP_SETUP_DELAY_MS, false);
@@ -121,7 +131,7 @@ class ERRM_SharedMapComponent : SCR_MapGadgetComponent
protected void CenterMapOnHolder()
{
if (!m_bESMOwnsMapRenderer || !m_ESMMapEntity || !m_ESMCharacterOwner)
if (!OwnsMapCapture() || !m_ESMCharacterOwner)
return;
ERRM_SharedMapComponentClass data = ERRM_SharedMapComponentClass.Cast(GetComponentData(GetOwner()));
@@ -136,19 +146,41 @@ class ERRM_SharedMapComponent : SCR_MapGadgetComponent
{
if (!m_bESMOwnsMapRenderer)
return;
if (!OwnsMapCapture())
{
ReleaseMapCapture();
// A native UI replaced this capture. Do not close, pan, fade or
// focus that UI; use the existing retry path after it closes.
if (m_bESMInHand && GetGame())
GetGame().GetCallqueue().CallLater(TryCaptureMapSurface, MAP_RETRY_DELAY_MS, false);
return;
}
// Freeze the last rendered frame before closing the auxiliary map.
// Leaving the widget enabled would redraw the closed map as an empty
// texture and make the physical map appear to vanish.
ReleaseMapCapture();
CompleteMapModeSwitch();
}
protected bool OwnsMapCapture()
{
if (!GetGame() || !m_bESMOwnsMapRenderer || !m_ESMMapEntity || !m_ESMMapConfig || !m_ESMRootWidget)
return false;
if (SCR_MapEntity.GetMapInstance() != m_ESMMapEntity || !m_ESMMapEntity.IsOpen())
return false;
// Vanilla reuses the same config object for equal map modes and changes
// RootWidgetRef, so pointer identity alone cannot establish ownership.
return m_ESMMapEntity.GetMapConfig() == m_ESMMapConfig && m_ESMMapConfig.RootWidgetRef == m_ESMRootWidget;
}
protected void ReleaseMapCapture()
{
bool ownsRenderer = OwnsMapCapture();
// Freeze our own target even on interruption or foreign replacement.
if (m_ESMRenderTarget)
m_ESMRenderTarget.SetEnabled(false);
if (m_ESMMapEntity && m_ESMMapEntity.IsOpen())
m_ESMMapEntity.CloseMap();
m_bESMOwnsMapRenderer = false;
RestoreCharacterCamera();
CompleteMapModeSwitch();
m_ESMMapConfig = null;
if (ownsRenderer)
m_ESMMapEntity.CloseMap(); // vanilla also restores its character camera
}
protected void CompleteMapModeSwitch()
@@ -163,21 +195,20 @@ class ERRM_SharedMapComponent : SCR_MapGadgetComponent
protected void StopMapCapture()
{
m_bESMInHand = false;
GetGame().GetCallqueue().Remove(TryCaptureMapSurface);
GetGame().GetCallqueue().Remove(CenterMapOnHolder);
GetGame().GetCallqueue().Remove(FinishMapCapture);
if (m_bESMOwnsMapRenderer && m_ESMMapEntity && m_ESMMapEntity.IsOpen())
m_ESMMapEntity.CloseMap();
m_bESMOwnsMapRenderer = false;
if (GetGame())
{
GetGame().GetCallqueue().Remove(TryCaptureMapSurface);
GetGame().GetCallqueue().Remove(CenterMapOnHolder);
GetGame().GetCallqueue().Remove(FinishMapCapture);
}
ReleaseMapCapture();
m_ESMCharacterOwner = null;
RestoreCharacterCamera();
m_ESMMapEntity = null;
}
protected void RestoreCharacterCamera()
{
if (!GetGame()) return;
if (!OwnsMapCapture()) return;
PlayerController playerController = GetGame().GetPlayerController();
if (playerController)
playerController.SetCharacterCameraRenderActive(true);