mirror of
https://github.com/soarqin/DSP_Mods.git
synced 2025-12-09 14:13:31 +08:00
WIP
This commit is contained in:
@@ -3,55 +3,78 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace UXAssist.Common;
|
namespace UXAssist.Common;
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum WindowStyles: int
|
|
||||||
{
|
|
||||||
WS_BORDER = 0x00800000,
|
|
||||||
WS_CAPTION = 0x00C00000,
|
|
||||||
WS_CHILD = 0x40000000,
|
|
||||||
WS_CHILDWINDOW = 0x40000000,
|
|
||||||
WS_CLIPCHILDREN = 0x02000000,
|
|
||||||
WS_CLIPSIBLINGS = 0x04000000,
|
|
||||||
WS_DISABLED = 0x08000000,
|
|
||||||
WS_DLGFRAME = 0x00400000,
|
|
||||||
WS_GROUP = 0x00020000,
|
|
||||||
WS_HSCROLL = 0x00100000,
|
|
||||||
WS_ICONIC = 0x20000000,
|
|
||||||
WS_MAXIMIZE = 0x01000000,
|
|
||||||
WS_MAXIMIZEBOX = 0x00010000,
|
|
||||||
WS_MINIMIZE = 0x20000000,
|
|
||||||
WS_MINIMIZEBOX = 0x00020000,
|
|
||||||
WS_OVERLAPPED = 0x00000000,
|
|
||||||
WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
|
|
||||||
WS_POPUP = unchecked((int)0x80000000),
|
|
||||||
WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU,
|
|
||||||
WS_SIZEBOX = 0x00040000,
|
|
||||||
WS_SYSMENU = 0x00080000,
|
|
||||||
WS_TABSTOP = 0x00010000,
|
|
||||||
WS_THICKFRAME = 0x00040000,
|
|
||||||
WS_TILED = 0x00000000,
|
|
||||||
WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX,
|
|
||||||
WS_VISIBLE = 0x10000000,
|
|
||||||
WS_VSCROLL = 0x00200000
|
|
||||||
}
|
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum WindowLongFlags: int
|
|
||||||
{
|
|
||||||
GWL_EXSTYLE = -20,
|
|
||||||
GWLP_HINSTANCE = -6,
|
|
||||||
GWLP_HWNDPARENT = -8,
|
|
||||||
GWLP_ID = -12,
|
|
||||||
GWL_STYLE = -16,
|
|
||||||
GWLP_USERDATA = -21,
|
|
||||||
GWLP_WNDPROC = -4,
|
|
||||||
DWLP_DLGPROC = 0x4,
|
|
||||||
DWLP_MSGRESULT = 0,
|
|
||||||
DWLP_USER = 0x8
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class WinApi
|
public static class WinApi
|
||||||
{
|
{
|
||||||
|
#region Styles
|
||||||
|
|
||||||
|
public const int WS_BORDER = 0x00800000;
|
||||||
|
public const int WS_CAPTION = 0x00C00000;
|
||||||
|
public const int WS_CHILD = 0x40000000;
|
||||||
|
public const int WS_CHILDWINDOW = 0x40000000;
|
||||||
|
public const int WS_CLIPCHILDREN = 0x02000000;
|
||||||
|
public const int WS_CLIPSIBLINGS = 0x04000000;
|
||||||
|
public const int WS_DISABLED = 0x08000000;
|
||||||
|
public const int WS_DLGFRAME = 0x00400000;
|
||||||
|
public const int WS_GROUP = 0x00020000;
|
||||||
|
public const int WS_HSCROLL = 0x00100000;
|
||||||
|
public const int WS_ICONIC = 0x20000000;
|
||||||
|
public const int WS_MAXIMIZE = 0x01000000;
|
||||||
|
public const int WS_MAXIMIZEBOX = 0x00010000;
|
||||||
|
public const int WS_MINIMIZE = 0x20000000;
|
||||||
|
public const int WS_MINIMIZEBOX = 0x00020000;
|
||||||
|
public const int WS_OVERLAPPED = 0x00000000;
|
||||||
|
public const int WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
|
||||||
|
public const int WS_POPUP = unchecked((int)0x80000000);
|
||||||
|
public const int WS_POPUPWINDOW = WS_POPUP | WS_BORDER | WS_SYSMENU;
|
||||||
|
public const int WS_SIZEBOX = 0x00040000;
|
||||||
|
public const int WS_SYSMENU = 0x00080000;
|
||||||
|
public const int WS_TABSTOP = 0x00010000;
|
||||||
|
public const int WS_THICKFRAME = 0x00040000;
|
||||||
|
public const int WS_TILED = 0x00000000;
|
||||||
|
public const int WS_TILEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
|
||||||
|
public const int WS_VISIBLE = 0x10000000;
|
||||||
|
public const int WS_VSCROLL = 0x00200000;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetWindowLong and SetWindowLong Flags
|
||||||
|
|
||||||
|
public const int GWL_EXSTYLE = -20;
|
||||||
|
public const int GWLP_HINSTANCE = -6;
|
||||||
|
public const int GWLP_HWNDPARENT = -8;
|
||||||
|
public const int GWLP_ID = -12;
|
||||||
|
public const int GWL_STYLE = -16;
|
||||||
|
public const int GWLP_USERDATA = -21;
|
||||||
|
public const int GWLP_WNDPROC = -4;
|
||||||
|
public const int DWLP_DLGPROC = 0x4;
|
||||||
|
public const int DWLP_MSGRESULT = 0;
|
||||||
|
public const int DWLP_USER = 0x8;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Messages
|
||||||
|
|
||||||
|
public const int WM_CREATE = 0x0001;
|
||||||
|
public const int WM_DESTROY = 0x0002;
|
||||||
|
public const int WM_MOVE = 0x0003;
|
||||||
|
public const int WM_SIZE = 0x0005;
|
||||||
|
public const int WM_ACTIVATE = 0x0006;
|
||||||
|
public const int WM_SETFOCUS = 0x0007;
|
||||||
|
public const int WM_KILLFOCUS = 0x0008;
|
||||||
|
public const int WM_ENABLE = 0x000A;
|
||||||
|
public const int WM_CLOSE = 0x0010;
|
||||||
|
public const int WM_QUIT = 0x0012;
|
||||||
|
public const int WM_SIZING = 0x0214;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Errors
|
||||||
|
|
||||||
|
private const int ERROR_INSUFFICIENT_BUFFER = 122;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Structs
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct Rect
|
public struct Rect
|
||||||
@@ -59,6 +82,10 @@ public static class WinApi
|
|||||||
public int Left, Top, Right, Bottom;
|
public int Left, Top, Right, Bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public delegate IntPtr WndProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
[DllImport("user32", CharSet = CharSet.Unicode)]
|
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||||
public static extern int GetWindowLong(IntPtr hwnd, int nIndex);
|
public static extern int GetWindowLong(IntPtr hwnd, int nIndex);
|
||||||
|
|
||||||
@@ -79,4 +106,162 @@ public static class WinApi
|
|||||||
|
|
||||||
[DllImport("user32", ExactSpelling = true)]
|
[DllImport("user32", ExactSpelling = true)]
|
||||||
public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint);
|
public static extern bool MoveWindow(IntPtr hWnd, int x, int y, int nWidth, int nHeight, bool bRepaint);
|
||||||
|
|
||||||
|
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern bool GetProcessAffinityMask(IntPtr hProcess, out IntPtr lpProcessAffinityMask, out IntPtr lpSystemAffinityMask);
|
||||||
|
|
||||||
|
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern IntPtr GetCurrentProcess();
|
||||||
|
|
||||||
|
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern bool SetProcessAffinityMask(IntPtr hProcess, IntPtr dwProcessAffinityMask);
|
||||||
|
|
||||||
|
// GetPriorityClass and SetPriorityClass
|
||||||
|
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern int GetPriorityClass(IntPtr hProcess);
|
||||||
|
|
||||||
|
[DllImport("kernel32", ExactSpelling = true, SetLastError = true)]
|
||||||
|
public static extern bool SetPriorityClass(IntPtr hProcess, int dwPriorityClass);
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||||
|
public static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
|
||||||
|
|
||||||
|
[DllImport("user32", CharSet = CharSet.Unicode)]
|
||||||
|
public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
#region GetLogicalProcessorInformation
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum LOGICAL_PROCESSOR_RELATIONSHIP
|
||||||
|
{
|
||||||
|
RelationProcessorCore,
|
||||||
|
RelationNumaNode,
|
||||||
|
RelationCache,
|
||||||
|
RelationProcessorPackage,
|
||||||
|
RelationGroup,
|
||||||
|
RelationAll = 0xffff
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct PROCESSORCORE
|
||||||
|
{
|
||||||
|
public byte Flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct NUMANODE
|
||||||
|
{
|
||||||
|
public uint NodeNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PROCESSOR_CACHE_TYPE
|
||||||
|
{
|
||||||
|
CacheUnified,
|
||||||
|
CacheInstruction,
|
||||||
|
CacheData,
|
||||||
|
CacheTrace
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
public struct CACHE_DESCRIPTOR
|
||||||
|
{
|
||||||
|
public byte Level;
|
||||||
|
public byte Associativity;
|
||||||
|
public ushort LineSize;
|
||||||
|
public uint Size;
|
||||||
|
public PROCESSOR_CACHE_TYPE Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
|
public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION
|
||||||
|
{
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public PROCESSORCORE ProcessorCore;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public NUMANODE NumaNode;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
public CACHE_DESCRIPTOR Cache;
|
||||||
|
[FieldOffset(0)]
|
||||||
|
private UInt64 Reserved1;
|
||||||
|
[FieldOffset(8)]
|
||||||
|
private UInt64 Reserved2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
|
||||||
|
{
|
||||||
|
public UIntPtr ProcessorMask;
|
||||||
|
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
|
||||||
|
public SYSTEM_LOGICAL_PROCESSOR_INFORMATION_UNION ProcessorInformation;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport(@"kernel32", SetLastError=true)]
|
||||||
|
private static extern bool GetLogicalProcessorInformation(
|
||||||
|
IntPtr buffer,
|
||||||
|
ref uint returnLength
|
||||||
|
);
|
||||||
|
|
||||||
|
public struct LogicalProcessorDetails
|
||||||
|
{
|
||||||
|
public int CoreCount;
|
||||||
|
public int ThreadCount;
|
||||||
|
public int PerformanceCoreCount;
|
||||||
|
public int EfficiencyCoreCount;
|
||||||
|
public ulong PerformanceCoreMask;
|
||||||
|
public ulong EfficiencyCoreMask;
|
||||||
|
public bool HybridArchitecture => PerformanceCoreCount > 0 && EfficiencyCoreCount > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LogicalProcessorDetails GetLogicalProcessorDetails()
|
||||||
|
{
|
||||||
|
uint returnLength = 0;
|
||||||
|
GetLogicalProcessorInformation(IntPtr.Zero, ref returnLength);
|
||||||
|
var result = new LogicalProcessorDetails();
|
||||||
|
if (Marshal.GetLastWin32Error() != ERROR_INSUFFICIENT_BUFFER) return result;
|
||||||
|
var ptr = Marshal.AllocHGlobal((int)returnLength);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!GetLogicalProcessorInformation(ptr, ref returnLength))
|
||||||
|
return result;
|
||||||
|
var size = Marshal.SizeOf(typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
|
||||||
|
var len = (int)returnLength / size;
|
||||||
|
var item = ptr;
|
||||||
|
for (var i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
var buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION)Marshal.PtrToStructure(item, typeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
|
||||||
|
item += size;
|
||||||
|
if (buffer.Relationship != LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore) continue;
|
||||||
|
result.CoreCount++;
|
||||||
|
var tcount = CountBitsSet((ulong)buffer.ProcessorMask);
|
||||||
|
result.ThreadCount += tcount;
|
||||||
|
if (tcount > 1)
|
||||||
|
{
|
||||||
|
result.PerformanceCoreCount ++;
|
||||||
|
result.PerformanceCoreMask |= (ulong)buffer.ProcessorMask;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result.EfficiencyCoreCount ++;
|
||||||
|
result.EfficiencyCoreMask |= (ulong)buffer.ProcessorMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
int CountBitsSet(ulong mask)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
while (mask != 0)
|
||||||
|
{
|
||||||
|
mask &= mask - 1;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
149
UXAssist/Functions/WindowFunctions.cs
Normal file
149
UXAssist/Functions/WindowFunctions.cs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using UXAssist.Common;
|
||||||
|
|
||||||
|
namespace UXAssist.Functions;
|
||||||
|
|
||||||
|
public static class WindowFunctions
|
||||||
|
{
|
||||||
|
public static string ProfileName { get; private set; }
|
||||||
|
|
||||||
|
private const string GameWindowClass = "UnityWndClass";
|
||||||
|
private static string _gameWindowTitle = "Dyson Sphere Program";
|
||||||
|
|
||||||
|
private static IntPtr _oldWndProc = IntPtr.Zero;
|
||||||
|
private static IntPtr _gameWindowHandle = IntPtr.Zero;
|
||||||
|
|
||||||
|
public static void Start()
|
||||||
|
{
|
||||||
|
var wndProc = new WinApi.WndProc(GameWndProc);
|
||||||
|
var gameWnd = FindGameWindow();
|
||||||
|
if (gameWnd != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
_oldWndProc = WinApi.SetWindowLongPtr(gameWnd, WinApi.GWLP_WNDPROC, Marshal.GetFunctionPointerForDelegate(wndProc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr GameWndProc(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WinApi.WM_ACTIVATE:
|
||||||
|
UXAssist.Logger.LogDebug($"Activate: {wParam.ToInt32()}, {lParam.ToInt32()}");
|
||||||
|
// TODO: Set Priority like: WinApi.SetPriorityClass(WinApi.GetCurrentProcess(), 0x00000080);
|
||||||
|
break;
|
||||||
|
case WinApi.WM_DESTROY:
|
||||||
|
if (_oldWndProc != IntPtr.Zero && _gameWindowHandle != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
WinApi.SetWindowLongPtr(_gameWindowHandle, WinApi.GWLP_WNDPROC, _oldWndProc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return WinApi.CallWindowProc(_oldWndProc, hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
public static void ShowCPUInfo()
|
||||||
|
{
|
||||||
|
var details = WinApi.GetLogicalProcessorDetails();
|
||||||
|
var msg = $"Cores: {details.CoreCount}\nThreads: {details.ThreadCount}";
|
||||||
|
var hybrid = details.HybridArchitecture;
|
||||||
|
if (hybrid)
|
||||||
|
{
|
||||||
|
msg += "\nP-Cores: {details.PerformanceCoreCount}\nE-Cores: {details.EfficiencyCoreCount}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var handle = WinApi.GetCurrentProcess();
|
||||||
|
var prio = (ProcessPriorityClass)WinApi.GetPriorityClass(handle);
|
||||||
|
msg += $"\nPriority: {prio}";
|
||||||
|
|
||||||
|
var aff = 0UL;
|
||||||
|
if (WinApi.GetProcessAffinityMask(handle, out var processMask, out var systemMask))
|
||||||
|
aff = (ulong)processMask & (ulong)systemMask;
|
||||||
|
|
||||||
|
msg += $"\nEnabled CPUs: ";
|
||||||
|
var first = true;
|
||||||
|
for (var i = 0; aff != 0UL; i++)
|
||||||
|
{
|
||||||
|
if ((aff & 1UL) != 0)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
first = false;
|
||||||
|
else
|
||||||
|
msg += ",";
|
||||||
|
msg += i;
|
||||||
|
if (hybrid)
|
||||||
|
{
|
||||||
|
if ((details.PerformanceCoreMask & (1UL << i)) != 0)
|
||||||
|
msg += "(P)";
|
||||||
|
else if ((details.EfficiencyCoreMask & (1UL << i)) != 0)
|
||||||
|
msg += "(E)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
aff >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIMessageBox.Show("CPU Info".Translate(), msg, "OK".Translate(), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetWindowTitle()
|
||||||
|
{
|
||||||
|
// Get profile name from command line arguments, and set window title accordingly
|
||||||
|
var args = Environment.GetCommandLineArgs();
|
||||||
|
for (var i = 0; i < args.Length - 1; i++)
|
||||||
|
{
|
||||||
|
if (args[i] != "--doorstop-target") continue;
|
||||||
|
var arg = args[i + 1];
|
||||||
|
const string doorstopPathSuffix = @"\BepInEx\core\BepInEx.Preloader.dll";
|
||||||
|
if (!arg.EndsWith(doorstopPathSuffix, StringComparison.OrdinalIgnoreCase))
|
||||||
|
break;
|
||||||
|
arg = arg.Substring(0, arg.Length - doorstopPathSuffix.Length);
|
||||||
|
const string profileSuffix = @"\profiles\";
|
||||||
|
var index = arg.LastIndexOf(profileSuffix, StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (index < 0)
|
||||||
|
break;
|
||||||
|
arg = arg.Substring(index + profileSuffix.Length);
|
||||||
|
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
||||||
|
if (wnd == IntPtr.Zero) return;
|
||||||
|
ProfileName = arg;
|
||||||
|
_gameWindowTitle = $"Dyson Sphere Program - {arg}";
|
||||||
|
WinApi.SetWindowText(wnd, _gameWindowTitle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RefreshSavePath()
|
||||||
|
{
|
||||||
|
if (ProfileName == null) return;
|
||||||
|
|
||||||
|
if (UIRoot.instance.loadGameWindow.gameObject.activeSelf)
|
||||||
|
{
|
||||||
|
UIRoot.instance.loadGameWindow._Close();
|
||||||
|
}
|
||||||
|
if (UIRoot.instance.saveGameWindow.gameObject.activeSelf)
|
||||||
|
{
|
||||||
|
UIRoot.instance.saveGameWindow._Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
string gameSavePath;
|
||||||
|
if (Patches.GamePatch.ProfileBasedSaveFolderEnabled.Value && string.Compare(Patches.GamePatch.DefaultProfileName.Value, ProfileName, StringComparison.OrdinalIgnoreCase) != 0)
|
||||||
|
gameSavePath = $"{GameConfig.overrideDocumentFolder}{GameConfig.gameName}/Save/{ProfileName}/";
|
||||||
|
else
|
||||||
|
gameSavePath = $"{GameConfig.overrideDocumentFolder}{GameConfig.gameName}/Save/";
|
||||||
|
if (string.Compare(GameConfig.gameSavePath, gameSavePath, StringComparison.OrdinalIgnoreCase) == 0) return;
|
||||||
|
GameConfig.gameSavePath = gameSavePath;
|
||||||
|
if (!Directory.Exists(GameConfig.gameSavePath))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(GameConfig.gameSavePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IntPtr FindGameWindow()
|
||||||
|
{
|
||||||
|
if (_gameWindowHandle == IntPtr.Zero)
|
||||||
|
_gameWindowHandle = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
||||||
|
return _gameWindowHandle;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,11 +12,6 @@ namespace UXAssist.Patches;
|
|||||||
|
|
||||||
public class GamePatch: PatchImpl<GamePatch>
|
public class GamePatch: PatchImpl<GamePatch>
|
||||||
{
|
{
|
||||||
private const string GameWindowClass = "UnityWndClass";
|
|
||||||
private static string _gameWindowTitle = "Dyson Sphere Program";
|
|
||||||
|
|
||||||
public static string ProfileName { get; private set; }
|
|
||||||
|
|
||||||
public static ConfigEntry<bool> EnableWindowResizeEnabled;
|
public static ConfigEntry<bool> EnableWindowResizeEnabled;
|
||||||
public static ConfigEntry<bool> LoadLastWindowRectEnabled;
|
public static ConfigEntry<bool> LoadLastWindowRectEnabled;
|
||||||
public static ConfigEntry<int> MouseCursorScaleUpMultiplier;
|
public static ConfigEntry<int> MouseCursorScaleUpMultiplier;
|
||||||
@@ -75,28 +70,7 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
I18N.Add("KEYUPSSpeedUp", "Increase logical frame rate", "提升逻辑帧率");
|
I18N.Add("KEYUPSSpeedUp", "Increase logical frame rate", "提升逻辑帧率");
|
||||||
I18N.Add("Logical frame rate: {0}x", "Logical frame rate: {0}x", "逻辑帧速率: {0}x");
|
I18N.Add("Logical frame rate: {0}x", "Logical frame rate: {0}x", "逻辑帧速率: {0}x");
|
||||||
|
|
||||||
// Get profile name from command line arguments, and set window title accordingly
|
Functions.WindowFunctions.SetWindowTitle();
|
||||||
var args = Environment.GetCommandLineArgs();
|
|
||||||
for (var i = 0; i < args.Length - 1; i++)
|
|
||||||
{
|
|
||||||
if (args[i] != "--doorstop-target") continue;
|
|
||||||
var arg = args[i + 1];
|
|
||||||
const string doorstopPathSuffix = @"\BepInEx\core\BepInEx.Preloader.dll";
|
|
||||||
if (!arg.EndsWith(doorstopPathSuffix, StringComparison.OrdinalIgnoreCase))
|
|
||||||
break;
|
|
||||||
arg = arg.Substring(0, arg.Length - doorstopPathSuffix.Length);
|
|
||||||
const string profileSuffix = @"\profiles\";
|
|
||||||
var index = arg.LastIndexOf(profileSuffix, StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (index < 0)
|
|
||||||
break;
|
|
||||||
arg = arg.Substring(index + profileSuffix.Length);
|
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
|
||||||
if (wnd == IntPtr.Zero) return;
|
|
||||||
ProfileName = arg;
|
|
||||||
_gameWindowTitle = $"Dyson Sphere Program - {arg}";
|
|
||||||
WinApi.SetWindowText(wnd, _gameWindowTitle);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnableWindowResizeEnabled.SettingChanged += (_, _) => EnableWindowResize.Enable(EnableWindowResizeEnabled.Value);
|
EnableWindowResizeEnabled.SettingChanged += (_, _) => EnableWindowResize.Enable(EnableWindowResizeEnabled.Value);
|
||||||
LoadLastWindowRectEnabled.SettingChanged += (_, _) => LoadLastWindowRect.Enable(LoadLastWindowRectEnabled.Value);
|
LoadLastWindowRectEnabled.SettingChanged += (_, _) => LoadLastWindowRect.Enable(LoadLastWindowRectEnabled.Value);
|
||||||
@@ -107,8 +81,8 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
};
|
};
|
||||||
// AutoSaveOptEnabled.SettingChanged += (_, _) => AutoSaveOpt.Enable(AutoSaveOptEnabled.Value);
|
// AutoSaveOptEnabled.SettingChanged += (_, _) => AutoSaveOpt.Enable(AutoSaveOptEnabled.Value);
|
||||||
ConvertSavesFromPeaceEnabled.SettingChanged += (_, _) => ConvertSavesFromPeace.Enable(ConvertSavesFromPeaceEnabled.Value);
|
ConvertSavesFromPeaceEnabled.SettingChanged += (_, _) => ConvertSavesFromPeace.Enable(ConvertSavesFromPeaceEnabled.Value);
|
||||||
ProfileBasedSaveFolderEnabled.SettingChanged += (_, _) => RefreshSavePath();
|
ProfileBasedSaveFolderEnabled.SettingChanged += (_, _) => Functions.WindowFunctions.RefreshSavePath();
|
||||||
DefaultProfileName.SettingChanged += (_, _) => RefreshSavePath();
|
DefaultProfileName.SettingChanged += (_, _) => Functions.WindowFunctions.RefreshSavePath();
|
||||||
GameUpsFactor.SettingChanged += (_, _) =>
|
GameUpsFactor.SettingChanged += (_, _) =>
|
||||||
{
|
{
|
||||||
if (!EnableGameUpsFactor || GameUpsFactor.Value == 0.0) return;
|
if (!EnableGameUpsFactor || GameUpsFactor.Value == 0.0) return;
|
||||||
@@ -158,36 +132,10 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RefreshSavePath()
|
|
||||||
{
|
|
||||||
if (ProfileName == null) return;
|
|
||||||
|
|
||||||
if (UIRoot.instance.loadGameWindow.gameObject.activeSelf)
|
|
||||||
{
|
|
||||||
UIRoot.instance.loadGameWindow._Close();
|
|
||||||
}
|
|
||||||
if (UIRoot.instance.saveGameWindow.gameObject.activeSelf)
|
|
||||||
{
|
|
||||||
UIRoot.instance.saveGameWindow._Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
string gameSavePath;
|
|
||||||
if (ProfileBasedSaveFolderEnabled.Value && string.Compare(DefaultProfileName.Value, ProfileName, StringComparison.OrdinalIgnoreCase) != 0)
|
|
||||||
gameSavePath = $"{GameConfig.overrideDocumentFolder}{GameConfig.gameName}/Save/{ProfileName}/";
|
|
||||||
else
|
|
||||||
gameSavePath = $"{GameConfig.overrideDocumentFolder}{GameConfig.gameName}/Save/";
|
|
||||||
if (string.Compare(GameConfig.gameSavePath, gameSavePath, StringComparison.OrdinalIgnoreCase) == 0) return;
|
|
||||||
GameConfig.gameSavePath = gameSavePath;
|
|
||||||
if (!Directory.Exists(GameConfig.gameSavePath))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(GameConfig.gameSavePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix, HarmonyPatch(typeof(GameMain), nameof(GameMain.HandleApplicationQuit))]
|
[HarmonyPrefix, HarmonyPatch(typeof(GameMain), nameof(GameMain.HandleApplicationQuit))]
|
||||||
private static void GameMain_HandleApplicationQuit_Prefix()
|
private static void GameMain_HandleApplicationQuit_Prefix()
|
||||||
{
|
{
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
var wnd = Functions.WindowFunctions.FindGameWindow();
|
||||||
if (wnd == IntPtr.Zero) return;
|
if (wnd == IntPtr.Zero) return;
|
||||||
WinApi.GetWindowRect(wnd, out var rect);
|
WinApi.GetWindowRect(wnd, out var rect);
|
||||||
LastWindowRect.Value = new Vector4(rect.Left, rect.Top, Screen.width, Screen.height);
|
LastWindowRect.Value = new Vector4(rect.Left, rect.Top, Screen.width, Screen.height);
|
||||||
@@ -200,7 +148,7 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
|
|
||||||
protected override void OnEnable()
|
protected override void OnEnable()
|
||||||
{
|
{
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
var wnd = Functions.WindowFunctions.FindGameWindow();
|
||||||
if (wnd == IntPtr.Zero)
|
if (wnd == IntPtr.Zero)
|
||||||
{
|
{
|
||||||
Enable(false);
|
Enable(false);
|
||||||
@@ -208,33 +156,33 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
}
|
}
|
||||||
|
|
||||||
_enabled = true;
|
_enabled = true;
|
||||||
WinApi.SetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE,
|
WinApi.SetWindowLong(wnd, WinApi.GWL_STYLE,
|
||||||
WinApi.GetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE) | (int)WindowStyles.WS_THICKFRAME | (int)WindowStyles.WS_MAXIMIZEBOX);
|
WinApi.GetWindowLong(wnd, WinApi.GWL_STYLE) | WinApi.WS_THICKFRAME | WinApi.WS_MAXIMIZEBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnDisable()
|
protected override void OnDisable()
|
||||||
{
|
{
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
var wnd = Functions.WindowFunctions.FindGameWindow();
|
||||||
if (wnd == IntPtr.Zero)
|
if (wnd == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
WinApi.SetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE,
|
WinApi.SetWindowLong(wnd, WinApi.GWL_STYLE,
|
||||||
WinApi.GetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE) & ~((int)WindowStyles.WS_THICKFRAME | (int)WindowStyles.WS_MAXIMIZEBOX));
|
WinApi.GetWindowLong(wnd, WinApi.GWL_STYLE) & ~(WinApi.WS_THICKFRAME | WinApi.WS_MAXIMIZEBOX));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HarmonyPostfix]
|
[HarmonyPostfix]
|
||||||
[HarmonyPatch(typeof(UIOptionWindow), nameof(UIOptionWindow.ApplyOptions))]
|
[HarmonyPatch(typeof(UIOptionWindow), nameof(UIOptionWindow.ApplyOptions))]
|
||||||
private static void UIOptionWindow_ApplyOptions_Postfix()
|
private static void UIOptionWindow_ApplyOptions_Postfix()
|
||||||
{
|
{
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
var wnd = Functions.WindowFunctions.FindGameWindow();
|
||||||
if (wnd == IntPtr.Zero) return;
|
if (wnd == IntPtr.Zero) return;
|
||||||
if (_enabled)
|
if (_enabled)
|
||||||
WinApi.SetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE,
|
WinApi.SetWindowLong(wnd, WinApi.GWL_STYLE,
|
||||||
WinApi.GetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE) | (int)WindowStyles.WS_THICKFRAME | (int)WindowStyles.WS_MAXIMIZEBOX);
|
WinApi.GetWindowLong(wnd, WinApi.GWL_STYLE) | WinApi.WS_THICKFRAME | WinApi.WS_MAXIMIZEBOX);
|
||||||
else
|
else
|
||||||
WinApi.SetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE,
|
WinApi.SetWindowLong(wnd, WinApi.GWL_STYLE,
|
||||||
WinApi.GetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE) & ~((int)WindowStyles.WS_THICKFRAME | (int)WindowStyles.WS_MAXIMIZEBOX));
|
WinApi.GetWindowLong(wnd, WinApi.GWL_STYLE) & ~(WinApi.WS_THICKFRAME | WinApi.WS_MAXIMIZEBOX));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,7 +249,7 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
private static void MoveWindowPosition()
|
private static void MoveWindowPosition()
|
||||||
{
|
{
|
||||||
if (Screen.fullScreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow || GameMain.isRunning) return;
|
if (Screen.fullScreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow || GameMain.isRunning) return;
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
var wnd = Functions.WindowFunctions.FindGameWindow();
|
||||||
if (wnd == IntPtr.Zero) return;
|
if (wnd == IntPtr.Zero) return;
|
||||||
var rect = LastWindowRect.Value;
|
var rect = LastWindowRect.Value;
|
||||||
if (rect is { z: 0f, w: 0f }) return;
|
if (rect is { z: 0f, w: 0f }) return;
|
||||||
@@ -334,7 +282,7 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
{
|
{
|
||||||
if (_loaded || Screen.fullScreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow) return;
|
if (_loaded || Screen.fullScreenMode is FullScreenMode.ExclusiveFullScreen or FullScreenMode.FullScreenWindow or FullScreenMode.MaximizedWindow) return;
|
||||||
_loaded = true;
|
_loaded = true;
|
||||||
var wnd = WinApi.FindWindow(GameWindowClass, _gameWindowTitle);
|
var wnd = Functions.WindowFunctions.FindGameWindow();
|
||||||
if (wnd == IntPtr.Zero) return;
|
if (wnd == IntPtr.Zero) return;
|
||||||
var rect = LastWindowRect.Value;
|
var rect = LastWindowRect.Value;
|
||||||
if (rect is { z: 0f, w: 0f }) return;
|
if (rect is { z: 0f, w: 0f }) return;
|
||||||
@@ -345,8 +293,8 @@ public class GamePatch: PatchImpl<GamePatch>
|
|||||||
Screen.SetResolution(w, h, false);
|
Screen.SetResolution(w, h, false);
|
||||||
WinApi.SetWindowPos(wnd, IntPtr.Zero, x, y, 0, 0, 0x0235);
|
WinApi.SetWindowPos(wnd, IntPtr.Zero, x, y, 0, 0, 0x0235);
|
||||||
if (EnableWindowResizeEnabled.Value)
|
if (EnableWindowResizeEnabled.Value)
|
||||||
WinApi.SetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE,
|
WinApi.SetWindowLong(wnd, WinApi.GWL_STYLE,
|
||||||
WinApi.GetWindowLong(wnd, (int)WindowLongFlags.GWL_STYLE) | (int)WindowStyles.WS_THICKFRAME | (int)WindowStyles.WS_MAXIMIZEBOX);
|
WinApi.GetWindowLong(wnd, WinApi.GWL_STYLE) | WinApi.WS_THICKFRAME | WinApi.WS_MAXIMIZEBOX);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GameOption _gameOption;
|
private static GameOption _gameOption;
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ public static class UIConfigWindow
|
|||||||
*/
|
*/
|
||||||
y += 36f;
|
y += 36f;
|
||||||
wnd.AddCheckBox(x, y, tab1, GamePatch.ConvertSavesFromPeaceEnabled, "Convert old saves to Combat Mode on loading");
|
wnd.AddCheckBox(x, y, tab1, GamePatch.ConvertSavesFromPeaceEnabled, "Convert old saves to Combat Mode on loading");
|
||||||
if (GamePatch.ProfileName != null)
|
if (WindowFunctions.ProfileName != null)
|
||||||
{
|
{
|
||||||
y += 36f;
|
y += 36f;
|
||||||
checkBoxForMeasureTipsPos = wnd.AddCheckBox(x, y, tab1, GamePatch.ProfileBasedSaveFolderEnabled, "Profile-based save folder");
|
checkBoxForMeasureTipsPos = wnd.AddCheckBox(x, y, tab1, GamePatch.ProfileBasedSaveFolderEnabled, "Profile-based save folder");
|
||||||
@@ -162,6 +162,10 @@ public static class UIConfigWindow
|
|||||||
y += 18f;
|
y += 18f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x = 400f;
|
||||||
|
y = 10f;
|
||||||
|
wnd.AddButton(x, y, tab1, "Show CPU Info", 16, "button-show-cpu-info", WindowFunctions.ShowCPUInfo);
|
||||||
|
|
||||||
if (!ModsCompat.BulletTimeWrapper.HasBulletTime)
|
if (!ModsCompat.BulletTimeWrapper.HasBulletTime)
|
||||||
{
|
{
|
||||||
y += 36f;
|
y += 36f;
|
||||||
@@ -351,6 +355,7 @@ public static class UIConfigWindow
|
|||||||
cb1.gameObject.SetActive(true);
|
cb1.gameObject.SetActive(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var on = !ModsCompat.AuxilaryfunctionWrapper.ShowStationInfo.Value;
|
var on = !ModsCompat.AuxilaryfunctionWrapper.ShowStationInfo.Value;
|
||||||
cb0.gameObject.SetActive(on);
|
cb0.gameObject.SetActive(on);
|
||||||
cb1.gameObject.SetActive(on);
|
cb1.gameObject.SetActive(on);
|
||||||
|
|||||||
@@ -158,7 +158,8 @@ public class UXAssist : BaseUnityPlugin, IModCanSave
|
|||||||
|
|
||||||
UIConfigWindow.Init();
|
UIConfigWindow.Init();
|
||||||
|
|
||||||
_patches = Common.Util.GetTypesInNamespace(Assembly.GetExecutingAssembly(), "UXAssist.Patches");
|
_patches = Common.Util.GetTypesFiltered(Assembly.GetExecutingAssembly(),
|
||||||
|
t => string.Equals(t.Namespace, "UXAssist.Patches", StringComparison.Ordinal) || string.Equals(t.Namespace, "UXAssist.Functions", StringComparison.Ordinal));
|
||||||
_patches?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
_patches?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
||||||
_compats = Common.Util.GetTypesInNamespace(Assembly.GetExecutingAssembly(), "UXAssist.ModsCompat");
|
_compats = Common.Util.GetTypesInNamespace(Assembly.GetExecutingAssembly(), "UXAssist.ModsCompat");
|
||||||
_compats?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
_compats?.Do(type => type.GetMethod("Init")?.Invoke(null, null));
|
||||||
|
|||||||
Reference in New Issue
Block a user