Files
EscapistsReintroduced/addons/map/Scripts/Game/ERRMap/ERRM_SharedMapComponent.c
T

201 lines
5.7 KiB
C

[ComponentEditorProps(category: "GameScripted/Gadgets", description: "Vanilla map gadget with a world-visible rendered surface")]
class ERRM_SharedMapComponentClass : SCR_MapGadgetComponentClass
{
[Attribute("{255E1265F702B4AE}UI/layouts/ERRMap/SharedMapRenderTarget.layout", UIWidgets.ResourcePickerThumbnail, "Off-screen map render target", "layout")]
protected ResourceName m_sLayoutName;
[Attribute("0.12", UIWidgets.EditBox, "Initial map zoom in pixels per metre", "0.01 20", category: "Shared Map")]
protected float m_fInitialZoom;
ResourceName GetSharedMapLayout()
{
return m_sLayoutName;
}
float GetInitialZoom()
{
return m_fInitialZoom;
}
}
// This remains a real SCR_MapGadgetComponent, so the normal M-key map,
// animations, ruler and faction-specific protractor settings keep working.
// The extra off-screen widget supplies the texture used by the held model.
class ERRM_SharedMapComponent : SCR_MapGadgetComponent
{
protected const ResourceName MAP_CONFIG = "{A786DD4868598F15}Configs/Map/MapPlain.conf";
protected const int MAP_SETUP_DELAY_MS = 100;
protected const int MAP_CAPTURE_DELAY_MS = 500;
protected const int MAP_RETRY_DELAY_MS = 250;
protected Widget m_ESMRootWidget;
protected RTTextureWidget m_ESMRenderTarget;
protected SCR_MapEntity m_ESMMapEntity;
protected IEntity m_ESMCharacterOwner;
protected bool m_bESMInHand;
protected bool m_bESMOwnsMapRenderer;
protected override void EOnInit(IEntity owner)
{
super.EOnInit(owner);
ERRM_SharedMapComponentClass data = ERRM_SharedMapComponentClass.Cast(GetComponentData(owner));
WorkspaceWidget workspace = GetGame().GetWorkspace();
if (!data || !workspace || data.GetSharedMapLayout().IsEmpty())
return;
m_ESMRootWidget = workspace.CreateWidgets(data.GetSharedMapLayout());
if (!m_ESMRootWidget)
return;
m_ESMRenderTarget = RTTextureWidget.Cast(m_ESMRootWidget.FindAnyWidget("RTTexture0"));
if (!m_ESMRenderTarget)
return;
m_ESMRenderTarget.SetRenderTarget(owner);
m_ESMRenderTarget.SetEnabled(false);
}
protected override void ModeSwitch(EGadgetMode mode, IEntity charOwner)
{
if (mode != EGadgetMode.IN_HAND || !m_ESMRootWidget || !m_ESMRenderTarget)
{
super.ModeSwitch(mode, charOwner);
return;
}
m_bESMInHand = true;
m_ESMCharacterOwner = charOwner;
TryCaptureMapSurface();
}
protected override void ModeClear(EGadgetMode mode)
{
if (mode == EGadgetMode.IN_HAND)
StopMapCapture();
super.ModeClear(mode);
}
protected void TryCaptureMapSurface()
{
if (!m_bESMInHand)
return;
if (!m_ESMRootWidget || !m_ESMRenderTarget)
{
CompleteMapModeSwitch();
return;
}
m_ESMMapEntity = SCR_MapEntity.GetMapInstance();
if (!m_ESMMapEntity)
{
CompleteMapModeSwitch();
return;
}
// The owner's normal map has priority. Capture only after it closes;
// otherwise this auxiliary render would replace or close the M-key UI.
if (m_ESMMapEntity.IsOpen())
{
GetGame().GetCallqueue().CallLater(TryCaptureMapSurface, MAP_RETRY_DELAY_MS, false);
return;
}
m_ESMRenderTarget.SetEnabled(true);
MapConfiguration mapConfig = m_ESMMapEntity.SetupMapConfig(EMapEntityMode.PLAIN, MAP_CONFIG, m_ESMRootWidget);
if (!mapConfig)
{
CompleteMapModeSwitch();
return;
}
m_ESMMapEntity.OpenMap(mapConfig);
m_bESMOwnsMapRenderer = true;
RestoreCharacterCamera();
GetGame().GetCallqueue().CallLater(CenterMapOnHolder, MAP_SETUP_DELAY_MS, false);
GetGame().GetCallqueue().CallLater(FinishMapCapture, MAP_CAPTURE_DELAY_MS, false);
}
protected void CenterMapOnHolder()
{
if (!m_bESMOwnsMapRenderer || !m_ESMMapEntity || !m_ESMCharacterOwner)
return;
ERRM_SharedMapComponentClass data = ERRM_SharedMapComponentClass.Cast(GetComponentData(GetOwner()));
if (!data)
return;
vector holderPosition = m_ESMCharacterOwner.GetOrigin();
m_ESMMapEntity.ZoomPanSmooth(data.GetInitialZoom(), holderPosition[0], holderPosition[2], 0.1);
}
protected void FinishMapCapture()
{
if (!m_bESMOwnsMapRenderer)
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.
if (m_ESMRenderTarget)
m_ESMRenderTarget.SetEnabled(false);
if (m_ESMMapEntity && m_ESMMapEntity.IsOpen())
m_ESMMapEntity.CloseMap();
m_bESMOwnsMapRenderer = false;
RestoreCharacterCamera();
CompleteMapModeSwitch();
}
protected void CompleteMapModeSwitch()
{
if (!m_bESMInHand || !m_ESMCharacterOwner)
return;
// Start the stock map only after the world-visible surface owns a frame.
super.ModeSwitch(EGadgetMode.IN_HAND, m_ESMCharacterOwner);
}
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;
m_ESMCharacterOwner = null;
RestoreCharacterCamera();
}
protected void RestoreCharacterCamera()
{
if (!GetGame()) return;
PlayerController playerController = GetGame().GetPlayerController();
if (playerController)
playerController.SetCharacterCameraRenderActive(true);
}
protected override void OnDelete(IEntity owner)
{
StopMapCapture();
// The entity may already be destroyed when this callback runs during a
// world restart. Destroying the widget releases its render binding without
// passing the deleted entity back into the native renderer.
if (m_ESMRootWidget)
m_ESMRootWidget.RemoveFromHierarchy();
m_ESMRenderTarget = null;
m_ESMRootWidget = null;
super.OnDelete(owner);
}
}