Extends the existing MapEnhancer gear menu integration with a full settings panel covering the options added by the community fork: marker visibility toggles, scale sliders for flares, junctions, track lines, and crossings, and bulk switch reset buttons. Also adds pan-cancels-follow and right-click to recenter on player toggles, three independent opacity controls (Window, Map Elements, Map Background), a per-element hover minimum of 50% for the window chrome so controls stay reachable at low opacity, and fixes to make the compass and toolbar correctly respond to their respective sliders. Both surfaces (in-game overlay and OS popout) maintain parity on all new settings.
236 lines
13 KiB
C#
236 lines
13 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace S3.Modules.Popout {
|
|
|
|
// Must match InputEvent in native/include/shared_types.h exactly.
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
public struct InputEvent {
|
|
public int type; // InputEventType (0=Move,1=LDown,2=LUp,3=RDown,4=RUp,5=Wheel)
|
|
public float x; // normalized [0,1] left=0
|
|
public float y; // normalized [0,1] top=0
|
|
public float delta; // wheel delta; positive = scroll up
|
|
}
|
|
|
|
public enum InputEventType {
|
|
MouseMove = 0,
|
|
LButtonDown = 1,
|
|
LButtonUp = 2,
|
|
RButtonDown = 3,
|
|
RButtonUp = 4,
|
|
MouseWheel = 5,
|
|
UICommand = 6, // toolbar button; x = UICmd value cast to float
|
|
}
|
|
|
|
public enum UICmd {
|
|
Recenter = 1,
|
|
FollowMode = 2, // toggle MapEnhancer follow on/off
|
|
FollowPlayerCam = 3, // follow Camera.main continuously
|
|
FollowSelectedLoco = 4, // follow TrainController.Shared.SelectedCar
|
|
FollowLoco = 5, // follow specific loco; InputEvent.y = 0-based index
|
|
JumpToLocation = 6, // jump to named location; InputEvent.y = 0-based index
|
|
SetRotation = 7, // set map rotation; InputEvent.y = degrees [0,360)
|
|
RotateReset = 8, // reset map rotation to 0
|
|
RotateSyncPlayer = 9, // toggle sync-rotation-to-player-camera mode
|
|
ToggleFollowPlayer = 10, // toggle continuous follow of player world position
|
|
PopOut = 11, // (in-game only) close the overlay and open the OS popout
|
|
SetTheme = 12, // (in-game only) apply theme preset; InputEvent.y = preset index
|
|
SetAlpha = 13, // (in-game only) set chrome alpha; InputEvent.y = [0.1, 1.0]
|
|
Close = 14, // (in-game only) user clicked [X] — hide the overlay
|
|
SetMapAlpha = 15, // (in-game only) set map image alpha; InputEvent.y = [0.0, 1.0]
|
|
// MapEnhancer settings
|
|
SetMEBool = 16, // toggle ME bool setting; y = MEBoolBit index, delta = 0|1
|
|
SetMEFloat = 17, // set ME float setting; y = MEFloatIdx index, delta = value
|
|
MEResetSwitchesNormal = 18, // bulk reset all switches to Normal
|
|
MEResetSwitchesThrown = 19, // bulk reset all switches to Thrown
|
|
TogglePanDisablesFollow = 20, // toggle whether panning cancels follow mode
|
|
ToggleRightClickRecenter = 21, // toggle whether right-clicking recenters on player
|
|
SetMapBgAlpha = 22, // set map camera clear-colour opacity; y = [0.0, 1.0]
|
|
}
|
|
|
|
// Must match MapThemeData in native/include/shared_types.h exactly (36 floats = 144 bytes).
|
|
[Serializable]
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
public struct MapThemeData {
|
|
public float wBgR, wBgG, wBgB, wBgA; // window / toolbar background
|
|
public float accR, accG, accB, accA; // accent (TitleBgActive, buttons)
|
|
public float txtR, txtG, txtB, txtA; // status text
|
|
public float popR, popG, popB, popA; // settings popup background
|
|
public float mapR, mapG, mapB, mapA; // map image tint (1,1,1,1 = no tint)
|
|
public float cmpR, cmpG, cmpB, cmpA; // compass background disk
|
|
public float nNR, nNG, nNB, nNA; // compass needle N half
|
|
public float nSR, nSG, nSB, nSA; // compass needle S half
|
|
public float mapBgR, mapBgG, mapBgB, mapBgA; // map camera clear colour
|
|
}
|
|
|
|
internal static class Native {
|
|
// S3Native.dll lives in the mod folder (Mods/S3) and is loaded by full path
|
|
// via NativeLoader before any of these are called; once loaded, [DllImport]
|
|
// binds to it by name. (Pure-UMM install — no game-root copy, no winhttp proxy.)
|
|
// Named S3Native (not RRPopout) so it can never collide with a leftover copy
|
|
// of the old standalone PopOut's RRPopout.dll still injected in someone's game.
|
|
private const string Dll = "S3Native";
|
|
|
|
// Create a floating window. Returns a handle (> 0) or 0 on failure.
|
|
// Native loads saved position/size from its state file; width/height are the first-run defaults.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
|
public static extern int RRPOPOUT_CreateWindow(string title, int width, int height);
|
|
|
|
// Set the source texture and the UV sub-rect to blit next frame.
|
|
// Call this on the main thread immediately before IssuePluginEvent.
|
|
// u0,v0 = top-left UV in D3D convention (V=0 at top); u1,v1 = bottom-right.
|
|
// Pass (0, 0, 1, 1) for full texture.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetFrameTexture(
|
|
int windowHandle, IntPtr texturePtr,
|
|
float u0, float v0, float u1, float v1);
|
|
|
|
// Returns the UnityRenderingEvent callback pointer for GL.IssuePluginEvent.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern IntPtr RRPOPOUT_GetRenderEventFunc();
|
|
|
|
// Fills outWidth / outHeight with the current client area size.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_GetWindowSize(int windowHandle, out int outWidth, out int outHeight);
|
|
|
|
// Drains queued input events from the OS window into outEvents.
|
|
// Returns the number of events written (≤ maxEvents).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int RRPOPOUT_PollInputEvents(
|
|
int windowHandle,
|
|
[Out] InputEvent[] outEvents,
|
|
int maxEvents);
|
|
|
|
// Close and free the window.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_DestroyWindow(int windowHandle);
|
|
|
|
// Update the status bar text shown at the bottom of the popout.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
|
public static extern void RRPOPOUT_SetStatusText(int windowHandle, string text);
|
|
|
|
// Set the locomotive list shown in the Follow submenu.
|
|
// names: loco display names joined by '\n'.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
|
public static extern void RRPOPOUT_SetLocoList(int windowHandle, string names);
|
|
|
|
// Set the location list shown in the Jump to location submenu.
|
|
// names: location names joined by '\n'.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
|
|
public static extern void RRPOPOUT_SetLocationList(int windowHandle, string names);
|
|
|
|
// Tell the native UI whether MapEnhancer is installed (controls menu layout).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetMapEnhancerInstalled(int windowHandle, bool installed);
|
|
|
|
// Update the compass display to reflect the current map rotation (degrees).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetMapRotation(int windowHandle, float degrees);
|
|
|
|
// Highlight (or un-highlight) the sync button in the toolbar.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetMapSyncPlayer(int windowHandle, bool active);
|
|
|
|
// Highlight (or un-highlight) the follow-player toolbar button.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetFollowPlayer(int windowHandle, bool active);
|
|
|
|
// Push current map zoom so native can persist it on window close.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetMapZoom(int windowHandle, float zoom);
|
|
|
|
// Read back the C#-side state that native loaded from its save file.
|
|
// followPlayer / syncRotation return 1 (true) or 0 (false).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_GetPersistedState(int windowHandle,
|
|
out int followPlayer, out int syncRotation,
|
|
out float mapRotation, out float mapZoom);
|
|
|
|
// -------------------------------------------------------------------
|
|
// In-game overlay. Shares the native engine's shared ImGui context
|
|
// and D3D11 device; renders into Unity's bound backbuffer after frame.
|
|
// -------------------------------------------------------------------
|
|
|
|
// Event id to pass to GL.IssuePluginEvent to drive the overlay render.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int RRPOPOUT_GetOverlayEventId();
|
|
|
|
// One-time: hand native a texture so it can acquire Unity's D3D device.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayDeviceTexture(IntPtr texturePtr);
|
|
|
|
// Per-frame input snapshot (top-left origin, pixels; wheel in WHEEL_DELTA units).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayInput(
|
|
float displayW, float displayH,
|
|
float mouseX, float mouseY,
|
|
int lButton, int rButton, int wheel);
|
|
|
|
// Show or hide the overlay.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayVisible(int visible);
|
|
|
|
// Map render texture to display inside the in-game overlay window, plus the
|
|
// UV sub-rect (V flipped for a Unity RT: v0=1, v1=0). IntPtr.Zero clears it.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayMapTexture(
|
|
IntPtr texturePtr, float u0, float v0, float u1, float v1);
|
|
|
|
// 1 when ImGui wants the mouse this frame (hovering a widget).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int RRPOPOUT_OverlayWantsMouse();
|
|
|
|
// Drains queued in-game map input (drag/zoom over the map image). Events are
|
|
// in normalized [0,1] image space (top-left origin); forward to the map camera.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int RRPOPOUT_PollOverlayInput(
|
|
[Out] InputEvent[] outEvents, int maxEvents);
|
|
|
|
// Reads the map image region size (px) so C# can set camera.aspect to match,
|
|
// filling the window with no letterbox bars.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_GetOverlayMapView(out float outW, out float outH);
|
|
|
|
// Handle of the in-game overlay's shared UI-state holder. Push state to it
|
|
// (status/loco/location/rotation/follow) and poll it for toolbar commands
|
|
// with the same handle-based functions the popout uses.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern int RRPOPOUT_GetOverlayWindowHandle();
|
|
|
|
// Apply a theme to the shared ImGui context. Affects both the in-game overlay
|
|
// and the popout (they share one context). presetIndex is stored for the gear
|
|
// menu checkmarks. Thread-safe: stored on main thread, applied on render thread.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetTheme(ref MapThemeData data, int presetIndex);
|
|
|
|
// Set the in-game overlay's chrome alpha [0.1, 1.0]. Thread-safe via atomic.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayAlpha(float alpha);
|
|
|
|
// Set the map image alpha [0.0, 1.0]. Independent of chrome alpha.
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayMapAlpha(float alpha);
|
|
|
|
// Tell native whether panning should cancel follow mode (for the gear menu checkmark).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetPanDisablesFollow(int windowHandle, bool active);
|
|
|
|
// Tell native whether right-clicking the map recenters on the player (gear menu checkmark).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetRightClickRecenter(int windowHandle, bool active);
|
|
|
|
// Seed the map camera clear-colour opacity slider (shared global, overlay + popout).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetOverlayMapBgAlpha(float alpha);
|
|
|
|
// Push MapEnhancer settings state to a window's render-thread atomics.
|
|
// flags: bit-packed booleans (see MEBoolBit in shared_types.h).
|
|
// Scale values seed slider positions; sliders update them live during drag
|
|
// and push UICmd::SetMEFloat only on release (IsItemDeactivatedAfterEdit).
|
|
[DllImport(Dll, CallingConvention = CallingConvention.Cdecl)]
|
|
public static extern void RRPOPOUT_SetMEState(
|
|
int windowHandle, uint flags,
|
|
float flareScale, float junctionScale,
|
|
float trackThickness, float crossingScale);
|
|
}
|
|
}
|