using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Threading;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Unity.IL2CPP;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace WindowCanvasScaler
{
[BepInPlugin("khundian.sod.uiscaler", "Shadows of Doubt UI Scaler", "1.0.1")]
public class Plugin : BasePlugin
{
private struct OriginalScaler
{
public bool existed;
public ScaleMode uiScaleMode;
public Vector2 referenceResolution;
public float matchWidthOrHeight;
public ScreenMatchMode screenMatchMode;
}
public class UiDriver : MonoBehaviour
{
private string _toast = "";
private float _toastUntil;
private GUIStyle? _toastStyle;
public UiDriver(IntPtr handle)
: base(handle)
{
}
public UiDriver()
{
}
private void OnEnable()
{
Instance?.DebugMsg("UiDriver.OnEnable");
((MonoBehaviour)this).CancelInvoke("Tick");
((MonoBehaviour)this).CancelInvoke("Heartbeat");
((MonoBehaviour)this).InvokeRepeating("Tick", 0.25f, 0.25f);
((MonoBehaviour)this).InvokeRepeating("Heartbeat", 1f, 3f);
}
private void OnDisable()
{
Instance?.DebugMsg("UiDriver.OnDisable");
((MonoBehaviour)this).CancelInvoke("Tick");
((MonoBehaviour)this).CancelInvoke("Heartbeat");
}
private void Update()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_0162: Unknown result type (might be due to invalid IL or missing references)
Plugin instance = Instance;
if (instance == null)
{
return;
}
if (Input.GetKeyDown(instance._keyToggle))
{
bool flag = !CfgEnabled.Value;
CfgEnabled.Value = flag;
instance._saveConfigAtMs = (double)Time.unscaledTime * 1000.0 + 500.0;
if (!flag)
{
instance.RevertAll();
ShowToast("UI Scaler: Disabled (reverted)");
}
else
{
instance._configuredCanvasIds.Clear();
instance.SafeRescan();
ShowToast("UI Scaler: Enabled");
}
instance._lastEnabledState = flag;
}
if (Input.GetKeyDown(instance._keyUp))
{
float num = Mathf.Clamp(Mathf.Round((CfgUiScale.Value + 0.05f) * 20f) / 20f, 0.1f, 5f);
if (Math.Abs(num - CfgUiScale.Value) > 0.0001f)
{
CfgUiScale.Value = num;
instance._saveConfigAtMs = (double)Time.unscaledTime * 1000.0 + 500.0;
ShowToast($"UI Scale: {num:0.00}x");
if (CfgEnabled.Value)
{
instance.RevertAll();
instance.SafeRescan();
}
}
}
if (!Input.GetKeyDown(instance._keyDown))
{
return;
}
float num2 = Mathf.Clamp(Mathf.Round((CfgUiScale.Value - 0.05f) * 20f) / 20f, 0.1f, 5f);
if (Math.Abs(num2 - CfgUiScale.Value) > 0.0001f)
{
CfgUiScale.Value = num2;
instance._saveConfigAtMs = (double)Time.unscaledTime * 1000.0 + 500.0;
ShowToast($"UI Scale: {num2:0.00}x");
if (CfgEnabled.Value)
{
instance.RevertAll();
instance.SafeRescan();
}
}
}
private void Heartbeat()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
if (CfgLogTicks.Value && Instance != null)
{
Scene activeScene = SceneManager.GetActiveScene();
Instance.Info($"[Tick] scene='{((Scene)(ref activeScene)).name}' buildIndex={((Scene)(ref activeScene)).buildIndex} configured={Instance._configuredCanvasIds.Count}");
}
}
private void OnGUI()
{
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0034: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Expected O, but got Unknown
if (!(Time.unscaledTime > _toastUntil))
{
if (_toastStyle == null)
{
_toastStyle = new GUIStyle(GUI.skin.label)
{
alignment = (TextAnchor)4,
fontStyle = (FontStyle)1,
fontSize = 18
};
}
int num = Mathf.Min(Screen.width - 40, 800);
Rect val = new Rect((float)(Screen.width - num) * 0.5f, 20f, (float)num, 32f);
GUI.Box(val, GUIContent.none);
GUI.Label(val, _toast, _toastStyle);
}
}
private void Tick()
{
//IL_01ab: Unknown result type (might be due to invalid IL or missing references)
//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
Plugin instance = Instance;
if (instance == null)
{
return;
}
double num = (double)Time.unscaledTime * 1000.0;
if (Volatile.Read(ref instance._cfgReloadRequested) == 1)
{
if (instance._cfgReloadAtMs <= 0.0)
{
instance._cfgReloadAtMs = num + 200.0;
}
else if (num >= instance._cfgReloadAtMs)
{
Interlocked.Exchange(ref instance._cfgReloadRequested, 0);
instance._cfgReloadAtMs = 0.0;
instance.DebugMsg("Config changed on disk; reloading...");
try
{
((BasePlugin)instance).Config.Reload();
instance.UpdateParsedHotkeys();
instance.UpdateCachedNameTokens();
bool value = CfgEnabled.Value;
if (instance._lastEnabledState && !value)
{
instance.RevertAll();
ShowToast("UI Scaler: Disabled (reverted)");
}
else if (!instance._lastEnabledState && value)
{
instance._configuredCanvasIds.Clear();
instance.SafeRescan();
ShowToast("UI Scaler: Enabled");
}
if (value)
{
instance.RevertAll();
instance.SafeRescan();
ShowToast($"UI Scaler: Reloaded ({CfgUiScale.Value:0.00}x)");
}
instance._lastEnabledState = value;
instance.DebugMsg("Config reloaded and applied.");
}
catch (Exception ex)
{
instance.Info("Config reload failed: " + ex.Message);
}
}
}
if (instance._saveConfigAtMs > 0.0 && num >= instance._saveConfigAtMs)
{
instance._saveConfigAtMs = 0.0;
try
{
((BasePlugin)instance).Config.Save();
}
catch
{
}
}
Scene activeScene = SceneManager.GetActiveScene();
if (((Scene)(ref activeScene)).buildIndex != instance._lastSceneIndex || ((Scene)(ref activeScene)).name != instance._lastSceneName)
{
instance.Info($"[SceneChange] '{instance._lastSceneName}' -> '{((Scene)(ref activeScene)).name}' ({instance._lastSceneIndex}->{((Scene)(ref activeScene)).buildIndex})");
instance._lastSceneName = ((Scene)(ref activeScene)).name ?? string.Empty;
instance._lastSceneIndex = ((Scene)(ref activeScene)).buildIndex;
instance._configuredCanvasIds.Clear();
if (CfgEnabled.Value)
{
instance.SafeRescan();
}
}
if (CfgEnabled.Value && num >= instance._nextRescanAtMs)
{
float num2 = Mathf.Max(250f, (float)CfgRescanMS.Value);
instance._nextRescanAtMs = num + (double)num2;
instance.SafeRescan();
}
}
private void ShowToast(string s)
{
_toast = s;
_toastUntil = Time.unscaledTime + 1.5f;
}
}
public const string PluginGuid = "khundian.sod.uiscaler";
public const string PluginName = "Shadows of Doubt UI Scaler";
public const string PluginVersion = "1.0.1";
internal static Plugin Instance;
internal static ConfigEntry<bool> CfgEnabled;
internal static ConfigEntry<bool> CfgVerbose;
internal static ConfigEntry<bool> CfgLogTicks;
internal static ConfigEntry<int> CfgRefWidth;
internal static ConfigEntry<int> CfgRefHeight;
internal static ConfigEntry<float> CfgMatchWH;
internal static ConfigEntry<float> CfgUiScale;
internal static ConfigEntry<bool> CfgIncludeWorldSpace;
internal static ConfigEntry<bool> CfgActiveSceneOnly;
internal static ConfigEntry<string> CfgCanvasIncludeTokens;
internal static ConfigEntry<string> CfgCanvasExcludeTokens;
internal static ConfigEntry<int> CfgRescanMS;
internal static ConfigEntry<string> CfgKeyToggle;
internal static ConfigEntry<string> CfgKeyScaleUp;
internal static ConfigEntry<string> CfgKeyScaleDown;
private readonly HashSet<int> _configuredCanvasIds = new HashSet<int>();
private readonly Dictionary<int, (Canvas canvas, OriginalScaler original)> _originalById = new Dictionary<int, (Canvas, OriginalScaler)>();
private readonly List<int> _pruneKeys = new List<int>(64);
private double _nextRescanAtMs;
private string _lastSceneName = string.Empty;
private int _lastSceneIndex = -1;
private bool _lastEnabledState = true;
private UiDriver _driver;
private string[] _incTokens = Array.Empty<string>();
private string[] _excTokens = Array.Empty<string>();
private double _cfgReloadAtMs;
private double _saveConfigAtMs;
private KeyCode _keyToggle = (KeyCode)290;
private KeyCode _keyUp = (KeyCode)292;
private KeyCode _keyDown = (KeyCode)291;
private FileSystemWatcher? _cfgWatcher;
private int _cfgReloadRequested;
public override void Load()
{
//IL_024c: Unknown result type (might be due to invalid IL or missing references)
//IL_0252: Expected O, but got Unknown
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_0282: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
((BasePlugin)this).Config.GenerateSettingDescriptions = true;
((BasePlugin)this).Config.SaveOnConfigSet = true;
CfgEnabled = ((BasePlugin)this).Config.Bind<bool>("General", "Enabled", true, "Master switch. true = apply Canvas Scaler; false = revert all and pause.");
CfgVerbose = ((BasePlugin)this).Config.Bind<bool>("Logging", "Verbose", false, "When true, prints detailed discovery/apply logs.");
CfgLogTicks = ((BasePlugin)this).Config.Bind<bool>("Logging", "LogTicks", false, "When true, prints a 3s heartbeat with scene & configured counts.");
CfgRefWidth = ((BasePlugin)this).Config.Bind<int>("Scaling", "ReferenceWidth", 1920, "Scaler Reference Resolution (width).");
CfgRefHeight = ((BasePlugin)this).Config.Bind<int>("Scaling", "ReferenceHeight", 1080, "Scaler Reference Resolution (height).");
CfgMatchWH = ((BasePlugin)this).Config.Bind<float>("Scaling", "MatchWidthOrHeight", 0.5f, "Match: 0=width, 1=height.");
CfgUiScale = ((BasePlugin)this).Config.Bind<float>("Scaling", "UiScaleMultiplier", 1f, "Resolution multiplier (e.g., 1.25 = 125%).");
CfgIncludeWorldSpace = ((BasePlugin)this).Config.Bind<bool>("Filter", "IncludeWorldSpaceCanvases", false, "Include RenderMode.WorldSpace canvases.");
CfgActiveSceneOnly = ((BasePlugin)this).Config.Bind<bool>("Filter", "ActiveSceneOnly", true, "Affect only canvases in the active scene.");
CfgCanvasIncludeTokens = ((BasePlugin)this).Config.Bind<string>("Filter", "CanvasIncludeTokens", "", "CSV/semicolon tokens; empty = include all.");
CfgCanvasExcludeTokens = ((BasePlugin)this).Config.Bind<string>("Filter", "CanvasExcludeTokens", "", "CSV/semicolon tokens; empty = exclude none.");
CfgRescanMS = ((BasePlugin)this).Config.Bind<int>("Engine", "RescanEveryMilliseconds", 2000, "Periodic rescan interval.");
CfgKeyToggle = ((BasePlugin)this).Config.Bind<string>("Hotkeys", "Toggle", "F9", "Enable/disable plugin.");
CfgKeyScaleUp = ((BasePlugin)this).Config.Bind<string>("Hotkeys", "ScaleUp", "F11", "Increase UiScale by +5%.");
CfgKeyScaleDown = ((BasePlugin)this).Config.Bind<string>("Hotkeys", "ScaleDown", "F10", "Decrease UiScale by −5%.");
_lastEnabledState = CfgEnabled.Value;
UpdateParsedHotkeys();
UpdateCachedNameTokens();
ClassInjector.RegisterTypeInIl2Cpp<UiDriver>();
GameObject val = new GameObject("ShadowsOfDoubt.UIScaler.Host");
((Object)val).hideFlags = (HideFlags)61;
Object.DontDestroyOnLoad((Object)(object)val);
_driver = val.AddComponent<UiDriver>();
Info("Loaded.");
DumpConfig();
Scene activeScene = SceneManager.GetActiveScene();
_lastSceneName = ((Scene)(ref activeScene)).name ?? string.Empty;
_lastSceneIndex = ((Scene)(ref activeScene)).buildIndex;
SafeRescan();
WriteConfigHeaderIfMissing();
StartConfigWatcher();
}
private void SafeRescan()
{
//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
//IL_013b: Unknown result type (might be due to invalid IL or missing references)
//IL_0141: Invalid comparison between Unknown and I4
//IL_0156: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
Profiler.BeginSample("UIScaler.Rescan");
try
{
int num = 0;
_pruneKeys.Clear();
foreach (KeyValuePair<int, (Canvas, OriginalScaler)> item in _originalById)
{
if ((Object)(object)item.Value.Item1 == (Object)null)
{
_pruneKeys.Add(item.Key);
}
}
num = _pruneKeys.Count;
for (int i = 0; i < _pruneKeys.Count; i++)
{
_originalById.Remove(_pruneKeys[i]);
}
_pruneKeys.Clear();
Scene activeScene = SceneManager.GetActiveScene();
Il2CppArrayBase<Canvas> val = Object.FindObjectsOfType<Canvas>(true);
TryEnsureCapacity(_originalById, Math.Max(_originalById.Count, val.Length * 2));
TryEnsureCapacity(_configuredCanvasIds, Math.Max(_configuredCanvasIds.Count, val.Length * 2));
int num2 = 0;
int num3 = 0;
foreach (Canvas item2 in val)
{
if ((Object)(object)item2 == (Object)null || (!CfgIncludeWorldSpace.Value && (int)item2.renderMode == 2))
{
continue;
}
if (CfgActiveSceneOnly.Value)
{
Scene scene = ((Component)item2).gameObject.scene;
if (((Scene)(ref scene)).handle != ((Scene)(ref activeScene)).handle)
{
continue;
}
}
if (NameAllowed(((Object)item2).name))
{
num2++;
if (ApplyScaler(item2))
{
num3++;
}
}
}
if (num3 > 0)
{
Canvas.ForceUpdateCanvases();
}
if (CfgVerbose.Value)
{
DebugMsg($"Rescan: seen={num2}, configuredNow={num3}, totalConfigured={_configuredCanvasIds.Count}, cleaned={num}");
}
}
catch (Exception value)
{
Info($"Rescan error: {value}");
}
finally
{
Profiler.EndSample();
}
}
private unsafe bool ApplyScaler(Canvas c)
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01f3: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Unknown result type (might be due to invalid IL or missing references)
//IL_0072: Unknown result type (might be due to invalid IL or missing references)
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_0057->IL0057: Incompatible stack types: Ref vs I4
//IL_0050->IL0057: Incompatible stack types: I4 vs Ref
//IL_0050->IL0057: Incompatible stack types: Ref vs I4
//IL_00ba->IL00ba: Incompatible stack types: Ref vs I4
//IL_00b3->IL00ba: Incompatible stack types: I4 vs Ref
//IL_00b3->IL00ba: Incompatible stack types: Ref vs I4
Profiler.BeginSample("UIScaler.Apply");
try
{
int instanceID = ((Object)c).GetInstanceID();
if (!_originalById.ContainsKey(instanceID))
{
CanvasScaler component = ((Component)c).GetComponent<CanvasScaler>();
OriginalScaler originalScaler = default(OriginalScaler);
originalScaler.existed = (Object)(object)component != (Object)null;
ref OriginalScaler reference = ref originalScaler;
int num;
if ((Object)(object)component != (Object)null)
{
reference = ref *(OriginalScaler*)component.uiScaleMode;
num = (int)(ref reference);
}
else
{
num = 0;
reference = ref *(OriginalScaler*)num;
num = (int)(ref reference);
}
Unsafe.Write(&((OriginalScaler*)num)->uiScaleMode, (ScaleMode)(ref reference));
originalScaler.referenceResolution = (Vector2)(((Object)(object)component != (Object)null) ? component.referenceResolution : new Vector2(1920f, 1080f));
originalScaler.matchWidthOrHeight = (((Object)(object)component != (Object)null) ? component.matchWidthOrHeight : 0.5f);
ref OriginalScaler reference2 = ref originalScaler;
int num2;
if ((Object)(object)component != (Object)null)
{
reference2 = ref *(OriginalScaler*)component.screenMatchMode;
num2 = (int)(ref reference2);
}
else
{
num2 = 0;
reference2 = ref *(OriginalScaler*)num2;
num2 = (int)(ref reference2);
}
Unsafe.Write(&((OriginalScaler*)num2)->screenMatchMode, (ScreenMatchMode)(ref reference2));
OriginalScaler item = originalScaler;
_originalById[instanceID] = (c, item);
}
if (_configuredCanvasIds.Contains(instanceID))
{
return false;
}
CanvasScaler val = ((Component)c).GetComponent<CanvasScaler>();
if ((Object)(object)val == (Object)null)
{
val = ((Component)c).gameObject.AddComponent<CanvasScaler>();
}
val.uiScaleMode = (ScaleMode)1;
float num3 = Mathf.Max(0.1f, Mathf.Min(5f, CfgUiScale.Value));
Vector2 referenceResolution = default(Vector2);
((Vector2)(ref referenceResolution))..ctor((float)Mathf.Max(1, Mathf.RoundToInt((float)CfgRefWidth.Value / num3)), (float)Mathf.Max(1, Mathf.RoundToInt((float)CfgRefHeight.Value / num3)));
val.referenceResolution = referenceResolution;
val.screenMatchMode = (ScreenMatchMode)0;
val.matchWidthOrHeight = Mathf.Clamp01(CfgMatchWH.Value);
_configuredCanvasIds.Add(instanceID);
if (CfgVerbose.Value)
{
DebugMsg($"Configured '{((Object)c).name}' (mode={c.renderMode}, ref={val.referenceResolution}, match={val.matchWidthOrHeight:0.00})");
}
return true;
}
catch (Exception value)
{
Info($"ApplyScaler error on canvas '{((c != null) ? ((Object)c).name : null)}': {value}");
return false;
}
finally
{
Profiler.EndSample();
}
}
private void RevertAll()
{
//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
int num = 0;
int num2 = 0;
Profiler.BeginSample("UIScaler.RevertAll");
try
{
_pruneKeys.Clear();
foreach (KeyValuePair<int, (Canvas, OriginalScaler)> item in _originalById)
{
int key = item.Key;
var (val, originalScaler) = item.Value;
if ((Object)(object)val == (Object)null)
{
_pruneKeys.Add(key);
continue;
}
CanvasScaler val2 = ((Component)val).GetComponent<CanvasScaler>();
if (!originalScaler.existed && (Object)(object)val2 != (Object)null)
{
Object.Destroy((Object)(object)val2);
num++;
}
else if (originalScaler.existed)
{
if ((Object)(object)val2 == (Object)null)
{
val2 = ((Component)val).gameObject.AddComponent<CanvasScaler>();
}
val2.uiScaleMode = originalScaler.uiScaleMode;
val2.referenceResolution = originalScaler.referenceResolution;
val2.matchWidthOrHeight = originalScaler.matchWidthOrHeight;
val2.screenMatchMode = originalScaler.screenMatchMode;
num++;
}
_configuredCanvasIds.Remove(key);
}
num2 = _pruneKeys.Count;
for (int i = 0; i < _pruneKeys.Count; i++)
{
_originalById.Remove(_pruneKeys[i]);
}
_pruneKeys.Clear();
Info($"Reverted {num} canvases; cleaned {num2} stale entries.");
}
finally
{
Profiler.EndSample();
}
Canvas.ForceUpdateCanvases();
}
private void WriteConfigHeaderIfMissing()
{
try
{
string path = Path.Combine(Paths.ConfigPath, "khundian.sod.uiscaler.cfg");
if (File.Exists(path))
{
string text = File.ReadAllText(path);
if (!text.StartsWith("# === Shadows of Doubt UI Scaler ===", StringComparison.Ordinal))
{
string text2 = string.Join(Environment.NewLine, "# === Shadows of Doubt UI Scaler ===", "# Version: 1.0.1", "#", "# Scales UI using Unity's Canvas Scaler (Scale With Screen Size).", "# [Hotkeys] use Unity KeyCode names (F9, F11, F10, BackQuote, etc.).", "# Toggle default is F9 (avoids Steam F12 screenshot).", "#", "");
File.WriteAllText(path, text2 + text);
}
}
}
catch (Exception ex)
{
Info("Config header write skipped: " + ex.Message);
}
}
private void StartConfigWatcher()
{
try
{
string configPath = Paths.ConfigPath;
string filter = "khundian.sod.uiscaler.cfg";
_cfgWatcher = new FileSystemWatcher(configPath, filter)
{
NotifyFilter = (NotifyFilters.FileName | NotifyFilters.Size | NotifyFilters.LastWrite),
IncludeSubdirectories = false,
EnableRaisingEvents = true
};
_cfgWatcher.Changed += OnCfgChanged;
_cfgWatcher.Created += OnCfgChanged;
_cfgWatcher.Renamed += OnCfgRenamed;
Info("Config watcher started.");
}
catch (Exception ex)
{
Info("Config watcher unavailable: " + ex.Message);
}
}
private void OnCfgChanged(object sender, FileSystemEventArgs e)
{
Interlocked.Exchange(ref _cfgReloadRequested, 1);
}
private void OnCfgRenamed(object sender, RenamedEventArgs e)
{
OnCfgChanged(sender, e);
}
private static void TryEnsureCapacity<TVal>(Dictionary<int, TVal> dict, int capacity)
{
try
{
MethodInfo method = dict.GetType().GetMethod("EnsureCapacity", new Type[1] { typeof(int) });
if (method != null)
{
method.Invoke(dict, new object[1] { capacity });
}
}
catch
{
}
}
private static void TryEnsureCapacity(HashSet<int> set, int capacity)
{
try
{
MethodInfo method = set.GetType().GetMethod("EnsureCapacity", new Type[1] { typeof(int) });
if (method != null)
{
method.Invoke(set, new object[1] { capacity });
}
}
catch
{
}
}
private static string[] SplitTokens(string csv)
{
if (string.IsNullOrWhiteSpace(csv))
{
return Array.Empty<string>();
}
return (from s in csv.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries)
select s.Trim() into s
where s.Length > 0
select s).ToArray();
}
private bool NameAllowed(string name)
{
string name2 = name;
string[] incTokens = _incTokens;
string[] excTokens = _excTokens;
if (incTokens.Length != 0 && !incTokens.Any((string tok) => name2.IndexOf(tok, StringComparison.OrdinalIgnoreCase) >= 0))
{
return false;
}
if (excTokens.Length != 0 && excTokens.Any((string tok) => name2.IndexOf(tok, StringComparison.OrdinalIgnoreCase) >= 0))
{
return false;
}
return true;
}
private void UpdateCachedNameTokens()
{
_incTokens = SplitTokens(CfgCanvasIncludeTokens.Value);
_excTokens = SplitTokens(CfgCanvasExcludeTokens.Value);
}
private static KeyCode ParseKey(string s, KeyCode fallback)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: Unknown result type (might be due to invalid IL or missing references)
//IL_0008: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_001c: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Unknown result type (might be due to invalid IL or missing references)
if (string.IsNullOrWhiteSpace(s))
{
return fallback;
}
try
{
return (KeyCode)Enum.Parse(typeof(KeyCode), s, ignoreCase: true);
}
catch
{
return fallback;
}
}
private void UpdateParsedHotkeys()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0042: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Unknown result type (might be due to invalid IL or missing references)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
_keyToggle = ParseKey(CfgKeyToggle.Value, _keyToggle);
_keyUp = ParseKey(CfgKeyScaleUp.Value, _keyUp);
_keyDown = ParseKey(CfgKeyScaleDown.Value, _keyDown);
}
private void DumpConfig()
{
Info($"Enabled={CfgEnabled.Value} Scale={CfgUiScale.Value:0.00} Ref={CfgRefWidth.Value}x{CfgRefHeight.Value} Match={CfgMatchWH.Value:0.00} IncludeWS={CfgIncludeWorldSpace.Value} ActiveSceneOnly={CfgActiveSceneOnly.Value} RescanMS={CfgRescanMS.Value}");
}
internal void Info(string s)
{
((BasePlugin)this).Log.LogInfo((object)s);
}
internal void DebugMsg(string s)
{
if (CfgVerbose.Value)
{
((BasePlugin)this).Log.LogDebug((object)s);
}
}
}
}