Icon culling hides car icons when zoomed out past a configurable threshold (default 40%), keeping only locomotive icons visible. Locos scale up automatically when culling is active (configurable boost). An option also hides MU trailing units. All managed by the new MapIconCuller class with smooth fade transitions. EOTD (End-of-Train Device): a blinking red dot at the rear of each consist. Shown by default when car icons are hidden. Dot size and visibility conditions are configurable. Implemented in EotdSystem as a programmatically generated circle texture to avoid asset dependencies. Added an Icons submenu to the gear menu containing all icon and EOTD settings. Controls grey out to reflect dependencies: culling sub-settings (MU hide, loco boost, EOTD) grey out when culling is off; EOTD dot size and hide-when-visible grey out when EOTD is off. Changes round-trip via UICmd events, persist to PopoutSettings, and call MapIconCuller.Refresh(). Native state is seeded from C# on window init via RRPOPOUT_SetIconCullingState. Settings completeness: added Right-click recenters toggle and Map BG opacity slider to the UMM settings panel (were only accessible from the gear menu). Replaced four FindObjectOfType<MapWindow> calls with PanelFinder.GetMapWindow(). Fixed AV false-positive on release zips: ImGui's built-in font blob contained the substring "UPX", matching the heuristic for UPX-packed binaries. Added IMGUI_DISABLE_DEFAULT_FONT to strip the blob; ProggyClean.ttf is now shipped as a separate file alongside the DLL and loaded at runtime instead.
85 lines
3.6 KiB
C#
85 lines
3.6 KiB
C#
using HarmonyLib;
|
|
using Helpers;
|
|
using UI.Common;
|
|
using UI.Map;
|
|
using UnityEngine;
|
|
|
|
namespace S3.Modules.Popout {
|
|
|
|
// Locates the map panel at runtime.
|
|
//
|
|
// MapWindow.instance is private in the current game build, so we use
|
|
// FindObjectOfType<MapWindow>() instead. All the useful fields (_renderTexture,
|
|
// _window, mapDrag) are also private — accessed via Harmony Traverse.
|
|
//
|
|
// MapBuilder.Shared and MapBuilder.mapCamera are public.
|
|
|
|
internal static class PanelFinder {
|
|
|
|
private static MapWindow? _cachedMapWindow;
|
|
|
|
// Returns the live MapWindow MonoBehaviour, or null if the map isn't loaded.
|
|
// Cached after first find; Unity's == null catches destroyed instances and
|
|
// triggers a fresh search on the next call.
|
|
public static MapWindow? GetMapWindow() {
|
|
if (_cachedMapWindow == null)
|
|
_cachedMapWindow = Object.FindObjectOfType<MapWindow>();
|
|
return _cachedMapWindow;
|
|
}
|
|
|
|
// Returns the RenderTexture the map camera renders to each frame.
|
|
public static RenderTexture? GetMapRenderTexture() {
|
|
var mw = GetMapWindow();
|
|
return mw == null ? null
|
|
: Traverse.Create(mw).Field<RenderTexture>("_renderTexture").Value;
|
|
}
|
|
|
|
// Returns the Window UI component (exposes public IsShown / ShowWindow).
|
|
public static Window? GetMapWindowUI() {
|
|
var mw = GetMapWindow();
|
|
return mw == null ? null
|
|
: Traverse.Create(mw).Field<Window>("_window").Value;
|
|
}
|
|
|
|
// Returns the MapDrag component (exposes public OnZoom / OnDragChange actions).
|
|
public static MapDrag? GetMapDrag() {
|
|
var mw = GetMapWindow();
|
|
return mw == null ? null
|
|
: Traverse.Create(mw).Field<MapDrag>("mapDrag").Value;
|
|
}
|
|
|
|
public static bool IsMapReady() {
|
|
var mw = GetMapWindow();
|
|
if (mw == null) return false;
|
|
return GetMapRenderTexture() != null && MapBuilder.Shared?.mapCamera != null;
|
|
}
|
|
|
|
// Recomputes map icon scale for the current orthographic size.
|
|
// MapBuilder.UpdateForZoom() is private in the current game build (it used to
|
|
// be public), so we invoke it via Traverse. Called after we set
|
|
// orthographicSize directly (zoom / RT setup) so icons rescale to match.
|
|
public static void UpdateMapForZoom() {
|
|
var mb = MapBuilder.Shared;
|
|
if (mb != null)
|
|
Traverse.Create(mb).Method("UpdateForZoom").GetValue();
|
|
}
|
|
|
|
// Builds the toolbar status string shared by the popout and the in-game overlay.
|
|
// ASCII separators only — ImGui's default font has no non-ASCII glyphs.
|
|
public static string BuildStatusText(Camera mapCamera) {
|
|
string follow = MapEnhancerBridge.IsInstalled
|
|
? (MapEnhancerBridge.FollowMode ? " | Following" : "")
|
|
: "";
|
|
string mapCoord = "", camCoord = "";
|
|
try {
|
|
var mapPt = WorldTransformer.WorldToGame(mapCamera.transform.position);
|
|
mapCoord = $" | Map ({(int)mapPt.x}, {(int)mapPt.z})";
|
|
if (Camera.main != null) {
|
|
var camPt = WorldTransformer.WorldToGame(Camera.main.transform.position);
|
|
camCoord = $" | Cam ({(int)camPt.x}, {(int)camPt.z})";
|
|
}
|
|
} catch { /* WorldTransformer not ready yet — omit coords */ }
|
|
return $"Zoom: {(int)mapCamera.orthographicSize}{follow}{mapCoord}{camCoord}";
|
|
}
|
|
}
|
|
}
|