1+ [ assembly: MelonInfo ( typeof ( Mod ) , "Bye Sweet Carole Ultra-Wide" , "0.1.0" , "p1xel8ted" ) ]
2+
3+ namespace ByeSweetCarole ;
4+
5+ public class Mod : MelonMod
6+ {
7+ public enum TargetFrameRateOption
8+ {
9+ Sixty = 60 ,
10+ OneTwenty = 120 ,
11+ OneEighty = 180 ,
12+ TwoForty = 240 ,
13+ ThreeSixty = 360 ,
14+ MaxRefresh = - 1
15+ }
16+
17+
18+ public enum VsyncOption
19+ {
20+ Disabled ,
21+ EveryRefresh ,
22+ EverySecondRefresh
23+ }
24+
25+ #if DEBUG
26+ internal static readonly int NativeDisplayWidth = 3200 ;
27+ internal static readonly int NativeDisplayHeight = 900 ;
28+ #else
29+ internal static readonly int NativeDisplayWidth = Display . main . systemWidth ; //3440
30+ internal static readonly int NativeDisplayHeight = Display . main . systemHeight ; //1440
31+ #endif
32+
33+
34+ internal static readonly int MaxRefresh = Screen . resolutions . Max ( a => a . refreshRate ) ; //144
35+ internal static float MainAspect => NativeDisplayWidth / ( float ) NativeDisplayHeight ; //2.3888
36+ internal static Rect CameraRect => new ( 0 , 0 , NativeDisplayWidth , NativeDisplayHeight ) ; //(0,0,3440,1440)
37+ private static float NormalWidth => NativeDisplayHeight * 16f / 9f ; //2560
38+ internal static float PositiveScaleFactor => NativeDisplayWidth / NormalWidth ; //1.34375
39+
40+
41+ private static MelonPreferences_Entry < bool > RunInBackground { get ; set ; }
42+ private static MelonPreferences_Entry < bool > MuteInBackground { get ; set ; }
43+
44+ internal static MelonPreferences_Entry < FullScreenMode > FullScreenModeConfig { get ; private set ; }
45+
46+
47+ private static MelonPreferences_Entry < TargetFrameRateOption > TargetFramerate { get ; set ; }
48+ internal static float NativeAspectRatio => 16f / 9f ; //1.7777
49+ private static float CameraWidth => NativeDisplayHeight * NativeAspectRatio ; //2560
50+ internal static float BlackBarSize => ( NativeDisplayWidth - CameraWidth ) / 2f ; //440
51+
52+ private static MelonPreferences_Entry < VsyncOption > VSyncSetting { get ; set ; }
53+ private static bool RequiresUpdate { get ; set ; }
54+
55+ private static void UpdateCanvasScalers ( )
56+ {
57+ foreach ( var scaler in Patches . Patches . Scalers . Where ( scaler => scaler ) )
58+ {
59+ Patches . Patches . ProcessScaler ( scaler ) ;
60+ }
61+ }
62+
63+ private static void FocusChanged ( bool focus )
64+ {
65+ Application . runInBackground = RunInBackground . Value ;
66+ var audioSources = Resources . FindObjectsOfTypeAll < AudioSource > ( ) ;
67+ foreach ( var audioSource in audioSources )
68+ {
69+ audioSource . mute = ! focus && MuteInBackground . Value ;
70+ }
71+ }
72+
73+ public override void OnInitializeMelon ( )
74+ {
75+ var category = MelonPreferences . CreateCategory ( "ByeSweetCaroleUltraWideFix" , "Bye Sweet Carole Ultra-Wide Settings" ) ;
76+ category . SetFilePath ( Path . Combine ( "UserData" , "Bye Sweet Carole Ultra-Wide Settings.cfg" ) , true , true ) ;
77+
78+ // Display Entries
79+ FullScreenModeConfig = category . CreateEntry ( "FullScreenMode" , FullScreenMode . FullScreenWindow ,
80+ "Full Screen Mode" ,
81+ "Select how the game displays on your screen:\n " +
82+ "- FullScreenWindow (Recommended): Runs the game in a borderless window that covers the entire screen. " +
83+ "This mode offers seamless alt-tabbing and behaves like Exclusive Fullscreen on most modern Windows versions.\n " +
84+ "- Exclusive Fullscreen: Attempts to take direct control of the display for scenarios like legacy compatibility or HDR management. " +
85+ "On modern systems, its behavior is nearly identical to FullScreenWindow, so this mode is generally not needed.\n " +
86+ "- Windowed: Runs the game in a resizable window." ) ;
87+ FullScreenModeConfig . OnEntryValueChanged . Subscribe ( ( _ , _ ) => { UpdateAll ( true ) ; } ) ;
88+
89+ VSyncSetting = category . CreateEntry ( "VSyncSetting" , VsyncOption . Disabled ,
90+ "VSync Setting" ,
91+ "Control how VSync synchronizes the game's frame rate with your monitor's refresh rate to prevent screen tearing:\n " +
92+ "- Disabled (Higher Performance): Turns off synchronization, potentially improving performance but may cause screen tearing.\n " +
93+ "- Enabled (Every Refresh): Synchronizes with every monitor refresh, ensuring smooth visuals but might slightly reduce performance.\n " +
94+ "- Enabled (Every 2nd Refresh): Synchronizes with every second monitor refresh, effectively halving the refresh rate for weaker hardware or demanding setups." ) ;
95+ VSyncSetting . OnEntryValueChanged . Subscribe ( ( _ , _ ) => { UpdateAll ( true ) ; } ) ;
96+
97+ TargetFramerate = category . CreateEntry ( "TargetFramerate" , TargetFrameRateOption . MaxRefresh ,
98+ "Target Framerate" ,
99+ "Set the target framerate - this will only function when VSYNC is OFF (0)" ) ;
100+ TargetFramerate . OnEntryValueChanged . Subscribe ( ( _ , _ ) => { UpdateAll ( true ) ; } ) ;
101+
102+ // Background Entries
103+ RunInBackground = category . CreateEntry ( "RunInBackground" , true ,
104+ "Run In Background" ,
105+ "Allows the game to run even when not in focus." ) ;
106+
107+ MuteInBackground = category . CreateEntry ( "MuteInBackground" , false ,
108+ "Mute In Background" ,
109+ "Mutes the game's audio when it is not in focus." ) ;
110+
111+
112+ Application . focusChanged += ( Il2CppSystem . Action < bool > ) FocusChanged ;
113+
114+ MelonLogger . Msg ( $ "Plugin WitchSpring R Ultra-Wide is loaded!") ;
115+
116+ category . SaveToFile ( false ) ;
117+ MelonPreferences . Save ( ) ;
118+ }
119+
120+
121+ private static void UpdateAll ( bool force = false )
122+ {
123+ UpdateDisplay ( force ) ;
124+ }
125+
126+ public override void OnSceneWasLoaded ( int buildIndex , string sceneName )
127+ {
128+ base . OnSceneWasLoaded ( buildIndex , sceneName ) ;
129+
130+ UpdateCanvasScalers ( ) ;
131+ UpdateAll ( true ) ;
132+ }
133+
134+ private static void UpdateDisplay ( bool force = false )
135+ {
136+ // Apply VSync setting using the mapped value
137+
138+ QualitySettings . vSyncCount = ( int ) VSyncSetting . Value ;
139+
140+
141+ // Apply target frame rate only if VSync is off
142+ Application . targetFrameRate = QualitySettings . vSyncCount == 0 ? ( int ) TargetFramerate . Value : - 1 ;
143+
144+ if ( force )
145+ {
146+ RequiresUpdate = true ;
147+ }
148+
149+ if ( ! RequiresUpdate ) return ;
150+
151+ #if DEBUG
152+ Screen . SetResolution ( NativeDisplayWidth , NativeDisplayHeight , FullScreenMode . Windowed , MaxRefresh ) ;
153+ #else
154+ Screen . SetResolution ( NativeDisplayWidth , NativeDisplayHeight , FullScreenModeConfig . Value , MaxRefresh ) ;
155+ #endif
156+ MelonLogger . Msg ( $ "Resolution updated: { NativeDisplayWidth } x{ NativeDisplayHeight } , Full Screen Mode={ FullScreenModeConfig . Value } , Refresh Rate={ MaxRefresh } Hz") ;
157+
158+ RequiresUpdate = false ;
159+ }
160+ }
0 commit comments