Parcourir la source

Reformat part 1

Reformatting to match the style rules defined in the editorconfig and
also some of my personal preferences.

This is only a reformat with no optimizations or change in logic.

There are a lot of places I've missed reformatting and will go over
again later.

Some things I need to look out for are:
 * Order of fields, properties, methods etc. by access and other things
   inspired by stylecop.
 * Using is and not operator rather than == or != for comparisons with
   constants and null. Watch out for null comparisons with
   UnityEngine.Object though.
 * Prefer early return/continue/break etc.
 * Prefer no braces and expression body for single line
   statements/expressions.
 * Prefer patterns.

dotnet format seems to have removed the BOM for some files. idk why.

This was an huge amount of work and now I have an huge headache.
habeebweeb il y a 2 ans
Parent
commit
2a5d5a130b
150 fichiers modifiés avec 6038 ajouts et 4258 suppressions
  1. 1 1
      src/MeidoPhotoStudio.Converter/Converters/IConverter.cs
  2. 11 10
      src/MeidoPhotoStudio.Converter/Converters/MMConverter.cs
  3. 11 10
      src/MeidoPhotoStudio.Converter/Converters/MMPngConverter.cs
  4. 7 4
      src/MeidoPhotoStudio.Converter/MPSSceneSerializer.cs
  5. 13 5
      src/MeidoPhotoStudio.Converter/MultipleMaids/ConversionUtility.cs
  6. 4 2
      src/MeidoPhotoStudio.Converter/MultipleMaids/MMConstants.cs
  7. 1 1
      src/MeidoPhotoStudio.Converter/MultipleMaids/MMScene.cs
  8. 18 9
      src/MeidoPhotoStudio.Converter/MultipleMaids/MMSceneConverter.cs
  9. 7 5
      src/MeidoPhotoStudio.Converter/Plugin.cs
  10. 2 1
      src/MeidoPhotoStudio.Converter/PluginCore.cs
  11. 4 3
      src/MeidoPhotoStudio.Converter/UI.cs
  12. 1 1
      src/MeidoPhotoStudio.Converter/Utility/LZMA.cs
  13. 1 1
      src/MeidoPhotoStudio.Converter/Utility/PngUtility.cs
  14. 3 2
      src/MeidoPhotoStudio.Plugin/Configuration.cs
  15. 400 343
      src/MeidoPhotoStudio.Plugin/Constants.cs
  16. 40 20
      src/MeidoPhotoStudio.Plugin/DragPoint/CustomGizmo.cs
  17. 134 97
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPoint.cs
  18. 98 66
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGeneral.cs
  19. 38 17
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGravity.cs
  20. 121 82
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointLight.cs
  21. 19 14
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointMeido.cs
  22. 14 10
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointOther.cs
  23. 41 28
      src/MeidoPhotoStudio.Plugin/DragPoint/DragPointProp.cs
  24. 4 1
      src/MeidoPhotoStudio.Plugin/GUI/Controls/BaseControl.cs
  25. 8 3
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Button.cs
  26. 21 12
      src/MeidoPhotoStudio.Plugin/GUI/Controls/ComboBox.cs
  27. 146 101
      src/MeidoPhotoStudio.Plugin/GUI/Controls/DropDown.cs
  28. 12 4
      src/MeidoPhotoStudio.Plugin/GUI/Controls/KeyRebindButton.cs
  29. 9 3
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Modal.cs
  30. 50 35
      src/MeidoPhotoStudio.Plugin/GUI/Controls/SelectionGrid.cs
  31. 33 21
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Slider.cs
  32. 5 7
      src/MeidoPhotoStudio.Plugin/GUI/Controls/TextArea.cs
  33. 11 6
      src/MeidoPhotoStudio.Plugin/GUI/Controls/TextField.cs
  34. 13 9
      src/MeidoPhotoStudio.Plugin/GUI/Controls/Toggle.cs
  35. 53 25
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/AttachPropPane.cs
  36. 79 63
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/ModPropsPane.cs
  37. 39 31
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/MyRoomPropsPane.cs
  38. 45 30
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/PropManagerPane.cs
  39. 50 45
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/PropsPane.cs
  40. 30 28
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/BackgroundSelectorPane.cs
  41. 35 20
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/CameraPane.cs
  42. 22 18
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/DragPointPane.cs
  43. 36 14
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/BloomPane.cs
  44. 28 12
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/DepthOfFieldPane.cs
  45. 27 17
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/EffectPane.cs
  46. 14 14
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/EffectsPane.cs
  47. 49 23
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/FogPane.cs
  48. 4 3
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/OtherEffectsPane.cs
  49. 22 10
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/VignettePane.cs
  50. 169 124
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/LightsPane.cs
  51. 13 7
      src/MeidoPhotoStudio.Plugin/GUI/Panes/BasePane.cs
  52. 27 16
      src/MeidoPhotoStudio.Plugin/GUI/Panes/CallWindowPanes/MaidSelectorPane.cs
  53. 57 36
      src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/MaidFaceBlendPane.cs
  54. 89 56
      src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/MaidFaceSliderPane.cs
  55. 17 13
      src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/SaveFacePane.cs
  56. 11 8
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BG2WindowPane.cs
  57. 6 8
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BGWindowPane.cs
  58. 3 1
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BaseMainWindowPane.cs
  59. 12 10
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/CallWindowPane.cs
  60. 10 8
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/FaceWindowPane.cs
  61. 37 29
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/PoseWindowPane.cs
  62. 40 45
      src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/SettingsWindowPane.cs
  63. 49 29
      src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/MaidSwitcherPane.cs
  64. 15 10
      src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/TabsPane.cs
  65. 28 22
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/CopyPosePane.cs
  66. 24 14
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/GravityControlPane.cs
  67. 32 21
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/HandPresetPane.cs
  68. 164 131
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidDressingPane.cs
  69. 32 22
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidFreeLookPane.cs
  70. 24 19
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidIKPane.cs
  71. 58 40
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidPoseSelectorPane.cs
  72. 28 22
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MpnAttachPropPane.cs
  73. 17 15
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/SaveHandPane.cs
  74. 16 13
      src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/SavePosePane.cs
  75. 27 21
      src/MeidoPhotoStudio.Plugin/GUI/Panes/SceneManagerPanes/SceneManagerDirectoryPane.cs
  76. 20 14
      src/MeidoPhotoStudio.Plugin/GUI/Panes/SceneManagerPanes/SceneManagerScenePane.cs
  77. 46 25
      src/MeidoPhotoStudio.Plugin/GUI/Panes/SceneManagerPanes/SceneManagerTitleBar.cs
  78. 37 28
      src/MeidoPhotoStudio.Plugin/GUI/Windows/BaseWindow.cs
  79. 62 42
      src/MeidoPhotoStudio.Plugin/GUI/Windows/MainWindow.cs
  80. 48 40
      src/MeidoPhotoStudio.Plugin/GUI/Windows/MessageWindow.cs
  81. 70 57
      src/MeidoPhotoStudio.Plugin/GUI/Windows/SceneModalWindow.cs
  82. 23 17
      src/MeidoPhotoStudio.Plugin/GUI/Windows/SceneWindow.cs
  83. 15 8
      src/MeidoPhotoStudio.Plugin/MPSScene.cs
  84. 51 43
      src/MeidoPhotoStudio.Plugin/MaidPlacementUtility.cs
  85. 46 28
      src/MeidoPhotoStudio.Plugin/Managers/CameraManager.cs
  86. 11 6
      src/MeidoPhotoStudio.Plugin/Managers/EffectManager.cs
  87. 38 18
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/BloomEffectManager.cs
  88. 13 5
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/BlurEffectManager.cs
  89. 22 14
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/DepthOfFieldManager.cs
  90. 33 12
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/FogEffectManager.cs
  91. 1 0
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/IEffectManager.cs
  92. 10 4
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/SepiaToneEffectManager.cs
  93. 16 6
      src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/VignetteEffectManager.cs
  94. 44 24
      src/MeidoPhotoStudio.Plugin/Managers/EnvironmentManager.cs
  95. 69 42
      src/MeidoPhotoStudio.Plugin/Managers/InputManager.cs
  96. 71 35
      src/MeidoPhotoStudio.Plugin/Managers/LightManager.cs
  97. 228 195
      src/MeidoPhotoStudio.Plugin/Managers/MeidoManager.cs
  98. 3 5
      src/MeidoPhotoStudio.Plugin/Managers/MessageWindowManager.cs
  99. 118 72
      src/MeidoPhotoStudio.Plugin/Managers/PropManager.cs
  100. 132 94
      src/MeidoPhotoStudio.Plugin/Managers/SceneManager.cs
  101. 20 12
      src/MeidoPhotoStudio.Plugin/Managers/WindowManager.cs
  102. 32 20
      src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointFinger.cs
  103. 26 30
      src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointHead.cs
  104. 20 12
      src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointPelvis.cs
  105. 32 26
      src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointSpine.cs
  106. 30 23
      src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointTorso.cs
  107. 8 6
      src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointChain.cs
  108. 52 28
      src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointLimb.cs
  109. 19 8
      src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointMune.cs
  110. 376 248
      src/MeidoPhotoStudio.Plugin/Meido/Meido.cs
  111. 280 232
      src/MeidoPhotoStudio.Plugin/Meido/MeidoDragPointManager.cs
  112. 132 96
      src/MeidoPhotoStudio.Plugin/MeidoPhotoStudio.cs
  113. 31 16
      src/MeidoPhotoStudio.Plugin/MenuFileCache.cs
  114. 114 64
      src/MeidoPhotoStudio.Plugin/MenuFileUtility.cs
  115. 37 22
      src/MeidoPhotoStudio.Plugin/MenuItem.cs
  116. 194 126
      src/MeidoPhotoStudio.Plugin/ModelUtility.cs
  117. 58 32
      src/MeidoPhotoStudio.Plugin/MyGui.cs
  118. 4 4
      src/MeidoPhotoStudio.Plugin/Patchers/AllProcPropSeqStartPatcher.cs
  119. 4 2
      src/MeidoPhotoStudio.Plugin/Patchers/BgMgrPatcher.cs
  120. 1 1
      src/MeidoPhotoStudio.Plugin/Serialization/ISerializer.cs
  121. 1 1
      src/MeidoPhotoStudio.Plugin/Serialization/ISimpleSerializer.cs
  122. 11 15
      src/MeidoPhotoStudio.Plugin/Serialization/SceneMetadata.cs
  123. 20 13
      src/MeidoPhotoStudio.Plugin/Serialization/Serialization.cs
  124. 6 4
      src/MeidoPhotoStudio.Plugin/Serialization/Serializer.cs
  125. 4 4
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/AttachPointInfoSerializer.cs
  126. 1 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/CameraInfoSerializer.cs
  127. 16 12
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/DragPointLightSerializer.cs
  128. 2 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/BloomEffectSerializer.cs
  129. 2 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/BlurEffectSerializer.cs
  130. 2 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/DepthOfFieldEffectSerializer.cs
  131. 2 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/FogEffectSerializer.cs
  132. 2 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/SepiaToneEffectSerializer.cs
  133. 2 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/VignetteEffectSerializer.cs
  134. 1 1
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/LightPropertySerializer.cs
  135. 16 9
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/CameraManagerSerializer.cs
  136. 7 6
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/EffectManagerSerializer.cs
  137. 14 12
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/EnvironmentManagerSerializer.cs
  138. 15 10
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/LightManagerSerializer.cs
  139. 8 5
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/MeidoManagerSerializer.cs
  140. 6 2
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/MessageWindowManagerSerializer.cs
  141. 35 31
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/PropManagerSerializer.cs
  142. 107 70
      src/MeidoPhotoStudio.Plugin/Serialization/Serializers/MeidoSerializer.cs
  143. 6 4
      src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializer.cs
  144. 8 5
      src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/DragPointPropDTOSerializer.cs
  145. 2 2
      src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/PoseInfoSerializer.cs
  146. 3 3
      src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/PropInfoSerializer.cs
  147. 1 1
      src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/TransformDTOSerializer.cs
  148. 36 36
      src/MeidoPhotoStudio.Plugin/Translation.cs
  149. 165 135
      src/MeidoPhotoStudio.Plugin/Utility.cs
  150. 1 1
      src/MeidoPhotoStudio.Plugin/WindowsLogicalComparer.cs

+ 1 - 1
src/MeidoPhotoStudio.Converter/Converters/IConverter.cs

@@ -1,4 +1,4 @@
-namespace MeidoPhotoStudio.Converter.Converters
+namespace MeidoPhotoStudio.Converter.Converters
 {
     public interface IConverter
     {

+ 11 - 10
src/MeidoPhotoStudio.Converter/Converters/MMConverter.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.IO;
 using System.Linq;
 using ExIni;
@@ -8,17 +8,9 @@ namespace MeidoPhotoStudio.Converter.Converters
 {
     public class MMConverter : IConverter
     {
-        private const string InputDirectoryName = "Input";
         public const string ConverterName = "MultipleMaids";
 
-        public void Convert(string workingDirectory)
-        {
-            var baseDirectory = Path.Combine(workingDirectory, ConverterName);
-            var baseInputDirectory = Path.Combine(baseDirectory, InputDirectoryName);
-            var baseOutputDirectory = Path.Combine(baseDirectory, MPSSceneSerializer.FormatDate(DateTime.Now));
-
-            Convert(baseInputDirectory, baseOutputDirectory);
-        }
+        private const string InputDirectoryName = "Input";
 
         private static void Convert(string workingDirectory, string destination)
         {
@@ -130,5 +122,14 @@ namespace MeidoPhotoStudio.Converter.Converters
 
             return null;
         }
+
+        public void Convert(string workingDirectory)
+        {
+            var baseDirectory = Path.Combine(workingDirectory, ConverterName);
+            var baseInputDirectory = Path.Combine(baseDirectory, InputDirectoryName);
+            var baseOutputDirectory = Path.Combine(baseDirectory, MPSSceneSerializer.FormatDate(DateTime.Now));
+
+            Convert(baseInputDirectory, baseOutputDirectory);
+        }
     }
 }

+ 11 - 10
src/MeidoPhotoStudio.Converter/Converters/MMPngConverter.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.IO;
 using System.Text;
 using MeidoPhotoStudio.Converter.MultipleMaids;
@@ -8,18 +8,10 @@ namespace MeidoPhotoStudio.Converter.Converters
 {
     public class MMPngConverter : IConverter
     {
-        private static readonly byte[] KankyoHeader = Encoding.ASCII.GetBytes("KANKYO");
         private const string InputDirectoryName = "Input";
         public const string ConverterName = "ModifiedMM PNG";
 
-        public void Convert(string workingDirectory)
-        {
-            var baseDirectory = Path.Combine(workingDirectory, ConverterName);
-            var baseInputDirectory = Path.Combine(baseDirectory, InputDirectoryName);
-            var baseOutputDirectory = Path.Combine(baseDirectory, MPSSceneSerializer.FormatDate(DateTime.Now));
-
-            Convert(baseInputDirectory, baseOutputDirectory);
-        }
+        private static readonly byte[] KankyoHeader = Encoding.ASCII.GetBytes("KANKYO");
 
         private static void Convert(string workingDirectory, string destination)
         {
@@ -97,5 +89,14 @@ namespace MeidoPhotoStudio.Converter.Converters
 
             MPSSceneSerializer.SaveToFile(outputFilename, sceneMetadata, convertedData, thumbnailData);
         }
+
+        public void Convert(string workingDirectory)
+        {
+            var baseDirectory = Path.Combine(workingDirectory, ConverterName);
+            var baseInputDirectory = Path.Combine(baseDirectory, InputDirectoryName);
+            var baseOutputDirectory = Path.Combine(baseDirectory, MPSSceneSerializer.FormatDate(DateTime.Now));
+
+            Convert(baseInputDirectory, baseOutputDirectory);
+        }
     }
 }

+ 7 - 4
src/MeidoPhotoStudio.Converter/MPSSceneSerializer.cs

@@ -1,8 +1,8 @@
-using System;
+using System;
 using System.IO;
 using System.Text;
-using MeidoPhotoStudio.Plugin;
 using Ionic.Zlib;
+using MeidoPhotoStudio.Plugin;
 
 namespace MeidoPhotoStudio.Converter
 {
@@ -17,7 +17,9 @@ namespace MeidoPhotoStudio.Converter
             + "w4k1xcQyxs6aaGJHycaabmIJ82M9xMTo2VjP+izrF8NPHwq3SYqeAAAAAElFTkSuQmCC";
 
         private static byte[]? noThumb;
-        public static byte[] NoThumb => noThumb ??= Convert.FromBase64String(NoThumbBase64);
+
+        public static byte[] NoThumb =>
+            noThumb ??= Convert.FromBase64String(NoThumbBase64);
 
         public static void SaveToFile(string filename, SceneMetadata metadata, byte[] rawSceneData, string? thumbnail)
         {
@@ -48,6 +50,7 @@ namespace MeidoPhotoStudio.Converter
             compressionStream.Close();
         }
 
-        public static string FormatDate(DateTime date) => date.ToString("yyyyMMddHHmmss");
+        public static string FormatDate(DateTime date) =>
+            date.ToString("yyyyMMddHHmmss");
     }
 }

+ 13 - 5
src/MeidoPhotoStudio.Converter/MultipleMaids/ConversionUtility.cs

@@ -1,4 +1,4 @@
-using UnityEngine;
+using UnityEngine;
 
 namespace MeidoPhotoStudio.Converter.MultipleMaids
 {
@@ -14,6 +14,7 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
         public static Vector3 ParseVector3(string vector3)
         {
             var data = vector3.Split(',');
+
             return new(float.Parse(data[0]), float.Parse(data[1]), float.Parse(data[2]));
         }
 
@@ -29,10 +30,17 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
 
             var data = euler.Split(',');
 
-            if (data.Length != 3) return false;
-
-            try { result = Quaternion.Euler(float.Parse(data[0]), float.Parse(data[1]), float.Parse(data[2])); }
-            catch { return false; }
+            if (data.Length is not 3)
+                return false;
+
+            try
+            {
+                result = Quaternion.Euler(float.Parse(data[0]), float.Parse(data[1]), float.Parse(data[2]));
+            }
+            catch
+            {
+                return false;
+            }
 
             return true;
         }

+ 4 - 2
src/MeidoPhotoStudio.Converter/MultipleMaids/MMConstants.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using MyRoomCustom;
@@ -8,6 +8,8 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
 {
     public static class MMConstants
     {
+        public static readonly Vector3 DefaultSoftG = new(0f, -3f / 1000f, 0f);
+
         public static readonly string[] FaceKeys =
         {
             "eyeclose", "eyeclose2", "eyeclose3", "eyeclose6", "hitomih", "hitomis", "mayuha",
@@ -27,6 +29,7 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
         };
 
         private static Dictionary<string, PlacementData.Data>? myrAssetNameToData;
+
         public static Dictionary<string, PlacementData.Data> MyrAssetNameToData =>
             myrAssetNameToData ??= PlacementData.GetAllDatas(false)
                 .ToDictionary(
@@ -34,6 +37,5 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
                     data => data,
                     StringComparer.InvariantCultureIgnoreCase
                 );
-        public static readonly Vector3 DefaultSoftG = new(0f, -3f / 1000f, 0f);
     }
 }

+ 1 - 1
src/MeidoPhotoStudio.Converter/MultipleMaids/MMScene.cs

@@ -1,4 +1,4 @@
-namespace MeidoPhotoStudio.Converter.MultipleMaids
+namespace MeidoPhotoStudio.Converter.MultipleMaids
 {
     public class MMScene
     {

+ 18 - 9
src/MeidoPhotoStudio.Converter/MultipleMaids/MMSceneConverter.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -11,6 +11,7 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
     public static class MMSceneConverter
     {
         private const int ClavicleLIndex = 68;
+
         private static readonly int[] BodyRotationIndices =
         {
             71, // Hip
@@ -39,8 +40,10 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
             51, // Foot L
             54, // Foot R
         };
+
         private static readonly int[] BodyRotationIndices64 =
             BodyRotationIndices.Where(rotation => rotation < 64).ToArray();
+
         private static readonly CameraInfo DefaultCameraInfo = new();
         private static readonly LightProperty DefaultLightProperty = new();
 
@@ -204,8 +207,8 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
                 {
                     // toe rotations
                     for (var i = 0; i < 2; i++)
-                    for (var j = 72 + i; j < 90; j += 2)
-                        writer.Write(ConversionUtility.ParseEulerAngle(maidData[j]));
+                        for (var j = 72 + i; j < 90; j += 2)
+                            writer.Write(ConversionUtility.ParseEulerAngle(maidData[j]));
                 }
 
                 var rotationIndices = sixtyFourFlag ? BodyRotationIndices64 : BodyRotationIndices;
@@ -272,7 +275,7 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
                 {
                     var mpnIndex = int.Parse(maidData[65].Split(',')[0]);
 
-                    if (mpnIndex >= 9 && mpnIndex <= 16)
+                    if (mpnIndex is >= 9 and <= 16)
                     {
                         var actualIndex = mpnIndex - 9;
 
@@ -288,11 +291,15 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
                         }
                         else
                         {
-                            if (mpnIndex > 13) actualIndex++;
+                            if (mpnIndex > 13)
+                                actualIndex++;
+
                             var kousokuMenu = MMConstants.MpnAttachProps[actualIndex];
 
-                            if (MMConstants.MpnAttachProps[actualIndex][7] == 'u') kousokuUpperMenu = kousokuMenu;
-                            else kousokuLowerMenu = kousokuMenu;
+                            if (MMConstants.MpnAttachProps[actualIndex][7] == 'u')
+                                kousokuUpperMenu = kousokuMenu;
+                            else
+                                kousokuLowerMenu = kousokuMenu;
                         }
                     }
                 }
@@ -530,7 +537,8 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
 
         private static void ConvertEffect(string[] data, BinaryWriter writer)
         {
-            if (data.Length < 5) return;
+            if (data.Length < 5)
+                return;
 
             writer.Write(EffectManager.header);
             // EffectManagerSerializer version
@@ -792,7 +800,8 @@ namespace MeidoPhotoStudio.Converter.MultipleMaids
                     // hand items are treated as game props (Odogu) in MPS
                     if (asset.StartsWith("handitem", StringComparison.OrdinalIgnoreCase)
                         || asset.StartsWith("kousoku", StringComparison.OrdinalIgnoreCase)
-                    ) propType = PropInfo.PropType.Odogu;
+                    )
+                        propType = PropInfo.PropType.Odogu;
 
                     return new(propType) { Filename = asset };
                 }

+ 7 - 5
src/MeidoPhotoStudio.Converter/Plugin.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 using BepInEx;
 using BepInEx.Logging;
 using MeidoPhotoStudio.Converter.Converters;
@@ -11,15 +11,17 @@ namespace MeidoPhotoStudio.Converter
     [BepInDependency("com.habeebweeb.com3d2.meidophotostudio")]
     public class Plugin : BaseUnityPlugin
     {
-        private const string PluginGuid = "com.habeebweeb.com3d2.meidophotostudio.converter";
         public const string PluginName = "MeidoPhotoStudio Converter";
         public const string PluginVersion = "0.0.1";
 
-        private PluginCore pluginCore;
-        private UI ui;
+        private const string PluginGuid = "com.habeebweeb.com3d2.meidophotostudio.converter";
 
         public static Plugin? Instance { get; private set; }
-        public new ManualLogSource Logger { get; private set; }
+
+        private PluginCore? pluginCore;
+        private UI? ui;
+
+        public new ManualLogSource? Logger { get; private set; }
 
         private void Awake()
         {

+ 2 - 1
src/MeidoPhotoStudio.Converter/PluginCore.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.IO;
 using MeidoPhotoStudio.Converter.Converters;
 
@@ -7,6 +7,7 @@ namespace MeidoPhotoStudio.Converter
     public class PluginCore
     {
         private readonly IConverter[] converters;
+
         public string WorkingDirectory { get; set; }
 
         public PluginCore(string workingDirectory, params IConverter[] converters)

+ 4 - 3
src/MeidoPhotoStudio.Converter/UI.cs

@@ -1,4 +1,4 @@
-using UnityEngine;
+using UnityEngine;
 
 namespace MeidoPhotoStudio.Converter
 {
@@ -6,12 +6,13 @@ namespace MeidoPhotoStudio.Converter
     {
         private const int WindowID = 0xEA4040;
         private const string WindowTitle = Plugin.PluginName + " " + Plugin.PluginVersion;
-        private Rect windowRect;
 
-        private PluginCore core;
+        private readonly PluginCore core;
 
         public bool Visible;
 
+        private Rect windowRect;
+
         public UI(PluginCore pluginCore) =>
             core = pluginCore;
 

+ 1 - 1
src/MeidoPhotoStudio.Converter/Utility/LZMA.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 using SevenZip.Compression.LZMA;
 
 namespace MeidoPhotoStudio.Converter.Utility

+ 1 - 1
src/MeidoPhotoStudio.Converter/Utility/PngUtility.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.IO;
 
 namespace MeidoPhotoStudio.Converter.Utility

+ 3 - 2
src/MeidoPhotoStudio.Plugin/Configuration.cs

@@ -8,8 +8,9 @@ namespace MeidoPhotoStudio.Plugin
 
         static Configuration()
         {
-            string configPath = System.IO.Path.Combine(Constants.configPath, $"{MeidoPhotoStudio.pluginName}.cfg");
-            Config = new ConfigFile(configPath, false);
+            var configPath = System.IO.Path.Combine(Constants.configPath, $"{MeidoPhotoStudio.pluginName}.cfg");
+
+            Config = new(configPath, false);
         }
     }
 }

Fichier diff supprimé car celui-ci est trop grand
+ 400 - 343
src/MeidoPhotoStudio.Plugin/Constants.cs


+ 40 - 20
src/MeidoPhotoStudio.Plugin/DragPoint/CustomGizmo.cs

@@ -6,18 +6,27 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class CustomGizmo : GizmoRender
     {
+        public enum GizmoType { Rotate, Move, Scale }
+        public enum GizmoMode { Local, World, Global }
+
         private static readonly Camera camera = GameMain.Instance.MainCamera.camera;
-        private Transform target;
-        private bool hasAlternateTarget;
-        private Transform positionTransform;
-        private readonly FieldInfo beSelectedType = Utility.GetFieldInfo<GizmoRender>("beSelectedType");
-        private int SelectedType => (int)beSelectedType.GetValue(this);
-        private static readonly FieldInfo is_drag_ = Utility.GetFieldInfo<GizmoRender>("is_drag_");
+        private static new readonly FieldInfo is_drag_ = Utility.GetFieldInfo<GizmoRender>("is_drag_");
+
+        private new readonly FieldInfo beSelectedType = Utility.GetFieldInfo<GizmoRender>("beSelectedType");
+
         public static bool IsDrag
         {
             get => (bool)is_drag_.GetValue(null);
             private set => is_drag_.SetValue(null, value);
         }
+
+        public event EventHandler GizmoDrag;
+        public GizmoMode gizmoMode;
+
+        private GizmoType gizmoType;
+        private Transform target;
+        private bool hasAlternateTarget;
+        private Transform positionTransform;
         private Vector3 positionOld = Vector3.zero;
         private Vector3 deltaPosition = Vector3.zero;
         private Vector3 deltaLocalPosition = Vector3.zero;
@@ -27,14 +36,18 @@ namespace MeidoPhotoStudio.Plugin
         private Vector3 deltaScale = Vector3.zero;
         private Vector3 scaleOld = Vector3.one;
         private GizmoType gizmoTypeOld;
-        private GizmoType gizmoType;
+        private int SelectedType =>
+            (int)beSelectedType.GetValue(this);
+
         public GizmoType CurrentGizmoType
         {
             get => gizmoType;
             set
             {
                 gizmoType = value;
-                if (gizmoTypeOld == gizmoType) return;
+
+                if (gizmoTypeOld == gizmoType)
+                    return;
 
                 gizmoTypeOld = gizmoType;
                 eAxis = gizmoType == GizmoType.Move;
@@ -42,20 +55,21 @@ namespace MeidoPhotoStudio.Plugin
                 eRotate = gizmoType == GizmoType.Rotate;
             }
         }
-        public bool IsGizmoDrag => GizmoVisible && IsDrag && SelectedType != 0;
+
+        public bool IsGizmoDrag =>
+            GizmoVisible && IsDrag && SelectedType != 0;
+
         public bool GizmoVisible
         {
             get => Visible;
             set
             {
-                if (value && IsDrag) IsDrag = false;
+                if (value && IsDrag)
+                    IsDrag = false;
+
                 Visible = value;
             }
         }
-        public GizmoMode gizmoMode;
-        public event EventHandler GizmoDrag;
-        public enum GizmoType { Rotate, Move, Scale }
-        public enum GizmoMode { Local, World, Global }
 
         public static CustomGizmo Make(Transform target, float scale = 0.25f, GizmoMode mode = GizmoMode.Local)
         {
@@ -84,7 +98,8 @@ namespace MeidoPhotoStudio.Plugin
 
             base.Update();
 
-            if (IsGizmoDrag) SetTargetTransform();
+            if (IsGizmoDrag)
+                SetTargetTransform();
 
             SetTransform();
 
@@ -93,7 +108,8 @@ namespace MeidoPhotoStudio.Plugin
 
         private void BeginUpdate()
         {
-            Quaternion rotation = transform.rotation;
+            var rotation = transform.rotation;
+
             deltaPosition = transform.position - positionOld;
             deltaRotation = rotation * Quaternion.Inverse(rotationOld);
             deltaLocalPosition = transform.InverseTransformVector(deltaPosition);
@@ -103,7 +119,8 @@ namespace MeidoPhotoStudio.Plugin
 
         private void EndUpdate()
         {
-            Transform transform = this.transform;
+            var transform = this.transform;
+
             positionOld = transform.position;
             rotationOld = transform.rotation;
             scaleOld = transform.localScale;
@@ -132,12 +149,14 @@ namespace MeidoPhotoStudio.Plugin
                 default: throw new ArgumentOutOfRangeException();
             }
 
-            if (dragged) OnGizmoDrag();
+            if (dragged)
+                OnGizmoDrag();
         }
 
         private void SetTransform()
         {
-            Transform transform = this.transform;
+            var transform = this.transform;
+
             transform.position = (hasAlternateTarget ? positionTransform : target).position;
             transform.localScale = Vector3.one;
             transform.rotation = gizmoMode switch
@@ -149,6 +168,7 @@ namespace MeidoPhotoStudio.Plugin
             };
         }
 
-        private void OnGizmoDrag() => GizmoDrag?.Invoke(this, EventArgs.Empty);
+        private void OnGizmoDrag() =>
+            GizmoDrag?.Invoke(this, EventArgs.Empty);
     }
 }

+ 134 - 97
src/MeidoPhotoStudio.Plugin/DragPoint/DragPoint.cs

@@ -1,46 +1,55 @@
 using System;
 using UnityEngine;
 
+using static MeidoPhotoStudio.Plugin.CustomGizmo;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static CustomGizmo;
     public abstract class DragPoint : MonoBehaviour
     {
-        private static readonly int layer = (int) Mathf.Log(LayerMask.GetMask("AbsolutFront"), 2);
+        public enum DragType
+        {
+            None, Ignore, Select, Delete, MoveXZ, MoveY, RotLocalXZ, RotY, RotLocalY, Scale
+        }
+
         public const float defaultAlpha = 0.75f;
-        private static GameObject dragPointParent;
+
         private const float doubleClickSensitivity = 0.3f;
+
+        public static Material dragPointMaterial = new(Shader.Find("CM3D2/Trans_AbsoluteFront"));
+        public static readonly Color defaultColour = new(0f, 0f, 0f, 0.4f);
+
+        protected static Camera camera = GameMain.Instance.MainCamera.camera;
+
+        // TODO: Use this value or just throw it away.
+        private static readonly int layer = (int)Mathf.Log(LayerMask.GetMask("AbsolutFront"), 2);
+        private static GameObject dragPointParent;
+
         private Func<Vector3> position;
         private Func<Vector3> rotation;
         private Collider collider;
         private Renderer renderer;
         private bool reinitializeDrag;
-        protected bool Transforming => CurrentDragType >= DragType.MoveXZ;
-        protected bool Special => CurrentDragType == DragType.Select || CurrentDragType == DragType.Delete;
-        protected bool Moving => CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.MoveY;
-        protected bool Rotating => CurrentDragType >= DragType.RotLocalXZ && CurrentDragType <= DragType.RotLocalY;
-        protected bool Scaling => CurrentDragType == DragType.Scale;
-        protected bool Selecting => CurrentDragType == DragType.Select;
-        protected bool Deleting => CurrentDragType == DragType.Delete;
         private Vector3 startMousePosition;
-        protected static Camera camera = GameMain.Instance.MainCamera.camera;
-        public enum DragType
-        {
-            None, Ignore, Select, Delete,
-            MoveXZ, MoveY,
-            RotLocalXZ, RotY, RotLocalY,
-            Scale
-        }
-        public Transform MyObject { get; protected set; }
-        public GameObject MyGameObject => MyObject.gameObject;
         private float startDoubleClick;
         private Vector3 screenPoint;
         private Vector3 startOffset;
         private Vector3 newOffset;
-        public static Material dragPointMaterial = new Material(Shader.Find("CM3D2/Trans_AbsoluteFront"));
-        public static readonly Color defaultColour = new Color(0f, 0f, 0f, 0.4f);
-        public Vector3 OriginalScale { get; private set; }
         private Vector3 baseScale;
+        private DragType oldDragType;
+        private DragType currentDragType;
+        private bool dragPointEnabled = true;
+        private float dragPointScale = 1f;
+        private bool gizmoEnabled = true;
+
+        public GameObject MyGameObject =>
+            MyObject.gameObject;
+
+        public Vector3 OriginalScale { get; private set; }
+        public Transform MyObject { get; protected set; }
+        public GameObject GizmoGo { get; protected set; }
+        public CustomGizmo Gizmo { get; protected set; }
+
         public Vector3 BaseScale
         {
             get => baseScale;
@@ -50,7 +59,7 @@ namespace MeidoPhotoStudio.Plugin
                 transform.localScale = BaseScale * DragPointScale;
             }
         }
-        private float dragPointScale = 1f;
+
         public float DragPointScale
         {
             get => dragPointScale;
@@ -60,47 +69,69 @@ namespace MeidoPhotoStudio.Plugin
                 transform.localScale = BaseScale * dragPointScale;
             }
         }
-        public GameObject GizmoGo { get; protected set; }
-        public CustomGizmo Gizmo { get; protected set; }
-        private DragType oldDragType;
-        private DragType currentDragType;
-        protected DragType CurrentDragType
-        {
-            get => currentDragType;
-            set
-            {
-                if (value != oldDragType)
-                {
-                    currentDragType = value;
-                    reinitializeDrag = true;
-                    oldDragType = currentDragType;
-                    ApplyDragType();
-                }
-            }
-        }
-        private bool dragPointEnabled = true;
+
         public bool DragPointEnabled
         {
             get => dragPointEnabled;
             set
             {
-                if (dragPointEnabled == value) return;
+                if (dragPointEnabled == value)
+                    return;
+
                 dragPointEnabled = value;
                 ApplyDragType();
             }
         }
-        private bool gizmoEnabled = true;
+
         public bool GizmoEnabled
         {
             get => GizmoGo != null && gizmoEnabled;
             set
             {
-                if (GizmoGo == null || (gizmoEnabled == value)) return;
+                if (GizmoGo == null || gizmoEnabled == value)
+                    return;
+
                 gizmoEnabled = value;
                 ApplyDragType();
             }
         }
 
+        protected DragType CurrentDragType
+        {
+            get => currentDragType;
+            set
+            {
+                if (value != oldDragType)
+                {
+                    currentDragType = value;
+                    reinitializeDrag = true;
+                    oldDragType = currentDragType;
+                    ApplyDragType();
+                }
+            }
+        }
+
+        protected bool Transforming =>
+            CurrentDragType >= DragType.MoveXZ;
+
+        protected bool Special =>
+            CurrentDragType is DragType.Select or DragType.Delete;
+
+        protected bool Moving =>
+            CurrentDragType is DragType.MoveXZ or DragType.MoveY;
+
+        protected bool Rotating =>
+            CurrentDragType is >= DragType.RotLocalXZ and <= DragType.RotLocalY;
+
+        protected bool Scaling =>
+            CurrentDragType is DragType.Scale;
+
+        protected bool Selecting =>
+            CurrentDragType is DragType.Select;
+
+        protected bool Deleting =>
+            CurrentDragType is DragType.Delete;
+
         static DragPoint()
         {
             InputManager.Register(MpsKey.DragSelect, KeyCode.A, "Select handle mode");
@@ -111,33 +142,29 @@ namespace MeidoPhotoStudio.Plugin
             InputManager.Register(MpsKey.DragFinger, KeyCode.Space, "Show finger handles");
         }
 
-        private void Awake()
-        {
-            BaseScale = OriginalScale = transform.localScale;
-            collider = GetComponent<Collider>();
-            renderer = GetComponent<Renderer>();
-            ApplyDragType();
-        }
-
-        private static GameObject DragPointParent()
-        {
-            return dragPointParent ? dragPointParent : (dragPointParent = new GameObject("[MPS DragPoint Parent]"));
-        }
-
         public static T Make<T>(PrimitiveType primitiveType, Vector3 scale) where T : DragPoint
         {
-            GameObject dragPointGo = GameObject.CreatePrimitive(primitiveType);
+            var dragPointGo = GameObject.CreatePrimitive(primitiveType);
+
             dragPointGo.transform.SetParent(DragPointParent().transform, false);
             dragPointGo.transform.localScale = scale;
             dragPointGo.layer = 8;
 
-            T dragPoint = dragPointGo.AddComponent<T>();
+            var dragPoint = dragPointGo.AddComponent<T>();
+
             dragPoint.renderer.material = dragPointMaterial;
             dragPoint.renderer.material.color = defaultColour;
 
             return dragPoint;
         }
 
+        private static GameObject DragPointParent() =>
+            dragPointParent ? dragPointParent : (dragPointParent = new("[MPS DragPoint Parent]"));
+
+        protected abstract void UpdateDragType();
+
+        protected abstract void Drag();
+
         public virtual void Initialize(Func<Vector3> position, Func<Vector3> rotation)
         {
             this.position = position;
@@ -158,37 +185,16 @@ namespace MeidoPhotoStudio.Plugin
             ApplyDragType();
         }
 
-        protected virtual void ApplyDragType() { }
-
         public void ApplyProperties(bool active = false, bool visible = false, bool gizmo = false)
         {
             collider.enabled = active;
             renderer.enabled = visible;
-            if (Gizmo) Gizmo.GizmoVisible = gizmo;
-        }
-
-        protected void ApplyColour(Color colour) => renderer.material.color = colour;
-
-        protected void ApplyColour(float r, float g, float b, float a = defaultAlpha)
-        {
-            ApplyColour(new Color(r, g, b, a));
-        }
-
-        protected Vector3 MouseDelta() => Utility.MousePosition - startMousePosition;
 
-        protected bool OtherDragType()
-        {
-            return InputManager.GetKey(MpsKey.DragSelect) || InputManager.GetKey(MpsKey.DragDelete)
-                || InputManager.GetKey(MpsKey.DragMove) || InputManager.GetKey(MpsKey.DragRotate)
-                || InputManager.GetKey(MpsKey.DragScale) || InputManager.GetKey(MpsKey.DragFinger);
+            if (Gizmo)
+                Gizmo.GizmoVisible = gizmo;
         }
 
-        protected Vector3 CursorPosition()
-        {
-            Vector3 mousePosition = Utility.MousePosition;
-            return camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, screenPoint.z))
-                + startOffset - newOffset;
-        }
+        protected virtual void ApplyDragType() { }
 
         protected virtual void Update()
         {
@@ -203,7 +209,7 @@ namespace MeidoPhotoStudio.Plugin
             screenPoint = camera.WorldToScreenPoint(transform.position);
             startMousePosition = Utility.MousePosition;
             startOffset = transform.position - camera.ScreenToWorldPoint(
-                new Vector3(startMousePosition.x, startMousePosition.y, screenPoint.z)
+                new(startMousePosition.x, startMousePosition.y, screenPoint.z)
             );
             newOffset = transform.position - MyObject.position;
         }
@@ -216,27 +222,56 @@ namespace MeidoPhotoStudio.Plugin
                 OnMouseDown();
             }
 
-            if (collider.enabled && startMousePosition != Utility.MousePosition) Drag();
+            if (collider.enabled && startMousePosition != Utility.MousePosition)
+                Drag();
         }
 
-        protected abstract void UpdateDragType();
-        protected abstract void Drag();
-
         protected virtual void OnMouseUp()
         {
-            if ((Time.time - startDoubleClick) < doubleClickSensitivity)
+            if (Time.time - startDoubleClick < doubleClickSensitivity)
             {
                 startDoubleClick = -1f;
                 OnDoubleClick();
             }
             else
-            {
                 startDoubleClick = Time.time;
-            }
         }
 
         protected virtual void OnDoubleClick() { }
 
+        protected virtual void OnDestroy() =>
+            Destroy(GizmoGo);
+
+        protected void ApplyColour(Color colour) =>
+            renderer.material.color = colour;
+
+        protected void ApplyColour(float r, float g, float b, float a = defaultAlpha) =>
+            ApplyColour(new(r, g, b, a));
+
+        protected Vector3 MouseDelta() =>
+            Utility.MousePosition - startMousePosition;
+
+        protected bool OtherDragType() =>
+            InputManager.GetKey(MpsKey.DragSelect) || InputManager.GetKey(MpsKey.DragDelete)
+            || InputManager.GetKey(MpsKey.DragMove) || InputManager.GetKey(MpsKey.DragRotate)
+            || InputManager.GetKey(MpsKey.DragScale) || InputManager.GetKey(MpsKey.DragFinger);
+
+        protected Vector3 CursorPosition()
+        {
+            var mousePosition = Utility.MousePosition;
+
+            return camera.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, screenPoint.z))
+                + startOffset - newOffset;
+        }
+
+        private void Awake()
+        {
+            BaseScale = OriginalScale = transform.localScale;
+            collider = GetComponent<Collider>();
+            renderer = GetComponent<Renderer>();
+            ApplyDragType();
+        }
+
         private void OnEnable()
         {
             if (position != null)
@@ -244,15 +279,17 @@ namespace MeidoPhotoStudio.Plugin
                 transform.position = position();
                 transform.eulerAngles = rotation();
             }
-            if (GizmoGo) GizmoGo.SetActive(true);
+
+            if (GizmoGo)
+                GizmoGo.SetActive(true);
+
             ApplyDragType();
         }
 
         private void OnDisable()
         {
-            if (GizmoGo) GizmoGo.SetActive(false);
+            if (GizmoGo)
+                GizmoGo.SetActive(false);
         }
-
-        protected virtual void OnDestroy() => Destroy(GizmoGo);
     }
 }

+ 98 - 66
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGeneral.cs

@@ -1,92 +1,83 @@
 using System;
 using UnityEngine;
 
+using static MeidoPhotoStudio.Plugin.CustomGizmo;
+
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static CustomGizmo;
-    using Input = InputManager;
-
     public abstract class DragPointGeneral : DragPoint
     {
         public const float smallCube = 0.5f;
+
+        public static readonly Color moveColour = new(0.2f, 0.5f, 0.95f, defaultAlpha);
+        public static readonly Color rotateColour = new(0.2f, 0.75f, 0.3f, defaultAlpha);
+        public static readonly Color scaleColour = new(0.8f, 0.7f, 0.3f, defaultAlpha);
+        public static readonly Color selectColour = new(0.9f, 0.5f, 1f, defaultAlpha);
+        public static readonly Color deleteColour = new(1f, 0.1f, 0.1f, defaultAlpha);
+
+        public event EventHandler Move;
+        public event EventHandler Rotate;
+        public event EventHandler Scale;
+        public event EventHandler EndScale;
+        public event EventHandler Delete;
+        public event EventHandler Select;
+
         private float currentScale;
         private bool scaling;
         private Quaternion currentRotation;
+
         public Quaternion DefaultRotation { get; set; } = Quaternion.identity;
         public Vector3 DefaultPosition { get; set; } = Vector3.zero;
         public Vector3 DefaultScale { get; set; } = Vector3.one;
         public float ScaleFactor { get; set; } = 1f;
         public bool ConstantScale { get; set; }
-        public static readonly Color moveColour = new Color(0.2f, 0.5f, 0.95f, defaultAlpha);
-        public static readonly Color rotateColour = new Color(0.2f, 0.75f, 0.3f, defaultAlpha);
-        public static readonly Color scaleColour = new Color(0.8f, 0.7f, 0.3f, defaultAlpha);
-        public static readonly Color selectColour = new Color(0.9f, 0.5f, 1f, defaultAlpha);
-        public static readonly Color deleteColour = new Color(1f, 0.1f, 0.1f, defaultAlpha);
-        public event EventHandler Move;
-        public event EventHandler Rotate;
-        public event EventHandler Scale;
-        public event EventHandler EndScale;
-        public event EventHandler Delete;
-        public event EventHandler Select;
 
         public override void AddGizmo(float scale = 0.35f, GizmoMode mode = GizmoMode.Local)
         {
             base.AddGizmo(scale, mode);
+
             Gizmo.GizmoDrag += (s, a) =>
             {
-                if (Gizmo.CurrentGizmoType == GizmoType.Rotate) OnRotate();
+                if (Gizmo.CurrentGizmoType is GizmoType.Rotate)
+                    OnRotate();
             };
         }
 
-        protected virtual void ApplyColours()
-        {
-            Color colour = moveColour;
-            if (Rotating) colour = rotateColour;
-            else if (Scaling) colour = scaleColour;
-            else if (Selecting) colour = selectColour;
-            else if (Deleting) colour = deleteColour;
-            ApplyColour(colour);
-        }
-
         protected override void Update()
         {
             base.Update();
 
             if (ConstantScale)
             {
-                float distance = Vector3.Distance(camera.transform.position, transform.position);
+                var distance = Vector3.Distance(camera.transform.position, transform.position);
+
                 transform.localScale = Vector3.one * (0.4f * BaseScale.x * DragPointScale * distance);
             }
         }
 
         protected override void UpdateDragType()
         {
-            bool shift = Input.Shift;
+            var shift = Input.Shift;
+
             if (Input.GetKey(MpsKey.DragSelect))
-            {
                 CurrentDragType = DragType.Select;
-            }
             else if (Input.GetKey(MpsKey.DragDelete))
-            {
                 CurrentDragType = DragType.Delete;
-            }
             else if (Input.GetKey(MpsKey.DragMove))
             {
-                if (Input.Control) CurrentDragType = DragType.MoveY;
-                else CurrentDragType = shift ? DragType.RotY : DragType.MoveXZ;
+                if (Input.Control)
+                    CurrentDragType = DragType.MoveY;
+                else
+                    CurrentDragType = shift ? DragType.RotY : DragType.MoveXZ;
             }
             else if (Input.GetKey(MpsKey.DragRotate))
-            {
                 CurrentDragType = shift ? DragType.RotLocalY : DragType.RotLocalXZ;
-            }
             else if (Input.GetKey(MpsKey.DragScale))
-            {
                 CurrentDragType = DragType.Scale;
-            }
             else
-            {
                 CurrentDragType = DragType.None;
-            }
         }
 
         protected override void OnMouseDown()
@@ -94,12 +85,14 @@ namespace MeidoPhotoStudio.Plugin
             if (Deleting)
             {
                 OnDelete();
+
                 return;
             }
 
             if (Selecting)
             {
                 OnSelect();
+
                 return;
             }
 
@@ -131,13 +124,10 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        protected virtual void ResetPosition() => MyObject.position = DefaultPosition;
-
-        protected virtual void ResetRotation() => MyObject.rotation = DefaultRotation;
-
         protected override void OnMouseUp()
         {
             base.OnMouseUp();
+
             if (scaling)
             {
                 scaling = false;
@@ -148,37 +138,40 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void Drag()
         {
-            if (CurrentDragType == DragType.Select || CurrentDragType == DragType.Delete) return;
+            if (CurrentDragType is DragType.Select or DragType.Delete)
+                return;
 
-            Vector3 cursorPosition = CursorPosition();
-            Vector3 mouseDelta = MouseDelta();
+            var cursorPosition = CursorPosition();
+            var mouseDelta = MouseDelta();
 
-            if (CurrentDragType == DragType.MoveXZ)
+            if (CurrentDragType is DragType.MoveXZ)
             {
-                MyObject.position = new Vector3(cursorPosition.x, MyObject.position.y, cursorPosition.z);
+                MyObject.position = new(cursorPosition.x, MyObject.position.y, cursorPosition.z);
                 OnMove();
             }
 
-            if (CurrentDragType == DragType.MoveY)
+            if (CurrentDragType is DragType.MoveY)
             {
-                MyObject.position = new Vector3(
+                MyObject.position = new(
                     MyObject.position.x, cursorPosition.y, MyObject.position.z
                 );
                 OnMove();
             }
 
-            if (CurrentDragType == DragType.RotY)
+            if (CurrentDragType is DragType.RotY)
             {
                 MyObject.rotation = currentRotation;
                 MyObject.Rotate(Vector3.up, -mouseDelta.x / 3f, Space.World);
                 OnRotate();
             }
 
-            if (CurrentDragType == DragType.RotLocalXZ)
+            if (CurrentDragType is DragType.RotLocalXZ)
             {
                 MyObject.rotation = currentRotation;
-                Vector3 forward = camera.transform.forward;
-                Vector3 right = camera.transform.right;
+
+                var forward = camera.transform.forward;
+                var right = camera.transform.right;
+
                 forward.y = 0f;
                 right.y = 0f;
                 MyObject.Rotate(forward, -mouseDelta.x / 6f, Space.World);
@@ -186,29 +179,68 @@ namespace MeidoPhotoStudio.Plugin
                 OnRotate();
             }
 
-            if (CurrentDragType == DragType.RotLocalY)
+            if (CurrentDragType is DragType.RotLocalY)
             {
                 MyObject.rotation = currentRotation;
                 MyObject.Rotate(Vector3.up * -mouseDelta.x / 2.2f);
                 OnRotate();
             }
 
-            if (CurrentDragType == DragType.Scale)
+            if (CurrentDragType is DragType.Scale)
             {
                 scaling = true;
-                float scale = currentScale + (mouseDelta.y / 200f * ScaleFactor);
-                if (scale < 0f) scale = 0f;
-                MyObject.localScale = new Vector3(scale, scale, scale);
+
+                var scale = currentScale + mouseDelta.y / 200f * ScaleFactor;
+
+                if (scale < 0f)
+                    scale = 0f;
+
+                MyObject.localScale = new(scale, scale, scale);
                 OnScale();
             }
         }
 
-        protected virtual void OnEndScale() => OnEvent(EndScale);
-        protected virtual void OnScale() => OnEvent(Scale);
-        protected virtual void OnMove() => OnEvent(Move);
-        protected virtual void OnRotate() => OnEvent(Rotate);
-        protected virtual void OnSelect() => OnEvent(Select);
-        protected virtual void OnDelete() => OnEvent(Delete);
-        private void OnEvent(EventHandler handler) => handler?.Invoke(this, EventArgs.Empty);
+        protected virtual void ApplyColours()
+        {
+            var colour = moveColour;
+
+            if (Rotating)
+                colour = rotateColour;
+            else if (Scaling)
+                colour = scaleColour;
+            else if (Selecting)
+                colour = selectColour;
+            else if (Deleting)
+                colour = deleteColour;
+
+            ApplyColour(colour);
+        }
+
+        protected virtual void ResetPosition() =>
+            MyObject.position = DefaultPosition;
+
+        protected virtual void ResetRotation() =>
+            MyObject.rotation = DefaultRotation;
+
+        protected virtual void OnEndScale() =>
+            OnEvent(EndScale);
+
+        protected virtual void OnScale() =>
+            OnEvent(Scale);
+
+        protected virtual void OnMove() =>
+            OnEvent(Move);
+
+        protected virtual void OnRotate() =>
+            OnEvent(Rotate);
+
+        protected virtual void OnSelect() =>
+            OnEvent(Select);
+
+        protected virtual void OnDelete() =>
+            OnEvent(Delete);
+
+        private void OnEvent(EventHandler handler) =>
+            handler?.Invoke(this, EventArgs.Empty);
     }
 }

+ 38 - 17
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointGravity.cs

@@ -1,44 +1,57 @@
 using UnityEngine;
 
+using static TBody;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static TBody;
     public class DragPointGravity : DragPointGeneral
     {
         private static readonly SlotID[] skirtSlots = { SlotID.skirt, SlotID.onepiece, SlotID.mizugi, SlotID.panz };
         private static readonly SlotID[] hairSlots = { SlotID.hairF, SlotID.hairR, SlotID.hairS, SlotID.hairT };
+
         public GravityTransformControl Control { get; private set; }
-        public bool Valid => Control.isValid;
-        public bool Active => Valid && gameObject.activeSelf;
+
+        public bool Valid =>
+            Control.isValid;
+
+        public bool Active =>
+            Valid && gameObject.activeSelf;
 
         public static GravityTransformControl MakeGravityControl(Maid maid, bool skirt = false)
         {
-            string category = skirt ? "skirt" : "hair";
+            var category = skirt ? "skirt" : "hair";
+
+            var bone = maid.body0.GetBone("Bip01");
+            var gravityGoName = $"GravityDatas_{maid.status.guid}_{category}";
+            var gravityTransform = maid.gameObject.transform.Find(gravityGoName);
 
-            Transform bone = maid.body0.GetBone("Bip01");
-            string gravityGoName = $"GravityDatas_{maid.status.guid}_{category}";
-            Transform gravityTransform = maid.gameObject.transform.Find(gravityGoName);
             if (gravityTransform == null)
             {
-                GameObject go = new GameObject(gravityGoName);
+                var go = new GameObject(gravityGoName);
+
                 go.transform.SetParent(bone, false);
                 go.transform.SetParent(maid.transform, true);
                 go.transform.localScale = Vector3.one;
                 go.transform.rotation = Quaternion.identity;
-                GameObject go2 = new GameObject(gravityGoName);
+
+                var go2 = new GameObject(gravityGoName);
+
                 go2.transform.SetParent(go.transform, false);
                 gravityTransform = go2.transform;
             }
             else
             {
                 gravityTransform = gravityTransform.GetChild(0);
-                GravityTransformControl control = gravityTransform.GetComponent<GravityTransformControl>();
-                if (control != null) GameObject.Destroy(control);
+
+                var control = gravityTransform.GetComponent<GravityTransformControl>();
+
+                if (control != null)
+                    Destroy(control);
             }
 
-            GravityTransformControl gravityControl = gravityTransform.gameObject.AddComponent<GravityTransformControl>();
+            var gravityControl = gravityTransform.gameObject.AddComponent<GravityTransformControl>();
 
-            SlotID[] slots = skirt ? skirtSlots : hairSlots;
+            var slots = skirt ? skirtSlots : hairSlots;
 
             gravityControl.SetTargetSlods(slots);
             gravityControl.forceRate = 0.1f;
@@ -49,11 +62,13 @@ namespace MeidoPhotoStudio.Plugin
         public override void Set(Transform myObject)
         {
             base.Set(myObject);
+
             Control = myObject.GetComponent<GravityTransformControl>();
             gameObject.SetActive(false);
         }
 
-        protected override void ResetPosition() => Control.transform.localPosition = DefaultPosition;
+        protected override void ResetPosition() =>
+            Control.transform.localPosition = DefaultPosition;
 
         protected override void ApplyDragType()
         {
@@ -68,18 +83,24 @@ namespace MeidoPhotoStudio.Plugin
                 Control.transform.localPosition = Vector3.zero;
                 Control.Update();
             }
-            GameObject.Destroy(Control.transform.parent.gameObject);
+
+            Destroy(Control.transform.parent.gameObject);
+
             base.OnDestroy();
         }
 
-        private void OnDisable() => Control.isEnabled = false;
+        private void OnDisable() =>
+            Control.isEnabled = false;
 
         private void OnEnable()
         {
             if (Control)
             {
+                // TODO: WTF?
                 Control.isEnabled = true;
-                if (!Control.isEnabled) gameObject.SetActive(false);
+
+                if (!Control.isEnabled)
+                    gameObject.SetActive(false);
             }
         }
     }

+ 121 - 82
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointLight.cs

@@ -4,29 +4,31 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class DragPointLight : DragPointGeneral
     {
-        public static EnvironmentManager EnvironmentManager { private get; set; }
-        private Light light;
-        public enum MPSLightType
-        {
-            Normal, Spot, Point, Disabled
-        }
+        public enum MPSLightType { Normal, Spot, Point, Disabled }
         public enum LightProp
         {
             LightRotX, LightRotY, Intensity, ShadowStrength, SpotAngle, Range, Red, Green, Blue
         }
 
-        public bool IsActiveLight { get; set; }
-        public string Name { get; private set; } = string.Empty;
-        public bool IsMain { get; set; }
-        public MPSLightType SelectedLightType { get; private set; }
-        public LightProperty CurrentLightProperty => LightProperties[(int)SelectedLightType];
+        public static EnvironmentManager EnvironmentManager { private get; set; }
+
         private readonly LightProperty[] LightProperties = new LightProperty[]
         {
-            new LightProperty(),
-            new LightProperty(),
-            new LightProperty()
+            new(), new(), new()
         };
+
+        private Light light;
         private bool isDisabled;
+        private bool isColourMode;
+
+        public bool IsActiveLight { get; set; }
+        public string Name { get; private set; } = string.Empty;
+        public bool IsMain { get; set; }
+        public MPSLightType SelectedLightType { get; private set; }
+
+        public LightProperty CurrentLightProperty =>
+            LightProperties[(int)SelectedLightType];
+
         public bool IsDisabled
         {
             get => isDisabled;
@@ -36,13 +38,15 @@ namespace MeidoPhotoStudio.Plugin
                 light.gameObject.SetActive(!isDisabled);
             }
         }
-        private bool isColourMode;
+
         public bool IsColourMode
         {
-            get => IsMain && isColourMode && SelectedLightType == MPSLightType.Normal;
+            get => IsMain && isColourMode && SelectedLightType is MPSLightType.Normal;
             set
             {
-                if (!IsMain) return;
+                if (!IsMain)
+                    return;
+
                 light.color = value ? Color.white : LightColour;
                 camera.backgroundColor = value ? LightColour : Color.black;
                 isColourMode = value;
@@ -50,21 +54,25 @@ namespace MeidoPhotoStudio.Plugin
                 EnvironmentManager.BGVisible = !IsColourMode;
             }
         }
+
         public Quaternion Rotation
         {
             get => CurrentLightProperty.Rotation;
             set => light.transform.rotation = CurrentLightProperty.Rotation = value;
         }
+
         public float Intensity
         {
             get => CurrentLightProperty.Intensity;
             set => light.intensity = CurrentLightProperty.Intensity = value;
         }
+
         public float Range
         {
             get => CurrentLightProperty.Range;
             set => light.range = CurrentLightProperty.Range = value;
         }
+
         public float SpotAngle
         {
             get => CurrentLightProperty.SpotAngle;
@@ -74,46 +82,57 @@ namespace MeidoPhotoStudio.Plugin
                 light.transform.localScale = Vector3.one * value;
             }
         }
+
         public float ShadowStrength
         {
             get => CurrentLightProperty.ShadowStrength;
             set => light.shadowStrength = CurrentLightProperty.ShadowStrength = value;
         }
+
         public float LightColorRed
         {
             get => IsColourMode ? camera.backgroundColor.r : CurrentLightProperty.LightColour.r;
             set
             {
-                Color color = IsColourMode ? camera.backgroundColor : light.color;
-                LightColour = new Color(value, color.g, color.b);
+                var color = IsColourMode ? camera.backgroundColor : light.color;
+
+                LightColour = new(value, color.g, color.b);
             }
         }
+
         public float LightColorGreen
         {
             get => IsColourMode ? camera.backgroundColor.g : CurrentLightProperty.LightColour.r;
             set
             {
-                Color color = IsColourMode ? camera.backgroundColor : light.color;
-                LightColour = new Color(color.r, value, color.b);
+                var color = IsColourMode ? camera.backgroundColor : light.color;
+
+                LightColour = new(color.r, value, color.b);
             }
         }
+
         public float LightColorBlue
         {
             get => IsColourMode ? camera.backgroundColor.b : CurrentLightProperty.LightColour.r;
             set
             {
-                Color color = IsColourMode ? camera.backgroundColor : light.color;
-                LightColour = new Color(color.r, color.g, value);
+                var color = IsColourMode ? camera.backgroundColor : light.color;
+
+                LightColour = new(color.r, color.g, value);
             }
         }
+
         public Color LightColour
         {
             get => IsColourMode ? camera.backgroundColor : CurrentLightProperty.LightColour;
             set
             {
-                Color colour = CurrentLightProperty.LightColour = value;
-                if (IsColourMode) camera.backgroundColor = colour;
-                else light.color = colour;
+                var colour = CurrentLightProperty.LightColour = value;
+
+                if (IsColourMode)
+                    camera.backgroundColor = colour;
+                else
+                    light.color = colour;
             }
         }
 
@@ -125,68 +144,26 @@ namespace MeidoPhotoStudio.Plugin
             light.spotAngle = prop.SpotAngle;
             light.shadowStrength = prop.ShadowStrength;
             light.color = prop.LightColour;
-            if (light.type == LightType.Spot) light.transform.localScale = Vector3.one * prop.SpotAngle;
-            else if (light.type == LightType.Point) light.transform.localScale = Vector3.one * prop.Range;
-        }
-
-        public override void Set(Transform myObject)
-        {
-            base.Set(myObject);
-            light = myObject.gameObject.GetOrAddComponent<Light>();
-
-            light.transform.position = LightProperty.DefaultPosition;
-            light.transform.rotation = LightProperty.DefaultRotation;
-
-            SetLightType(MPSLightType.Normal);
-            ScaleFactor = 50f;
-            DefaultRotation = LightProperty.DefaultRotation;
-            DefaultPosition = LightProperty.DefaultPosition;
-        }
-
-        protected override void OnDestroy()
-        {
-            if (!IsMain) Destroy(light.gameObject);
-            base.OnDestroy();
-        }
-
-        protected override void OnRotate()
-        {
-            CurrentLightProperty.Rotation = light.transform.rotation;
-            base.OnRotate();
-        }
 
-        protected override void OnScale()
-        {
-            float value = light.transform.localScale.x;
-            if (SelectedLightType == MPSLightType.Point) Range = value;
-            else if (SelectedLightType == MPSLightType.Spot) SpotAngle = value;
-            base.OnScale();
-        }
-
-        protected override void ApplyDragType()
-        {
-            if (Selecting || Moving) ApplyProperties(true, true, false);
-            else if (SelectedLightType != MPSLightType.Point && Rotating) ApplyProperties(true, true, false);
-            else if (SelectedLightType != MPSLightType.Normal && Scaling) ApplyProperties(true, true, false);
-            else if (!IsMain && Deleting) ApplyProperties(true, true, false);
-            else ApplyProperties(false, false, false);
-
-            ApplyColours();
+            if (light.type is LightType.Spot)
+                light.transform.localScale = Vector3.one * prop.SpotAngle;
+            else if (light.type is LightType.Point)
+                light.transform.localScale = Vector3.one * prop.Range;
         }
 
         public void SetLightType(MPSLightType type)
         {
-            LightType lightType = LightType.Directional;
+            var lightType = LightType.Directional;
+            var name = "normal";
 
-            string name = "normal";
             SelectedLightType = type;
 
-            if (type == MPSLightType.Spot)
+            if (type is MPSLightType.Spot)
             {
                 lightType = LightType.Spot;
                 name = "spot";
             }
-            else if (type == MPSLightType.Point)
+            else if (type is MPSLightType.Point)
             {
                 lightType = LightType.Point;
                 name = "point";
@@ -196,15 +173,14 @@ namespace MeidoPhotoStudio.Plugin
             Name = IsMain ? "main" : name;
 
             if (IsMain)
-            {
-                EnvironmentManager.BGVisible = !(IsColourMode && SelectedLightType == MPSLightType.Normal);
-            }
+                EnvironmentManager.BGVisible = !(IsColourMode && SelectedLightType is MPSLightType.Normal);
 
             SetProps();
             ApplyDragType();
         }
 
-        public void SetRotation(float x, float y) => Rotation = Quaternion.Euler(x, y, Rotation.eulerAngles.z);
+        public void SetRotation(float x, float y) =>
+            Rotation = Quaternion.Euler(x, y, Rotation.eulerAngles.z);
 
         public void SetProp(LightProp prop, float value)
         {
@@ -236,15 +212,77 @@ namespace MeidoPhotoStudio.Plugin
 
         public void ResetLightProps()
         {
-            LightProperties[(int)SelectedLightType] = new LightProperty();
+            LightProperties[(int)SelectedLightType] = new();
             SetProps();
         }
 
-        public void ResetLightPosition() => light.transform.position = LightProperty.DefaultPosition;
+        public void ResetLightPosition() =>
+            light.transform.position = LightProperty.DefaultPosition;
+
+        public override void Set(Transform myObject)
+        {
+            base.Set(myObject);
+
+            light = myObject.gameObject.GetOrAddComponent<Light>();
+
+            // TODO: Use trasnform.SetPositionAndRotation
+            light.transform.position = LightProperty.DefaultPosition;
+            light.transform.rotation = LightProperty.DefaultRotation;
+
+            SetLightType(MPSLightType.Normal);
+
+            ScaleFactor = 50f;
+            DefaultRotation = LightProperty.DefaultRotation;
+            DefaultPosition = LightProperty.DefaultPosition;
+        }
+
+        protected override void OnDestroy()
+        {
+            if (!IsMain)
+                Destroy(light.gameObject);
+
+            base.OnDestroy();
+        }
+
+        protected override void OnRotate()
+        {
+            CurrentLightProperty.Rotation = light.transform.rotation;
+
+            base.OnRotate();
+        }
+
+        protected override void OnScale()
+        {
+            var value = light.transform.localScale.x;
+
+            if (SelectedLightType is MPSLightType.Point)
+                Range = value;
+            else if (SelectedLightType is MPSLightType.Spot)
+                SpotAngle = value;
+
+            base.OnScale();
+        }
+
+        protected override void ApplyDragType()
+        {
+            if (Selecting || Moving)
+                ApplyProperties(true, true, false);
+            else if (SelectedLightType is not MPSLightType.Point && Rotating)
+                ApplyProperties(true, true, false);
+            else if (SelectedLightType is not MPSLightType.Normal && Scaling)
+                ApplyProperties(true, true, false);
+            else if (!IsMain && Deleting)
+                ApplyProperties(true, true, false);
+            else
+                ApplyProperties(false, false, false);
+
+            ApplyColours();
+        }
 
         private void SetProps()
         {
             SetLightProperties(light, CurrentLightProperty);
+
             if (IsColourMode)
             {
                 light.color = Color.white;
@@ -257,6 +295,7 @@ namespace MeidoPhotoStudio.Plugin
     {
         public static readonly Vector3 DefaultPosition = new(0f, 1.9f, 0.4f);
         public static readonly Quaternion DefaultRotation = Quaternion.Euler(40f, 180f, 0f);
+
         public Quaternion Rotation { get; set; } = DefaultRotation;
         public float Intensity { get; set; } = 0.95f;
         public float Range { get; set; } = GameMain.Instance.MainLight.GetComponent<Light>().range;

+ 19 - 14
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointMeido.cs

@@ -1,36 +1,43 @@
 using System;
 using UnityEngine;
 
+using static MeidoPhotoStudio.Plugin.CustomGizmo;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static CustomGizmo;
     public abstract class DragPointMeido : DragPoint
     {
-        public static readonly Vector3 boneScale = Vector3.one * 0.04f;
         protected const int jointUpper = 0;
         protected const int jointMiddle = 1;
         protected const int jointLower = 2;
+
+        public static readonly Vector3 boneScale = Vector3.one * 0.04f;
+
         protected Meido meido;
         protected Maid maid;
-        protected IKCtrlData IkCtrlData => meido.Body.IKCtrl.GetIKData("左手");
         protected bool isPlaying;
         protected bool isBone;
+
+        protected IKCtrlData IkCtrlData =>
+            meido.Body.IKCtrl.GetIKData("左手");
+
         public virtual bool IsBone
         {
             get => isBone;
             set
             {
-                if (value != isBone)
-                {
-                    isBone = value;
-                    ApplyDragType();
-                }
+                if (value == isBone)
+                    return;
+
+                isBone = value;
+                ApplyDragType();
             }
         }
 
         public virtual void Initialize(Meido meido, Func<Vector3> position, Func<Vector3> rotation)
         {
             base.Initialize(position, rotation);
+
             this.meido = meido;
             maid = meido.Maid;
             isPlaying = !meido.Stop;
@@ -39,6 +46,7 @@ namespace MeidoPhotoStudio.Plugin
         public override void AddGizmo(float scale = 0.25f, GizmoMode mode = GizmoMode.Local)
         {
             base.AddGizmo(scale, mode);
+
             Gizmo.GizmoDrag += (s, a) =>
             {
                 meido.Stop = true;
@@ -49,17 +57,14 @@ namespace MeidoPhotoStudio.Plugin
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
+
             isPlaying = !meido.Stop;
         }
 
-        protected void InitializeIK(TBody.IKCMO iKCmo, Transform upper, Transform middle, Transform lower)
-        {
+        protected void InitializeIK(TBody.IKCMO iKCmo, Transform upper, Transform middle, Transform lower) =>
             iKCmo.Init(upper, middle, lower, maid.body0);
-        }
 
-        protected void Porc(TBody.IKCMO ikCmo, IKCtrlData ikData, Transform upper, Transform middle, Transform lower)
-        {
+        protected void Porc(TBody.IKCMO ikCmo, IKCtrlData ikData, Transform upper, Transform middle, Transform lower) =>
             ikCmo.Porc(upper, middle, lower, CursorPosition(), Vector3.zero, ikData);
-        }
     }
 }

+ 14 - 10
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointOther.cs

@@ -1,32 +1,35 @@
-using System.Collections.Generic;
 using UnityEngine;
-using UnityEngine.Rendering;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public class DragPointBody : DragPointGeneral
     {
         public bool IsCube;
+
         private bool isIK;
+
         public bool IsIK
         {
             get => isIK;
             set
             {
-                if (isIK != value)
-                {
-                    isIK = value;
-                    ApplyDragType();
-                }
+                if (isIK == value)
+                    return;
+
+                isIK = value;
+                ApplyDragType();
             }
         }
+
         protected override void ApplyDragType()
         {
-            bool enabled = !IsIK && (Transforming || Selecting);
-            bool select = IsIK && Selecting;
+            var enabled = !IsIK && (Transforming || Selecting);
+            var select = IsIK && Selecting;
+
             ApplyProperties(enabled || select, IsCube && enabled, false);
 
-            if (IsCube) ApplyColours();
+            if (IsCube)
+                ApplyColours();
         }
     }
 
@@ -35,6 +38,7 @@ namespace MeidoPhotoStudio.Plugin
         public override void Set(Transform myObject)
         {
             base.Set(myObject);
+
             DefaultPosition = myObject.position;
         }
 

+ 41 - 28
src/MeidoPhotoStudio.Plugin/DragPoint/DragPointProp.cs

@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using UnityEngine;
@@ -8,15 +8,19 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class DragPointProp : DragPointGeneral
     {
-        private List<Renderer> renderers;
         public AttachPointInfo AttachPointInfo { get; private set; } = AttachPointInfo.Empty;
-        public string Name => MyGameObject.name;
         public string assetName = string.Empty;
+
+        private List<Renderer> renderers;
+
         public PropInfo Info { get; set; }
 
+        public string Name =>
+            MyGameObject.name;
+
         public bool ShadowCasting
         {
-            get => renderers.Count != 0 && renderers.Any(r => r.shadowCastingMode == ShadowCastingMode.On);
+            get => renderers.Count is not 0 && renderers.Any(r => r.shadowCastingMode is ShadowCastingMode.On);
             set
             {
                 foreach (var renderer in renderers)
@@ -24,20 +28,11 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        public override void Set(Transform myObject)
-        {
-            base.Set(myObject);
-            DefaultRotation = MyObject.rotation;
-            DefaultPosition = MyObject.position;
-            DefaultScale = MyObject.localScale;
-            renderers = new List<Renderer>(MyObject.GetComponentsInChildren<Renderer>());
-        }
-
         public void AttachTo(Meido meido, AttachPoint point, bool keepWorldPosition = true)
         {
             var attachPoint = meido?.IKManager.GetAttachPointTransform(point);
 
-            AttachPointInfo = meido == null ? AttachPointInfo.Empty : new AttachPointInfo(point, meido);
+            AttachPointInfo = meido == null ? AttachPointInfo.Empty : new(point, meido);
 
             var position = MyObject.position;
             var rotation = MyObject.rotation;
@@ -47,7 +42,7 @@ namespace MeidoPhotoStudio.Plugin
 
             if (keepWorldPosition)
             {
-                MyObject.position = position;
+                // TODO: Use transform.SetPositionAndRotation MyObject.position = position;
                 MyObject.rotation = rotation;
             }
             else
@@ -58,10 +53,12 @@ namespace MeidoPhotoStudio.Plugin
 
             MyObject.localScale = scale;
 
-            if (attachPoint == null) Utility.FixGameObjectScale(MyGameObject);
+            if (attachPoint == null)
+                Utility.FixGameObjectScale(MyGameObject);
         }
 
-        public void DetachFrom(bool keepWorldPosition = true) => AttachTo(null, AttachPoint.None, keepWorldPosition);
+        public void DetachFrom(bool keepWorldPosition = true) =>
+            AttachTo(null, AttachPoint.None, keepWorldPosition);
 
         public void DetachTemporary()
         {
@@ -69,9 +66,20 @@ namespace MeidoPhotoStudio.Plugin
             Utility.FixGameObjectScale(MyGameObject);
         }
 
+        public override void Set(Transform myObject)
+        {
+            base.Set(myObject);
+
+            DefaultRotation = MyObject.rotation;
+            DefaultPosition = MyObject.position;
+            DefaultScale = MyObject.localScale;
+            renderers = new List<Renderer>(MyObject.GetComponentsInChildren<Renderer>());
+        }
+
         protected override void ApplyDragType()
         {
             var active = DragPointEnabled && Transforming || Special;
+
             ApplyProperties(active, active, GizmoEnabled && Rotating);
             ApplyColours();
         }
@@ -95,19 +103,24 @@ namespace MeidoPhotoStudio.Plugin
 
         public PropInfo(PropType type) => Type = type;
 
-        public static PropInfo FromModItem(ModItem modItem) => new(PropType.Mod)
-        {
-            Filename = modItem.IsOfficialMod ? Path.GetFileName(modItem.MenuFile) : modItem.MenuFile,
-            SubFilename = modItem.BaseMenuFile
-        };
+        public static PropInfo FromModItem(ModItem modItem) =>
+            new(PropType.Mod)
+            {
+                Filename = modItem.IsOfficialMod ? Path.GetFileName(modItem.MenuFile) : modItem.MenuFile,
+                SubFilename = modItem.BaseMenuFile
+            };
 
-        public static PropInfo FromMyRoom(MyRoomItem myRoomItem) => new(PropType.MyRoom)
-        {
-            MyRoomID = myRoomItem.ID, Filename = myRoomItem.PrefabName
-        };
+        public static PropInfo FromMyRoom(MyRoomItem myRoomItem) =>
+            new(PropType.MyRoom)
+            {
+                MyRoomID = myRoomItem.ID,
+                Filename = myRoomItem.PrefabName
+            };
 
-        public static PropInfo FromBg(string name) => new(PropType.Bg) { Filename = name };
+        public static PropInfo FromBg(string name) =>
+            new(PropType.Bg) { Filename = name };
 
-        public static PropInfo FromGameProp(string name) => new(PropType.Odogu) { Filename = name };
+        public static PropInfo FromGameProp(string name) =>
+            new(PropType.Odogu) { Filename = name };
     }
 }

+ 4 - 1
src/MeidoPhotoStudio.Plugin/GUI/Controls/BaseControl.cs

@@ -6,7 +6,10 @@ namespace MeidoPhotoStudio.Plugin
     public abstract class BaseControl
     {
         public event EventHandler ControlEvent;
+
         public virtual void Draw(params GUILayoutOption[] layoutOptions) { }
-        public virtual void OnControlEvent(EventArgs args) => ControlEvent?.Invoke(this, args);
+
+        public virtual void OnControlEvent(EventArgs args) =>
+            ControlEvent?.Invoke(this, args);
     }
 }

+ 8 - 3
src/MeidoPhotoStudio.Plugin/GUI/Controls/Button.cs

@@ -6,15 +6,20 @@ namespace MeidoPhotoStudio.Plugin
     public class Button : BaseControl
     {
         public string Label { get; set; }
-        public Button(string label) => Label = label;
+
+        public Button(string label) =>
+            Label = label;
+
         public void Draw(GUIStyle buttonStyle, params GUILayoutOption[] layoutOptions)
         {
-            if (GUILayout.Button(Label, buttonStyle, layoutOptions)) OnControlEvent(EventArgs.Empty);
+            if (GUILayout.Button(Label, buttonStyle, layoutOptions))
+                OnControlEvent(EventArgs.Empty);
         }
 
         public override void Draw(params GUILayoutOption[] layoutOptions)
         {
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
+            var buttonStyle = new GUIStyle(GUI.skin.button);
+
             Draw(buttonStyle, layoutOptions);
         }
     }

+ 21 - 12
src/MeidoPhotoStudio.Plugin/GUI/Controls/ComboBox.cs

@@ -4,8 +4,10 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class ComboBox : BaseControl
     {
-        private readonly TextField textField = new TextField();
+        private readonly TextField textField = new();
+
         public Dropdown BaseDropDown { get; }
+
         public string Value
         {
             get => textField.Value;
@@ -14,34 +16,41 @@ namespace MeidoPhotoStudio.Plugin
 
         public ComboBox(string[] itemList)
         {
-            BaseDropDown = new Dropdown("▾", itemList);
+            BaseDropDown = new("▾", itemList);
             BaseDropDown.SelectionChange += (s, a) => textField.Value = BaseDropDown.SelectedItem;
             Value = itemList[0];
         }
 
         public void SetDropdownItems(string[] itemList)
         {
-            string oldValue = Value;
+            var oldValue = Value;
+
             BaseDropDown.SetDropdownItems(itemList);
             Value = oldValue;
         }
 
-        public void SetDropdownItem(int index, string newItem) => BaseDropDown.SetDropdownItem(index, newItem);
-
-        public void SetDropdownItem(string newItem) => BaseDropDown.SetDropdownItem(newItem);
+        public void SetDropdownItem(int index, string newItem) =>
+            BaseDropDown.SetDropdownItem(index, newItem);
 
-        public override void Draw(params GUILayoutOption[] layoutOptions)
-        {
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button) { alignment = TextAnchor.MiddleCenter };
-            Draw(buttonStyle, layoutOptions);
-        }
+        public void SetDropdownItem(string newItem) =>
+            BaseDropDown.SetDropdownItem(newItem);
 
         public void Draw(GUIStyle style, params GUILayoutOption[] layoutOptions)
         {
             GUILayout.BeginHorizontal();
-            textField.Draw(new GUIStyle(GUI.skin.textField), layoutOptions);
+            textField.Draw(new(GUI.skin.textField), layoutOptions);
             BaseDropDown.Draw(style, GUILayout.ExpandWidth(false));
             GUILayout.EndHorizontal();
         }
+
+        public override void Draw(params GUILayoutOption[] layoutOptions)
+        {
+            var buttonStyle = new GUIStyle(GUI.skin.button)
+            {
+                alignment = TextAnchor.MiddleCenter,
+            };
+
+            Draw(buttonStyle, layoutOptions);
+        }
     }
 }

+ 146 - 101
src/MeidoPhotoStudio.Plugin/GUI/Controls/DropDown.cs

@@ -1,31 +1,42 @@
 using System;
 using UnityEngine;
+using DropdownCloseArgs = MeidoPhotoStudio.Plugin.DropdownHelper.DropdownCloseArgs;
+using DropdownSelectArgs = MeidoPhotoStudio.Plugin.DropdownHelper.DropdownSelectArgs;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using DropdownSelectArgs = DropdownHelper.DropdownSelectArgs;
-    using DropdownCloseArgs = DropdownHelper.DropdownCloseArgs;
     public class Dropdown : BaseControl
     {
+        private readonly string label;
+        private readonly bool isMenu;
+
         public event EventHandler SelectionChange;
         public event EventHandler DropdownOpen;
         public event EventHandler DropdownClose;
+
+        private Vector2 elementSize;
+        private int selectedItemIndex;
         private bool clickedYou;
         private bool showDropdown;
-        private readonly string label;
-        private readonly bool isMenu;
-        public string[] DropdownList { get; private set; }
-        public int DropdownID { get; }
         private Vector2 scrollPos;
-        public Vector2 ScrollPos => scrollPos;
         private Rect buttonRect;
+
+        public int DropdownID { get; }
+
+        public string[] DropdownList { get; private set; }
+
+        public Vector2 ScrollPos =>
+            scrollPos;
+
         public Rect ButtonRect
         {
             get => buttonRect;
             private set => buttonRect = value;
         }
-        private Vector2 elementSize;
-        public Vector2 ElementSize => elementSize;
-        private int selectedItemIndex;
+
+        public Vector2 ElementSize =>
+            elementSize;
+
         public int SelectedItemIndex
         {
             get => selectedItemIndex;
@@ -35,13 +46,16 @@ namespace MeidoPhotoStudio.Plugin
                 OnDropdownEvent(SelectionChange);
             }
         }
-        public string SelectedItem => DropdownList[SelectedItemIndex];
+
+        public string SelectedItem =>
+            DropdownList[SelectedItemIndex];
 
         public Dropdown(string label, string[] itemList, int selectedItemIndex = 0)
             : this(itemList, selectedItemIndex)
         {
-            isMenu = true;
             this.label = label;
+
+            isMenu = true;
         }
 
         public Dropdown(string[] itemList, int selectedItemIndex = 0)
@@ -62,33 +76,34 @@ namespace MeidoPhotoStudio.Plugin
 
         public void SetDropdownItems(string[] itemList, int selectedItemIndex = -1)
         {
-            if (selectedItemIndex < 0) selectedItemIndex = SelectedItemIndex;
+            if (selectedItemIndex < 0)
+                selectedItemIndex = SelectedItemIndex;
+
             elementSize = Vector2.zero;
 
             // TODO: Calculate scrollpos position maybe
-            if ((selectedItemIndex != this.selectedItemIndex) || (itemList.Length != DropdownList?.Length))
-            {
+            if (selectedItemIndex != this.selectedItemIndex || itemList.Length != DropdownList?.Length)
                 scrollPos = Vector2.zero;
-            }
+
             DropdownList = itemList;
             SelectedItemIndex = selectedItemIndex;
         }
 
         public void SetDropdownItem(int index, string newItem)
         {
-            if (index < 0 || index >= DropdownList.Length) return;
+            if (index < 0 || index >= DropdownList.Length)
+                return;
 
-            Vector2 itemSize = DropdownHelper.CalculateElementSize(newItem);
+            var itemSize = DropdownHelper.CalculateElementSize(newItem);
 
-            if (itemSize.x > ElementSize.x) elementSize = itemSize;
+            if (itemSize.x > ElementSize.x)
+                elementSize = itemSize;
 
             DropdownList[index] = newItem;
         }
 
-        public void SetDropdownItem(string newItem)
-        {
+        public void SetDropdownItem(string newItem) =>
             SetDropdownItem(SelectedItemIndex, newItem);
-        }
 
         public void Step(int dir)
         {
@@ -96,14 +111,12 @@ namespace MeidoPhotoStudio.Plugin
             SelectedItemIndex = Utility.Wrap(SelectedItemIndex + dir, 0, DropdownList.Length);
         }
 
-        public void Draw(GUIStyle buttonStyle, params GUILayoutOption[] layoutOptions)
-        {
+        public void Draw(GUIStyle buttonStyle, params GUILayoutOption[] layoutOptions) =>
             Draw(buttonStyle, null, layoutOptions);
-        }
 
         public void Draw(GUIStyle buttonStyle, GUIStyle dropdownStyle = null, params GUILayoutOption[] layoutOptions)
         {
-            bool clicked = GUILayout.Button(
+            var clicked = GUILayout.Button(
                 isMenu ? label : DropdownList[selectedItemIndex], buttonStyle, layoutOptions
             );
 
@@ -113,34 +126,38 @@ namespace MeidoPhotoStudio.Plugin
                 clickedYou = false;
             }
 
-            if (showDropdown && Event.current.type == EventType.Repaint) InitializeDropdown(dropdownStyle);
+            if (showDropdown && Event.current.type is EventType.Repaint)
+                InitializeDropdown(dropdownStyle);
         }
 
         public override void Draw(params GUILayoutOption[] layoutOptions)
         {
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button) { alignment = TextAnchor.MiddleLeft };
+            var buttonStyle = new GUIStyle(GUI.skin.button)
+            {
+                alignment = TextAnchor.MiddleLeft,
+            };
+
             Draw(buttonStyle, layoutOptions);
         }
 
         private void OnChangeSelection(object sender, DropdownSelectArgs args)
         {
             if (args.DropdownID == DropdownID)
-            {
                 SelectedItemIndex = args.SelectedItemIndex;
-            }
         }
 
         private void OnCloseDropdown(object sender, DropdownCloseArgs args)
         {
-            if (args.DropdownID == DropdownID)
-            {
-                scrollPos = args.ScrollPos;
-                clickedYou = args.ClickedYou;
+            if (args.DropdownID != DropdownID)
+                return;
 
-                if (clickedYou) OnDropdownEvent(SelectionChange);
+            scrollPos = args.ScrollPos;
+            clickedYou = args.ClickedYou;
 
-                OnDropdownEvent(DropdownClose);
-            }
+            if (clickedYou)
+                OnDropdownEvent(SelectionChange);
+
+            OnDropdownEvent(DropdownClose);
         }
 
         private void InitializeDropdown(GUIStyle dropdownStyle)
@@ -148,39 +165,35 @@ namespace MeidoPhotoStudio.Plugin
             showDropdown = false;
 
             buttonRect = GUILayoutUtility.GetLastRect();
-            Vector2 rectPos = GUIUtility.GUIToScreenPoint(new Vector2(buttonRect.x, buttonRect.y));
+
+            var rectPos = GUIUtility.GUIToScreenPoint(new Vector2(buttonRect.x, buttonRect.y));
+
             buttonRect.x = rectPos.x;
             buttonRect.y = rectPos.y;
+
             if (elementSize == Vector2.zero)
-            {
                 elementSize = DropdownHelper.CalculateElementSize(DropdownList, dropdownStyle);
-            }
+
             DropdownHelper.Set(this, dropdownStyle);
 
             OnDropdownEvent(DropdownOpen);
         }
 
-        private void OnDropdownEvent(EventHandler handler)
-        {
+        private void OnDropdownEvent(EventHandler handler) =>
             handler?.Invoke(this, EventArgs.Empty);
-        }
     }
 
     public static class DropdownHelper
     {
         public static event EventHandler<DropdownSelectArgs> SelectionChange;
         public static event EventHandler<DropdownCloseArgs> DropdownClose;
+        public static Rect dropdownWindow;
+
         private static int dropdownID = 100;
-        public static int DropdownID => dropdownID++;
         private static GUIStyle defaultDropdownStyle;
-        public static GUIStyle DefaultDropdownStyle
-        {
-            get
-            {
-                if (!initialized) InitializeStyle();
-                return defaultDropdownStyle;
-            }
-        }
+        private static bool onScrollBar;
+        private static Rect dropdownScrollRect;
+        private static Rect dropdownRect;
         private static GUIStyle dropdownStyle;
         private static GUIStyle windowStyle;
         private static Rect buttonRect;
@@ -189,16 +202,28 @@ namespace MeidoPhotoStudio.Plugin
         private static int currentDropdownID;
         private static int selectedItemIndex;
         private static bool initialized;
+
+        public static int DropdownID =>
+            dropdownID++;
+
+        public static GUIStyle DefaultDropdownStyle
+        {
+            get
+            {
+                if (!initialized)
+                    InitializeStyle();
+
+                return defaultDropdownStyle;
+            }
+        }
+
         public static bool Visible { get; set; }
         public static bool DropdownOpen { get; private set; }
-        private static bool onScrollBar;
-        public static Rect dropdownWindow;
-        private static Rect dropdownScrollRect;
-        private static Rect dropdownRect;
 
         public static Vector2 CalculateElementSize(string item, GUIStyle style = null)
         {
-            if (!initialized) InitializeStyle();
+            if (!initialized)
+                InitializeStyle();
 
             style ??= DefaultDropdownStyle;
 
@@ -207,17 +232,22 @@ namespace MeidoPhotoStudio.Plugin
 
         public static Vector2 CalculateElementSize(string[] list, GUIStyle style = null)
         {
-            if (!initialized) InitializeStyle();
+            if (!initialized)
+                InitializeStyle();
 
             style ??= DefaultDropdownStyle;
 
-            GUIContent content = new GUIContent(list[0]);
-            Vector2 calculatedSize = style.CalcSize(content);
-            for (int i = 1; i < list.Length; i++)
+            var content = new GUIContent(list[0]);
+            var calculatedSize = style.CalcSize(content);
+
+            for (var i = 1; i < list.Length; i++)
             {
                 content.text = list[i];
-                Vector2 calcSize = style.CalcSize(content);
-                if (calcSize.x > calculatedSize.x) calculatedSize = calcSize;
+
+                var calcSize = style.CalcSize(content);
+
+                if (calcSize.x > calculatedSize.x)
+                    calculatedSize = calcSize;
             }
 
             return calculatedSize;
@@ -232,30 +262,31 @@ namespace MeidoPhotoStudio.Plugin
             selectedItemIndex = dropdown.SelectedItemIndex;
             scrollPos = dropdown.ScrollPos;
             buttonRect = dropdown.ButtonRect;
-            Vector2 calculatedSize = dropdown.ElementSize;
 
-            float calculatedListHeight = calculatedSize.y * dropdownList.Length;
+            var calculatedSize = dropdown.ElementSize;
 
-            float heightAbove = buttonRect.y;
-            float heightBelow = Screen.height - heightAbove - buttonRect.height;
+            var calculatedListHeight = calculatedSize.y * dropdownList.Length;
 
-            float rectWidth = Mathf.Max(calculatedSize.x + 5, buttonRect.width);
-            float rectHeight = Mathf.Min(calculatedListHeight, Mathf.Max(heightAbove, heightBelow));
+            var heightAbove = buttonRect.y;
+            var heightBelow = Screen.height - heightAbove - buttonRect.height;
+
+            var rectWidth = Mathf.Max(calculatedSize.x + 5, buttonRect.width);
+            var rectHeight = Mathf.Min(calculatedListHeight, Mathf.Max(heightAbove, heightBelow));
 
             if (calculatedListHeight > heightBelow && heightAbove > heightBelow)
-            {
-                dropdownWindow = new Rect(buttonRect.x, buttonRect.y - rectHeight, rectWidth + 18, rectHeight);
-            }
+                dropdownWindow = new(buttonRect.x, buttonRect.y - rectHeight, rectWidth + 18, rectHeight);
             else
             {
-                if (calculatedListHeight > heightBelow) rectHeight -= calculatedSize.y;
-                dropdownWindow = new Rect(buttonRect.x, buttonRect.y + buttonRect.height, rectWidth + 18, rectHeight);
+                if (calculatedListHeight > heightBelow)
+                    rectHeight -= calculatedSize.y;
+
+                dropdownWindow = new(buttonRect.x, buttonRect.y + buttonRect.height, rectWidth + 18, rectHeight);
             }
 
             dropdownWindow.x = Mathf.Clamp(dropdownWindow.x, 0, Screen.width - rectWidth - 18);
 
-            dropdownScrollRect = new Rect(0, 0, dropdownWindow.width, dropdownWindow.height);
-            dropdownRect = new Rect(0, 0, dropdownWindow.width - 18, calculatedListHeight);
+            dropdownScrollRect = new(0, 0, dropdownWindow.width, dropdownWindow.height);
+            dropdownRect = new(0, 0, dropdownWindow.width - 18, calculatedListHeight);
 
             DropdownOpen = true;
             Visible = true;
@@ -264,55 +295,66 @@ namespace MeidoPhotoStudio.Plugin
         public static void HandleDropdown()
         {
             dropdownWindow = GUI.Window(Constants.dropdownWindowID, dropdownWindow, GUIFunc, "", windowStyle);
-            if (Input.mouseScrollDelta.y != 0f && Visible && dropdownWindow.Contains(Event.current.mousePosition))
-            {
+
+            if (Input.mouseScrollDelta.y is not 0f && Visible && dropdownWindow.Contains(Event.current.mousePosition))
                 Input.ResetInputAxes();
-            }
         }
 
         private static void GUIFunc(int id)
         {
-            bool clicked = false;
+            var clicked = false;
 
-            if (Event.current.type == EventType.MouseUp) clicked = true;
+            if (Event.current.type is EventType.MouseUp)
+                clicked = true;
 
             scrollPos = GUI.BeginScrollView(dropdownScrollRect, scrollPos, dropdownRect);
-            int selection = GUI.SelectionGrid(dropdownRect, selectedItemIndex, dropdownList, 1, dropdownStyle);
+
+            var selection = GUI.SelectionGrid(dropdownRect, selectedItemIndex, dropdownList, 1, dropdownStyle);
+
             GUI.EndScrollView();
 
-            bool clickedYou = false;
+            var clickedYou = false;
+
             if (Utility.AnyMouseDown())
             {
-                Vector2 mousePos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
-                bool clickedMe = dropdownWindow.Contains(mousePos);
+                var mousePos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition);
+                var clickedMe = dropdownWindow.Contains(mousePos);
+
                 onScrollBar = mousePos.x > dropdownWindow.x + dropdownWindow.width - 12f;
-                if (buttonRect.Contains(mousePos)) clickedYou = true;
-                if (!clickedMe) DropdownOpen = false;
+
+                if (buttonRect.Contains(mousePos))
+                    clickedYou = true;
+
+                if (!clickedMe)
+                    DropdownOpen = false;
             }
 
-            if (selection != selectedItemIndex || (clicked && !onScrollBar))
+            if (selection != selectedItemIndex || clicked && !onScrollBar)
             {
-                SelectionChange?.Invoke(null, new DropdownSelectArgs(currentDropdownID, selection));
+                SelectionChange?.Invoke(null, new(currentDropdownID, selection));
                 DropdownOpen = false;
             }
 
             if (!DropdownOpen)
             {
                 Visible = false;
-                DropdownClose?.Invoke(null, new DropdownCloseArgs(currentDropdownID, scrollPos, clickedYou));
+                DropdownClose?.Invoke(null, new(currentDropdownID, scrollPos, clickedYou));
             }
         }
 
         private static void InitializeStyle()
         {
-            defaultDropdownStyle = new GUIStyle(GUI.skin.button)
+            defaultDropdownStyle = new(GUI.skin.button)
             {
                 alignment = TextAnchor.MiddleLeft,
-                margin = new RectOffset(0, 0, 0, 0)
+                margin = new(0, 0, 0, 0),
             };
+
             defaultDropdownStyle.padding.top = defaultDropdownStyle.padding.bottom = 2;
-            defaultDropdownStyle.normal.background = Utility.MakeTex(2, 2, new Color(0f, 0f, 0f, 0.5f));
-            Texture2D whiteBackground = new Texture2D(2, 2);
+            defaultDropdownStyle.normal.background = Utility.MakeTex(2, 2, new(0f, 0f, 0f, 0.5f));
+
+            var whiteBackground = new Texture2D(2, 2);
+
             defaultDropdownStyle.onHover.background
                 = defaultDropdownStyle.hover.background
                 = defaultDropdownStyle.onNormal.background
@@ -322,33 +364,36 @@ namespace MeidoPhotoStudio.Plugin
                 = defaultDropdownStyle.hover.textColor
                 = Color.black;
 
-            windowStyle = new GUIStyle(GUI.skin.box)
+            windowStyle = new(GUI.skin.box)
             {
-                padding = new RectOffset(0, 0, 0, 0),
-                alignment = TextAnchor.UpperRight
+                padding = new(0, 0, 0, 0),
+                alignment = TextAnchor.UpperRight,
             };
+
             initialized = true;
         }
 
         public class DropdownEventArgs : EventArgs
         {
             public int DropdownID { get; }
-            public DropdownEventArgs(int dropdownID) => DropdownID = dropdownID;
+
+            public DropdownEventArgs(int dropdownID) =>
+                DropdownID = dropdownID;
         }
 
         public class DropdownSelectArgs : DropdownEventArgs
         {
             public int SelectedItemIndex { get; }
-            public DropdownSelectArgs(int dropdownID, int selection) : base(dropdownID)
-            {
+
+            public DropdownSelectArgs(int dropdownID, int selection) : base(dropdownID) =>
                 SelectedItemIndex = selection;
-            }
         }
 
         public class DropdownCloseArgs : DropdownEventArgs
         {
             public Vector2 ScrollPos { get; }
             public bool ClickedYou { get; }
+
             public DropdownCloseArgs(int dropdownID, Vector2 scrollPos, bool clickedYou = false) : base(dropdownID)
             {
                 ScrollPos = scrollPos;

+ 12 - 4
src/MeidoPhotoStudio.Plugin/GUI/Controls/KeyRebindButton.cs

@@ -6,8 +6,10 @@ namespace MeidoPhotoStudio.Plugin
     public class KeyRebindButton : BaseControl
     {
         private readonly Button button;
+
         private bool listening;
         private KeyCode keyCode;
+
         public KeyCode KeyCode
         {
             get => keyCode;
@@ -17,9 +19,10 @@ namespace MeidoPhotoStudio.Plugin
                 button.Label = keyCode.ToString();
             }
         }
+
         public KeyRebindButton(KeyCode code)
         {
-            button = new Button(code.ToString());
+            button = new(code.ToString());
             button.ControlEvent += (s, a) => StartListening();
         }
 
@@ -32,7 +35,8 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void Draw(params GUILayoutOption[] layoutOptions)
         {
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
+            var buttonStyle = new GUIStyle(GUI.skin.button);
+
             Draw(buttonStyle, layoutOptions);
         }
 
@@ -47,9 +51,13 @@ namespace MeidoPhotoStudio.Plugin
         private void KeyChange(object sender, EventArgs args)
         {
             listening = false;
-            if (InputManager.CurrentKeyCode != KeyCode.Escape) KeyCode = InputManager.CurrentKeyCode;
-            else KeyCode = KeyCode;
+
+            KeyCode = InputManager.CurrentKeyCode is not KeyCode.Escape
+                ? InputManager.CurrentKeyCode
+                : KeyCode;
+
             InputManager.KeyChange -= KeyChange;
+
             OnControlEvent(EventArgs.Empty);
         }
     }

+ 9 - 3
src/MeidoPhotoStudio.Plugin/GUI/Controls/Modal.cs

@@ -5,19 +5,24 @@ namespace MeidoPhotoStudio.Plugin
     public static class Modal
     {
         private static BaseWindow currentModal;
+
         public static bool Visible
         {
             get => currentModal?.Visible ?? false;
             set
             {
-                if (currentModal == null) return;
+                if (currentModal is null)
+                    return;
+
                 currentModal.Visible = value;
             }
         }
 
         public static void Show(BaseWindow modalWindow)
         {
-            if (currentModal != null) Close();
+            if (currentModal is not null)
+                Close();
+
             currentModal = modalWindow;
             Visible = true;
         }
@@ -30,7 +35,8 @@ namespace MeidoPhotoStudio.Plugin
 
         public static void Draw()
         {
-            GUIStyle windowStyle = new GUIStyle(GUI.skin.box);
+            var windowStyle = new GUIStyle(GUI.skin.box);
+
             currentModal.WindowRect = GUI.ModalWindow(
                 currentModal.windowID, currentModal.WindowRect, currentModal.GUIFunc, "", windowStyle
             );

+ 50 - 35
src/MeidoPhotoStudio.Plugin/GUI/Controls/SelectionGrid.cs

@@ -7,16 +7,17 @@ namespace MeidoPhotoStudio.Plugin
     {
         private SimpleToggle[] toggles;
         private int selectedItemIndex;
+
         public int SelectedItemIndex
         {
             get => selectedItemIndex;
             set
             {
                 selectedItemIndex = Mathf.Clamp(value, 0, toggles.Length - 1);
-                foreach (SimpleToggle toggle in toggles)
-                {
+
+                foreach (var toggle in toggles)
                     toggle.value = toggle.toggleIndex == selectedItemIndex;
-                }
+
                 OnControlEvent(EventArgs.Empty);
             }
         }
@@ -27,51 +28,62 @@ namespace MeidoPhotoStudio.Plugin
             toggles = MakeToggles(items);
         }
 
-        private SimpleToggle[] MakeToggles(string[] items)
-        {
-            SimpleToggle[] toggles = new SimpleToggle[items.Length];
-            for (int i = 0; i < items.Length; i++)
-            {
-                SimpleToggle toggle = new SimpleToggle(items[i], i == SelectedItemIndex) { toggleIndex = i };
-                toggle.ControlEvent += (s, a) =>
-                {
-                    int value = (s as SimpleToggle).toggleIndex;
-                    if (value != SelectedItemIndex) SelectedItemIndex = value;
-                };
-                toggles[i] = toggle;
-            }
-            return toggles;
-        }
-
         public void SetItems(string[] items, int selectedItemIndex = -1)
         {
-            if (selectedItemIndex < 0) selectedItemIndex = SelectedItemIndex;
+            if (selectedItemIndex < 0)
+                selectedItemIndex = SelectedItemIndex;
+
             if (items.Length != toggles.Length)
-            {
                 toggles = MakeToggles(items);
-            }
             else
             {
-                for (int i = 0; i < items.Length; i++)
+                for (var i = 0; i < items.Length; i++)
                 {
-                    string item = items[i];
+                    var item = items[i];
+
                     toggles[i].value = i == SelectedItemIndex;
                     toggles[i].label = item;
                 }
             }
+
             SelectedItemIndex = Mathf.Clamp(selectedItemIndex, 0, items.Length - 1);
         }
 
         public override void Draw(params GUILayoutOption[] layoutOptions)
         {
             GUILayout.BeginHorizontal();
-            foreach (SimpleToggle toggle in toggles)
-            {
+
+            foreach (var toggle in toggles)
                 toggle.Draw(layoutOptions);
-            }
+
             GUILayout.EndHorizontal();
         }
 
+        private SimpleToggle[] MakeToggles(string[] items)
+        {
+            var toggles = new SimpleToggle[items.Length];
+
+            for (var i = 0; i < items.Length; i++)
+            {
+                var toggle = new SimpleToggle(items[i], i == SelectedItemIndex)
+                {
+                    toggleIndex = i
+                };
+
+                toggle.ControlEvent += (s, a) =>
+                {
+                    var value = (s as SimpleToggle).toggleIndex;
+
+                    if (value != SelectedItemIndex)
+                        SelectedItemIndex = value;
+                };
+
+                toggles[i] = toggle;
+            }
+
+            return toggles;
+        }
+
         private class SimpleToggle
         {
             public int toggleIndex;
@@ -87,15 +99,18 @@ namespace MeidoPhotoStudio.Plugin
 
             public void Draw(params GUILayoutOption[] layoutOptions)
             {
-                bool value = GUILayout.Toggle(this.value, label, layoutOptions);
-                if (value != this.value)
+                var value = GUILayout.Toggle(this.value, label, layoutOptions);
+
+                if (value == this.value)
+                    return;
+
+                if (!value)
+                    this.value = true;
+                else
                 {
-                    if (!value) this.value = true;
-                    else
-                    {
-                        this.value = value;
-                        ControlEvent?.Invoke(this, EventArgs.Empty);
-                    }
+                    this.value = value;
+
+                    ControlEvent?.Invoke(this, EventArgs.Empty);
                 }
             }
         }

+ 33 - 21
src/MeidoPhotoStudio.Plugin/GUI/Controls/Slider.cs

@@ -8,6 +8,13 @@ namespace MeidoPhotoStudio.Plugin
     {
         private bool hasLabel;
         private string label;
+        private float value;
+        private float left;
+        private float right;
+        private float defaultValue;
+        private string textFieldValue;
+        private bool hasTextField;
+
         public string Label
         {
             get => label;
@@ -18,21 +25,20 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private float value;
-
         public float Value
         {
             get => value;
             set
             {
                 this.value = Utility.Bound(value, Left, Right);
-                if (hasTextField) textFieldValue = FormatValue(value);
+
+                if (hasTextField)
+                    textFieldValue = FormatValue(value);
+
                 OnControlEvent(EventArgs.Empty);
             }
         }
 
-        private float left;
-
         public float Left
         {
             get => left;
@@ -43,8 +49,6 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private float right;
-
         public float Right
         {
             get => right;
@@ -54,24 +58,25 @@ namespace MeidoPhotoStudio.Plugin
                 this.value = Utility.Bound(value, left, right);
             }
         }
-        private float defaultValue;
+
         public float DefaultValue
         {
             get => defaultValue;
             set => defaultValue = Utility.Bound(value, Left, Right);
         }
 
-        private string textFieldValue;
-        private bool hasTextField;
         public bool HasTextField
         {
             get => hasTextField;
             set
             {
                 hasTextField = value;
-                if (hasTextField) textFieldValue = FormatValue(Value);
+
+                if (hasTextField)
+                    textFieldValue = FormatValue(Value);
             }
         }
+
         public bool HasReset { get; set; }
 
         public Slider(string label, float left, float right, float value = 0, float defaultValue = 0)
@@ -84,9 +89,11 @@ namespace MeidoPhotoStudio.Plugin
             DefaultValue = defaultValue;
         }
 
-        public Slider(string label, SliderProp prop) : this(label, prop.Left, prop.Right, prop.Initial, prop.Default) { }
+        public Slider(string label, SliderProp prop)
+            : this(label, prop.Left, prop.Right, prop.Initial, prop.Default) { }
 
-        public Slider(SliderProp prop) : this(string.Empty, prop.Left, prop.Right, prop.Initial, prop.Default) { }
+        public Slider(SliderProp prop)
+            : this(string.Empty, prop.Left, prop.Right, prop.Initial, prop.Default) { }
 
         public void SetBounds(float left, float right)
         {
@@ -113,41 +120,46 @@ namespace MeidoPhotoStudio.Plugin
                 }
 
                 if (HasTextField)
-                {
                     tempText = GUILayout.TextField(textFieldValue, MpsGui.SliderTextBoxStyle, GUILayout.Width(60f));
-                }
 
                 if (HasReset && GUILayout.Button("|", MpsGui.SliderResetButtonStyle, GUILayout.Width(15f)))
                 {
                     Value = DefaultValue;
                     tempText = textFieldValue = FormatValue(Value);
                 }
+
                 GUILayout.EndHorizontal();
             }
 
-            GUIStyle sliderStyle = hasUpper ? MpsGui.SliderStyle : MpsGui.SliderStyleNoLabel;
+            var sliderStyle = hasUpper ? MpsGui.SliderStyle : MpsGui.SliderStyleNoLabel;
 
             var tempValue = GUILayout.HorizontalSlider(
                 Value, Left, Right, sliderStyle, MpsGui.SliderThumbStyle, layoutOptions
             );
 
-            if (hasUpper) GUILayout.EndVertical();
+            if (hasUpper)
+                GUILayout.EndVertical();
 
             if (HasTextField)
             {
-                if (tempValue != Value) tempText = textFieldValue = FormatValue(tempValue);
+                if (tempValue != Value)
+                    tempText = textFieldValue = FormatValue(tempValue);
 
                 if (tempText != textFieldValue)
                 {
                     textFieldValue = tempText;
-                    if (float.TryParse(tempText, out var newValue)) tempValue = newValue;
+
+                    if (float.TryParse(tempText, out var newValue))
+                        tempValue = newValue;
                 }
             }
 
-            if (tempValue != Value) Value = tempValue;
+            if (tempValue != Value)
+                Value = tempValue;
         }
 
-        private static string FormatValue(float value) => value.ToString("0.####", CultureInfo.InvariantCulture);
+        private static string FormatValue(float value) =>
+            value.ToString("0.####", CultureInfo.InvariantCulture);
     }
 
     public readonly struct SliderProp

+ 5 - 7
src/MeidoPhotoStudio.Plugin/GUI/Controls/TextArea.cs

@@ -5,13 +5,11 @@ namespace MeidoPhotoStudio.Plugin
     public class TextArea : BaseControl
     {
         public string Value { get; set; } = string.Empty;
-        public void Draw(GUIStyle textAreaStyle, params GUILayoutOption[] layoutOptions)
-        {
+
+        public void Draw(GUIStyle textAreaStyle, params GUILayoutOption[] layoutOptions) =>
             Value = GUILayout.TextArea(Value, textAreaStyle, layoutOptions);
-        }
-        public override void Draw(params GUILayoutOption[] layoutOptions)
-        {
-            Draw(new GUIStyle(GUI.skin.textArea), layoutOptions);
-        }
+
+        public override void Draw(params GUILayoutOption[] layoutOptions) =>
+            Draw(new(GUI.skin.textArea), layoutOptions);
     }
 }

+ 11 - 6
src/MeidoPhotoStudio.Plugin/GUI/Controls/TextField.cs

@@ -6,19 +6,24 @@ namespace MeidoPhotoStudio.Plugin
     public class TextField : BaseControl
     {
         private static int textFieldID = 961;
-        private static int ID => ++textFieldID;
+
+        private static int ID =>
+            ++textFieldID;
+
         private readonly string controlName = $"textField{ID}";
+
         public string Value { get; set; } = string.Empty;
+
         public void Draw(GUIStyle textFieldStyle, params GUILayoutOption[] layoutOptions)
         {
             GUI.SetNextControlName(controlName);
             Value = GUILayout.TextField(Value, textFieldStyle, layoutOptions);
-            if (Event.current.isKey && Event.current.keyCode == KeyCode.Return) OnControlEvent(EventArgs.Empty);
-        }
 
-        public override void Draw(params GUILayoutOption[] layoutOptions)
-        {
-            Draw(new GUIStyle(GUI.skin.textField), layoutOptions);
+            if (Event.current.isKey && Event.current.keyCode == KeyCode.Return)
+                OnControlEvent(EventArgs.Empty);
         }
+
+        public override void Draw(params GUILayoutOption[] layoutOptions) =>
+            Draw(new(GUI.skin.textField), layoutOptions);
     }
 }

+ 13 - 9
src/MeidoPhotoStudio.Plugin/GUI/Controls/Toggle.cs

@@ -6,12 +6,14 @@ namespace MeidoPhotoStudio.Plugin
     public class Toggle : BaseControl
     {
         private bool value;
+
         public bool Value
         {
             get => value;
             set
             {
                 this.value = value;
+
                 OnControlEvent(EventArgs.Empty);
             }
         }
@@ -24,21 +26,23 @@ namespace MeidoPhotoStudio.Plugin
             value = state;
         }
 
-        public override void Draw(params GUILayoutOption[] layoutOptions)
-        {
-            Draw(new GUIStyle(GUI.skin.toggle), layoutOptions);
-        }
-
         public void Draw(GUIStyle toggleStyle, params GUILayoutOption[] layoutOptions)
         {
-            bool value = GUILayout.Toggle(Value, Label, toggleStyle, layoutOptions);
-            if (value != Value) Value = value;
+            var value = GUILayout.Toggle(Value, Label, toggleStyle, layoutOptions);
+
+            if (value != Value)
+                Value = value;
         }
 
         public void Draw(Rect rect)
         {
-            bool value = GUI.Toggle(rect, Value, Label);
-            if (value != Value) Value = value;
+            var value = GUI.Toggle(rect, Value, Label);
+
+            if (value != Value)
+                Value = value;
         }
+
+        public override void Draw(params GUILayoutOption[] layoutOptions) =>
+            Draw(new(GUI.skin.toggle), layoutOptions);
     }
 }

+ 53 - 25
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/AttachPropPane.cs

@@ -1,18 +1,14 @@
 using System;
-using System.Linq;
 using System.Collections.Generic;
+using System.Linq;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public class AttachPropPane : BasePane
     {
-        private readonly PropManager propManager;
-        private readonly MeidoManager meidoManager;
-        private readonly Dictionary<AttachPoint, Toggle> toggles = new Dictionary<AttachPoint, Toggle>();
-
         private static readonly Dictionary<AttachPoint, string> toggleTranslation =
-            new Dictionary<AttachPoint, string>()
+            new()
             {
                 [AttachPoint.Head] = "head",
                 [AttachPoint.Neck] = "neck",
@@ -37,20 +33,33 @@ namespace MeidoPhotoStudio.Plugin
                 [AttachPoint.Spine0] = "spine0"
             };
 
+        private readonly PropManager propManager;
+        private readonly MeidoManager meidoManager;
+        private readonly Dictionary<AttachPoint, Toggle> toggles = new();
         private readonly Toggle keepWorldPositionToggle;
         private readonly Dropdown meidoDropdown;
+
         private Toggle activeToggle;
         private bool meidoDropdownActive;
         private bool doguDropdownActive;
         private string header;
-        private bool PaneActive => meidoDropdownActive && doguDropdownActive;
-        private Meido SelectedMeido => meidoManager.ActiveMeidoList[meidoDropdown.SelectedItemIndex];
-        private DragPointProp SelectedProp => propManager.CurrentProp;
-        private bool KeepWoldPosition => keepWorldPositionToggle.Value;
+
+        private bool PaneActive =>
+            meidoDropdownActive && doguDropdownActive;
+
+        private Meido SelectedMeido =>
+            meidoManager.ActiveMeidoList[meidoDropdown.SelectedItemIndex];
+
+        private DragPointProp SelectedProp =>
+            propManager.CurrentProp;
+
+        private bool KeepWoldPosition =>
+            keepWorldPositionToggle.Value;
 
         public AttachPropPane(MeidoManager meidoManager, PropManager propManager)
         {
             header = Translation.Get("attachPropPane", "header");
+
             this.propManager = propManager;
             this.meidoManager = meidoManager;
 
@@ -63,17 +72,19 @@ namespace MeidoPhotoStudio.Plugin
                 UpdateToggles();
             };
 
-            meidoDropdown = new Dropdown(new[] { Translation.Get("systemMessage", "noMaids") });
+            meidoDropdown = new(new[] { Translation.Get("systemMessage", "noMaids") });
             meidoDropdown.SelectionChange += (s, a) => UpdateToggles();
 
-            keepWorldPositionToggle = new Toggle(Translation.Get("attachPropPane", "keepWorldPosition"));
+            keepWorldPositionToggle = new(Translation.Get("attachPropPane", "keepWorldPosition"));
 
-            foreach (AttachPoint attachPoint in Enum.GetValues(typeof(AttachPoint)))
+            foreach (var attachPoint in Enum.GetValues(typeof(AttachPoint)).Cast<AttachPoint>())
             {
-                if (attachPoint == AttachPoint.None) continue;
+                if (attachPoint is AttachPoint.None)
+                    continue;
 
                 var point = attachPoint;
                 var toggle = new Toggle(Translation.Get("attachPropPane", toggleTranslation[point]));
+
                 toggle.ControlEvent += (s, a) => OnToggleChange(point);
                 toggles[point] = toggle;
             }
@@ -83,9 +94,11 @@ namespace MeidoPhotoStudio.Plugin
         {
             header = Translation.Get("attachPropPane", "header");
             keepWorldPositionToggle.Label = Translation.Get("attachPropPane", "keepWorldPosition");
-            foreach (AttachPoint attachPoint in Enum.GetValues(typeof(AttachPoint)))
+
+            foreach (var attachPoint in Enum.GetValues(typeof(AttachPoint)).Cast<AttachPoint>())
             {
-                if (attachPoint == AttachPoint.None) continue;
+                if (attachPoint is AttachPoint.None)
+                    continue;
 
                 toggles[attachPoint].Label = Translation.Get("attachPropPane", toggleTranslation[attachPoint]);
             }
@@ -95,9 +108,11 @@ namespace MeidoPhotoStudio.Plugin
         {
             const float dropdownButtonHeight = 30;
             const float dropdownButtonWidth = 153f;
-            GUILayoutOption[] dropdownLayoutOptions =
+
+            var dropdownLayoutOptions = new[]
             {
-                GUILayout.Height(dropdownButtonHeight), GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Height(dropdownButtonHeight),
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             MpsGui.Header(header);
@@ -125,19 +140,24 @@ namespace MeidoPhotoStudio.Plugin
         {
             GUILayout.BeginHorizontal();
             GUILayout.FlexibleSpace();
-            foreach (var point in attachPoints) toggles[point].Draw();
+
+            foreach (var point in attachPoints)
+                toggles[point].Draw();
+
             GUILayout.FlexibleSpace();
             GUILayout.EndHorizontal();
         }
 
         private void OnToggleChange(AttachPoint point)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             var toggle = toggles[point];
+
             if (toggle.Value)
             {
-                if (activeToggle != null)
+                if (activeToggle is not null)
                 {
                     updating = true;
                     activeToggle.Value = false;
@@ -157,18 +177,25 @@ namespace MeidoPhotoStudio.Plugin
         private void UpdateToggles()
         {
             updating = true;
-            if (activeToggle != null) activeToggle.Value = false;
+
+            if (activeToggle is not null)
+                activeToggle.Value = false;
+
             activeToggle = null;
             updating = false;
 
-            if (!meidoManager.HasActiveMeido || propManager.PropCount == 0) return;
+            if (!meidoManager.HasActiveMeido || propManager.PropCount is 0)
+                return;
 
             var info = SelectedProp.AttachPointInfo;
 
-            if (SelectedMeido.Maid.status.guid != info.MaidGuid) return;
+            if (SelectedMeido.Maid.status.guid != info.MaidGuid)
+                return;
 
             updating = true;
+
             var toggle = toggles[info.AttachPoint];
+
             toggle.Value = true;
             activeToggle = toggle;
             updating = false;
@@ -177,7 +204,8 @@ namespace MeidoPhotoStudio.Plugin
         private void SetMeidoDropdown()
         {
             meidoDropdownActive = meidoManager.HasActiveMeido;
-            string[] dropdownList = meidoManager.ActiveMeidoList.Count == 0
+
+            var dropdownList = meidoManager.ActiveMeidoList.Count is 0
                 ? new[] { Translation.Get("systemMessage", "noMaids") }
                 : meidoManager.ActiveMeidoList.Select(meido => $"{meido.Slot + 1}: {meido.FirstName} {meido.LastName}")
                     .ToArray();

+ 79 - 63
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/ModPropsPane.cs

@@ -2,17 +2,21 @@ using System.Collections.Generic;
 using System.Linq;
 using UnityEngine;
 
+using static MeidoPhotoStudio.Plugin.MenuFileUtility;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static MenuFileUtility;
     public class ModPropsPane : BasePane
     {
+        private enum FilterType { None, Mod, Base }
+
         private readonly PropManager propManager;
         private readonly Dropdown propCategoryDropdown;
         private readonly Toggle modFilterToggle;
         private readonly Toggle baseFilterToggle;
+        private readonly bool isModsOnly = PropManager.ModItemsOnly;
+
         private Vector2 propListScrollPos;
-        private string SelectedCategory => MenuCategories[propCategoryDropdown.SelectedItemIndex];
         private List<ModItem> modPropList;
         private string currentCategory;
         private bool modItemsReady;
@@ -21,11 +25,9 @@ namespace MeidoPhotoStudio.Plugin
         private bool modFilter;
         private bool baseFilter;
         private int currentListCount;
-        private readonly bool isModsOnly = PropManager.ModItemsOnly;
-        private enum FilterType
-        {
-            None, Mod, Base
-        }
+
+        private string SelectedCategory =>
+            MenuCategories[propCategoryDropdown.SelectedItemIndex];
 
         public ModPropsPane(PropManager propManager)
         {
@@ -33,7 +35,7 @@ namespace MeidoPhotoStudio.Plugin
 
             modItemsReady = MenuFilesReady || PropManager.ModItemsOnly;
 
-            string[] listItems = Translation.GetArray("clothing", MenuCategories);
+            var listItems = Translation.GetArray("clothing", MenuCategories);
 
             if (!modItemsReady)
             {
@@ -48,47 +50,34 @@ namespace MeidoPhotoStudio.Plugin
                 };
             }
 
-            propCategoryDropdown = new Dropdown(listItems);
-
+            propCategoryDropdown = new(listItems);
             propCategoryDropdown.SelectionChange += (s, a) =>
             {
-                if (!modItemsReady) return;
+                if (!modItemsReady)
+                    return;
+
                 ChangePropCategory();
             };
 
-            if (!isModsOnly)
-            {
-                modFilterToggle = new Toggle(Translation.Get("background2Window", "modsToggle"));
-                modFilterToggle.ControlEvent += (s, a) => ChangeFilter(FilterType.Mod);
-
-                baseFilterToggle = new Toggle(Translation.Get("background2Window", "baseToggle"));
-                baseFilterToggle.ControlEvent += (s, a) => ChangeFilter(FilterType.Base);
-            }
-        }
-
-        protected override void ReloadTranslation()
-        {
-            string[] listItems = Translation.GetArray("clothing", MenuCategories);
-
-            if (!modItemsReady) listItems[0] = Translation.Get("systemMessage", "initializing");
+            if (isModsOnly)
+                return;
 
-            propCategoryDropdown.SetDropdownItems(listItems);
+            modFilterToggle = new(Translation.Get("background2Window", "modsToggle"));
+            modFilterToggle.ControlEvent += (s, a) => ChangeFilter(FilterType.Mod);
 
-            if (!isModsOnly)
-            {
-                modFilterToggle.Label = Translation.Get("background2Window", "modsToggle");
-                baseFilterToggle.Label = Translation.Get("background2Window", "baseToggle");
-            }
+            baseFilterToggle = new(Translation.Get("background2Window", "baseToggle"));
+            baseFilterToggle.ControlEvent += (s, a) => ChangeFilter(FilterType.Base);
         }
 
-        public float buttonSize = 54f;
         public override void Draw()
         {
             const float dropdownButtonHeight = 30f;
-            float dropdownButtonWidth = isModsOnly ? 120f : 90f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownButtonWidth = isModsOnly ? 120f : 90f;
+
+            var dropdownLayoutOptions = new[] {
                 GUILayout.Height(dropdownButtonHeight),
-                GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             GUILayout.BeginHorizontal();
@@ -114,32 +103,39 @@ namespace MeidoPhotoStudio.Plugin
 
             if (shouldDraw)
             {
-                Rect windowRect = parent.WindowRect;
-                float windowHeight = windowRect.height;
-                float windowWidth = windowRect.width;
+                var windowRect = parent.WindowRect;
+                var windowHeight = windowRect.height;
+                var windowWidth = windowRect.width;
 
-                // const float buttonSize = 50f;
                 const float offsetTop = 80f;
                 const int columns = 4;
-                float buttonSize = (windowWidth / columns) - 10f;
 
-                Rect positionRect = new Rect(
+                var buttonSize = windowWidth / columns - 10f;
+
+                var positionRect = new Rect(
                     5f, offsetTop + dropdownButtonHeight, windowWidth - 10f, windowHeight - 145f
                 );
-                Rect viewRect = new Rect(
-                    0f, 0f, buttonSize * columns, (buttonSize * Mathf.Ceil(currentListCount / (float)columns)) + 5
+
+                var viewRect = new Rect(
+                    0f, 0f, buttonSize * columns, buttonSize * Mathf.Ceil(currentListCount / (float)columns) + 5
                 );
+
                 propListScrollPos = GUI.BeginScrollView(positionRect, propListScrollPos, viewRect);
 
-                int modIndex = 0;
-                foreach (ModItem modItem in modPropList)
+                var modIndex = 0;
+
+                foreach (var modItem in modPropList)
                 {
-                    if ((modFilter && !modItem.IsMod) || (baseFilter && modItem.IsMod)) continue;
+                    if (modFilter && !modItem.IsMod || baseFilter && modItem.IsMod)
+                        continue;
+
+                    var x = modIndex % columns * buttonSize;
+                    var y = modIndex / columns * buttonSize;
+                    var iconRect = new Rect(x, y, buttonSize, buttonSize);
+
+                    if (GUI.Button(iconRect, ""))
+                        propManager.AddModProp(modItem);
 
-                    float x = modIndex % columns * buttonSize;
-                    float y = modIndex / columns * buttonSize;
-                    Rect iconRect = new Rect(x, y, buttonSize, buttonSize);
-                    if (GUI.Button(iconRect, "")) propManager.AddModProp(modItem);
                     GUI.DrawTexture(iconRect, modItem.Icon);
                     modIndex++;
                 }
@@ -148,15 +144,32 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
+        protected override void ReloadTranslation()
+        {
+            var listItems = Translation.GetArray("clothing", MenuCategories);
+
+            if (!modItemsReady)
+                listItems[0] = Translation.Get("systemMessage", "initializing");
+
+            propCategoryDropdown.SetDropdownItems(listItems);
+
+            if (isModsOnly)
+                return;
+
+            modFilterToggle.Label = Translation.Get("background2Window", "modsToggle");
+            baseFilterToggle.Label = Translation.Get("background2Window", "baseToggle");
+        }
+
         private void ChangeFilter(FilterType filterType)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             if (modFilterToggle.Value && baseFilterToggle.Value)
             {
                 updating = true;
-                modFilterToggle.Value = filterType == FilterType.Mod;
-                baseFilterToggle.Value = filterType == FilterType.Base;
+                modFilterToggle.Value = filterType is FilterType.Mod;
+                baseFilterToggle.Value = filterType is FilterType.Base;
                 updating = false;
             }
 
@@ -168,16 +181,19 @@ namespace MeidoPhotoStudio.Plugin
 
         private void ChangePropCategory()
         {
-            string category = SelectedCategory;
+            var category = SelectedCategory;
+
+            if (currentCategory == category)
+                return;
 
-            if (currentCategory == category) return;
             currentCategory = category;
 
             categoryIndex = propCategoryDropdown.SelectedItemIndex;
 
             shouldDraw = categoryIndex > 0;
 
-            if (!shouldDraw) return;
+            if (!shouldDraw)
+                return;
 
             propListScrollPos = Vector2.zero;
 
@@ -186,11 +202,11 @@ namespace MeidoPhotoStudio.Plugin
             SetListCount();
         }
 
-        private void SetListCount()
-        {
-            if (modFilter) currentListCount = modPropList.Count(mod => mod.IsMod);
-            else if (baseFilter) currentListCount = modPropList.Count(mod => !mod.IsMod);
-            else currentListCount = modPropList.Count;
-        }
+        private void SetListCount() =>
+            currentListCount = modFilter
+                ? modPropList.Count(mod => mod.IsMod)
+                : baseFilter
+                    ? modPropList.Count(mod => !mod.IsMod)
+                    : modPropList.Count;
     }
 }

+ 39 - 31
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/MyRoomPropsPane.cs

@@ -7,34 +7,32 @@ namespace MeidoPhotoStudio.Plugin
     {
         private readonly PropManager propManager;
         private readonly Dropdown propCategoryDropdown;
+
         private Vector2 propListScrollPos;
-        private string SelectedCategory => Constants.MyRoomPropCategories[propCategoryDropdown.SelectedItemIndex];
         private List<MyRoomItem> myRoomPropList;
         private string currentCategory;
 
+        private string SelectedCategory =>
+            Constants.MyRoomPropCategories[propCategoryDropdown.SelectedItemIndex];
+
         public MyRoomPropsPane(PropManager propManager)
         {
             this.propManager = propManager;
 
-            propCategoryDropdown = new Dropdown(Translation.GetArray("doguCategories", Constants.MyRoomPropCategories));
+            propCategoryDropdown = new(Translation.GetArray("doguCategories", Constants.MyRoomPropCategories));
             propCategoryDropdown.SelectionChange += (s, a) => ChangePropCategory(SelectedCategory);
-            ChangePropCategory(SelectedCategory);
-        }
 
-        protected override void ReloadTranslation()
-        {
-            propCategoryDropdown.SetDropdownItems(
-                Translation.GetArray("doguCategories", Constants.MyRoomPropCategories)
-            );
+            ChangePropCategory(SelectedCategory);
         }
 
         public override void Draw()
         {
             const float dropdownButtonHeight = 30f;
             const float dropdownButtonWidth = 120f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownLayoutOptions = new[] {
                 GUILayout.Height(dropdownButtonHeight),
-                GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             GUILayout.BeginHorizontal();
@@ -43,51 +41,61 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.FlexibleSpace();
             GUILayout.EndHorizontal();
 
-            Rect windowRect = parent.WindowRect;
+            var windowRect = parent.WindowRect;
 
-            float windowHeight = windowRect.height;
-            float windowWidth = windowRect.width;
+            var windowHeight = windowRect.height;
+            var windowWidth = windowRect.width;
 
             const float offsetTop = 80f;
             const int columns = 3;
-            float buttonSize = (windowWidth / columns) - 10f;
 
-            int listCount = myRoomPropList.Count;
+            var buttonSize = windowWidth / columns - 10f;
+
+            var listCount = myRoomPropList.Count;
 
-            Rect positionRect = new Rect(
+            var positionRect = new Rect(
                 5f, offsetTop + dropdownButtonHeight, windowWidth - 10f, windowHeight - 145f
             );
-            Rect viewRect = new Rect(
-                0f, 0f, buttonSize * columns, (buttonSize * Mathf.Ceil(listCount / (float)columns)) + 5f
+
+            var viewRect = new Rect(
+                0f, 0f, buttonSize * columns, buttonSize * Mathf.Ceil(listCount / (float)columns) + 5f
             );
+
             propListScrollPos = GUI.BeginScrollView(positionRect, propListScrollPos, viewRect);
 
-            for (int i = 0; i < listCount; i++)
+            for (var i = 0; i < listCount; i++)
             {
-                float x = i % columns * buttonSize;
-                float y = i / columns * buttonSize;
-                MyRoomItem myRoomItem = myRoomPropList[i];
-                Rect iconRect = new Rect(x, y, buttonSize, buttonSize);
-                if (GUI.Button(iconRect, "")) propManager.AddMyRoomProp(myRoomItem);
+                var x = i % columns * buttonSize;
+                var y = i / columns * buttonSize;
+                var myRoomItem = myRoomPropList[i];
+                var iconRect = new Rect(x, y, buttonSize, buttonSize);
+
+                if (GUI.Button(iconRect, ""))
+                    propManager.AddMyRoomProp(myRoomItem);
+
                 GUI.DrawTexture(iconRect, myRoomItem.Icon);
             }
 
             GUI.EndScrollView();
         }
 
+        protected override void ReloadTranslation() =>
+            propCategoryDropdown.SetDropdownItems(
+                Translation.GetArray("doguCategories", Constants.MyRoomPropCategories)
+            );
+
         private void ChangePropCategory(string category)
         {
-            if (currentCategory == category) return;
+            if (currentCategory == category)
+                return;
+
             currentCategory = category;
             propListScrollPos = Vector2.zero;
             myRoomPropList = Constants.MyRoomPropDict[category];
+
             if (myRoomPropList[0].Icon == null)
-            {
-                foreach (MyRoomItem item in myRoomPropList)
-                {
+                foreach (var item in myRoomPropList)
                     item.Icon = (Texture2D)MyRoomCustom.PlacementData.GetData(item.ID).GetThumbnail();
-                }
-            }
         }
     }
 }

+ 45 - 30
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/PropManagerPane.cs

@@ -13,9 +13,11 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Toggle shadowCastingToggle;
         private readonly Button deletePropButton;
         private readonly Button copyPropButton;
+
         private string propManagerHeader;
 
-        private int CurrentDoguIndex => propManager.CurrentPropIndex;
+        private int CurrentDoguIndex =>
+            propManager.CurrentPropIndex;
 
         public PropManagerPane(PropManager propManager)
         {
@@ -34,72 +36,73 @@ namespace MeidoPhotoStudio.Plugin
                 UpdateToggles();
             };
 
-            propDropdown = new Dropdown(this.propManager.PropNameList);
+            propDropdown = new(this.propManager.PropNameList);
             propDropdown.SelectionChange += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 this.propManager.CurrentPropIndex = propDropdown.SelectedItemIndex;
+
                 UpdateToggles();
             };
 
-            previousPropButton = new Button("<");
+            previousPropButton = new("<");
             previousPropButton.ControlEvent += (s, a) => propDropdown.Step(-1);
 
-            nextPropButton = new Button(">");
+            nextPropButton = new(">");
             nextPropButton.ControlEvent += (s, a) => propDropdown.Step(1);
 
-            dragPointToggle = new Toggle(Translation.Get("propManagerPane", "dragPointToggle"));
+            dragPointToggle = new(Translation.Get("propManagerPane", "dragPointToggle"));
             dragPointToggle.ControlEvent += (s, a) =>
             {
-                if (updating || this.propManager.PropCount == 0) return;
+                if (updating || this.propManager.PropCount == 0)
+                    return;
+
                 this.propManager.CurrentProp.DragPointEnabled = dragPointToggle.Value;
             };
 
-            gizmoToggle = new Toggle(Translation.Get("propManagerPane", "gizmoToggle"));
+            gizmoToggle = new(Translation.Get("propManagerPane", "gizmoToggle"));
             gizmoToggle.ControlEvent += (s, a) =>
             {
-                if (updating || this.propManager.PropCount == 0) return;
+                if (updating || this.propManager.PropCount == 0)
+                    return;
+
                 this.propManager.CurrentProp.GizmoEnabled = gizmoToggle.Value;
             };
 
-            shadowCastingToggle = new Toggle(Translation.Get("propManagerPane", "shadowCastingToggle"));
+            shadowCastingToggle = new(Translation.Get("propManagerPane", "shadowCastingToggle"));
             shadowCastingToggle.ControlEvent += (s, a) =>
             {
-                if (updating || this.propManager.PropCount == 0) return;
+                if (updating || this.propManager.PropCount == 0)
+                    return;
+
                 this.propManager.CurrentProp.ShadowCasting = shadowCastingToggle.Value;
             };
 
-            copyPropButton = new Button(Translation.Get("propManagerPane", "copyButton"));
+            copyPropButton = new(Translation.Get("propManagerPane", "copyButton"));
             copyPropButton.ControlEvent += (s, a) => this.propManager.CopyProp(CurrentDoguIndex);
 
-            deletePropButton = new Button(Translation.Get("propManagerPane", "deleteButton"));
+            deletePropButton = new(Translation.Get("propManagerPane", "deleteButton"));
             deletePropButton.ControlEvent += (s, a) => this.propManager.RemoveProp(CurrentDoguIndex);
 
             propManagerHeader = Translation.Get("propManagerPane", "header");
         }
 
-        protected override void ReloadTranslation()
-        {
-            dragPointToggle.Label = Translation.Get("propManagerPane", "dragPointToggle");
-            gizmoToggle.Label = Translation.Get("propManagerPane", "gizmoToggle");
-            shadowCastingToggle.Label = Translation.Get("propManagerPane", "shadowCastingToggle");
-            copyPropButton.Label = Translation.Get("propManagerPane", "copyButton");
-            deletePropButton.Label = Translation.Get("propManagerPane", "deleteButton");
-            propManagerHeader = Translation.Get("propManagerPane", "header");
-        }
-
         public override void Draw()
         {
             const float buttonHeight = 30;
-            GUILayoutOption[] arrowLayoutOptions = {
+
+            var arrowLayoutOptions = new[] {
                 GUILayout.Width(buttonHeight),
-                GUILayout.Height(buttonHeight)
+                GUILayout.Height(buttonHeight),
             };
 
             const float dropdownButtonWidth = 140f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownLayoutOptions = new[] {
                 GUILayout.Height(buttonHeight),
-                GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             MpsGui.Header(propManagerHeader);
@@ -113,7 +116,7 @@ namespace MeidoPhotoStudio.Plugin
             nextPropButton.Draw(arrowLayoutOptions);
             GUILayout.EndHorizontal();
 
-            GUILayoutOption noExpandWidth = GUILayout.ExpandWidth(false);
+            var noExpandWidth = GUILayout.ExpandWidth(false);
 
             GUILayout.BeginHorizontal();
             dragPointToggle.Draw(noExpandWidth);
@@ -129,6 +132,16 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            dragPointToggle.Label = Translation.Get("propManagerPane", "dragPointToggle");
+            gizmoToggle.Label = Translation.Get("propManagerPane", "gizmoToggle");
+            shadowCastingToggle.Label = Translation.Get("propManagerPane", "shadowCastingToggle");
+            copyPropButton.Label = Translation.Get("propManagerPane", "copyButton");
+            deletePropButton.Label = Translation.Get("propManagerPane", "deleteButton");
+            propManagerHeader = Translation.Get("propManagerPane", "header");
+        }
+
         private void UpdatePropList()
         {
             updating = true;
@@ -138,8 +151,10 @@ namespace MeidoPhotoStudio.Plugin
 
         private void UpdateToggles()
         {
-            DragPointProp prop = propManager.CurrentProp;
-            if (prop == null) return;
+            var prop = propManager.CurrentProp;
+
+            if (prop == null)
+                return;
 
             updating = true;
             dragPointToggle.Value = prop.DragPointEnabled;

+ 50 - 45
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindow2Panes/PropsPane.cs

@@ -1,14 +1,14 @@
-using UnityEngine;
 using System.Collections.Generic;
 using System.Linq;
+using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public class PropsPane : BasePane
     {
+        private static bool handItemsReady;
+
         private readonly PropManager propManager;
-        private string currentCategory;
-        private string SelectedCategory => Constants.DoguCategories[doguCategoryDropdown.SelectedItemIndex];
         private readonly Dropdown doguCategoryDropdown;
         private readonly Dropdown doguDropdown;
         private readonly Button addDoguButton;
@@ -16,70 +16,59 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Button prevDoguButton;
         private readonly Button nextDoguCategoryButton;
         private readonly Button prevDoguCategoryButton;
-        private static bool handItemsReady;
+
+        private string currentCategory;
         private bool itemSelectorEnabled = true;
 
+        private string SelectedCategory =>
+            Constants.DoguCategories[doguCategoryDropdown.SelectedItemIndex];
+
         public PropsPane(PropManager propManager)
         {
             this.propManager = propManager;
 
             handItemsReady = Constants.HandItemsInitialized;
-            if (!handItemsReady) Constants.MenuFilesChange += InitializeHandItems;
 
-            doguCategoryDropdown = new Dropdown(Translation.GetArray("doguCategories", Constants.DoguCategories));
+            if (!handItemsReady)
+                Constants.MenuFilesChange += InitializeHandItems;
+
+            doguCategoryDropdown = new(Translation.GetArray("doguCategories", Constants.DoguCategories));
             doguCategoryDropdown.SelectionChange += (s, a) => ChangeDoguCategory(SelectedCategory);
 
-            doguDropdown = new Dropdown(new[] { string.Empty });
+            doguDropdown = new(new[] { string.Empty });
 
-            addDoguButton = new Button("+");
+            addDoguButton = new("+");
             addDoguButton.ControlEvent += (s, a) => SpawnObject();
 
-            nextDoguButton = new Button(">");
+            nextDoguButton = new(">");
             nextDoguButton.ControlEvent += (s, a) => doguDropdown.Step(1);
 
-            prevDoguButton = new Button("<");
+            prevDoguButton = new("<");
             prevDoguButton.ControlEvent += (s, a) => doguDropdown.Step(-1);
 
-            nextDoguCategoryButton = new Button(">");
+            nextDoguCategoryButton = new(">");
             nextDoguCategoryButton.ControlEvent += (s, a) => doguCategoryDropdown.Step(1);
 
-            prevDoguCategoryButton = new Button("<");
+            prevDoguCategoryButton = new("<");
             prevDoguCategoryButton.ControlEvent += (s, a) => doguCategoryDropdown.Step(-1);
 
             ChangeDoguCategory(SelectedCategory);
         }
 
-        protected override void ReloadTranslation()
-        {
-            doguCategoryDropdown.SetDropdownItems(
-                Translation.GetArray("doguCategories", Constants.DoguCategories)
-            );
-
-            string category = SelectedCategory;
-
-            string[] translationArray;
-
-            if (category == Constants.customDoguCategories[Constants.DoguCategory.HandItem] && !handItemsReady)
-            {
-                translationArray = new[] { Translation.Get("systemMessage", "initializing") };
-            }
-            else translationArray = GetTranslations(category);
-
-            doguDropdown.SetDropdownItems(translationArray);
-        }
-
         public override void Draw()
         {
             const float buttonHeight = 30;
-            GUILayoutOption[] arrowLayoutOptions = {
+
+            var arrowLayoutOptions = new[] {
                 GUILayout.Width(buttonHeight),
-                GUILayout.Height(buttonHeight)
+                GUILayout.Height(buttonHeight),
             };
 
             const float dropdownButtonWidth = 120f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownLayoutOptions = new[] {
                 GUILayout.Height(buttonHeight),
-                GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             GUILayout.BeginHorizontal();
@@ -98,16 +87,31 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            doguCategoryDropdown.SetDropdownItems(
+                Translation.GetArray("doguCategories", Constants.DoguCategories)
+            );
+
+            var category = SelectedCategory;
+
+            var translationArray =
+                category == Constants.customDoguCategories[Constants.DoguCategory.HandItem] && !handItemsReady
+                    ? new[] { Translation.Get("systemMessage", "initializing") }
+                    : GetTranslations(category);
+
+            doguDropdown.SetDropdownItems(translationArray);
+        }
+
         private void InitializeHandItems(object sender, MenuFilesEventArgs args)
         {
             if (args.Type == MenuFilesEventArgs.EventType.HandItems)
             {
                 handItemsReady = true;
-                string selectedCategory = SelectedCategory;
+                var selectedCategory = SelectedCategory;
+
                 if (selectedCategory == Constants.customDoguCategories[Constants.DoguCategory.HandItem])
-                {
                     ChangeDoguCategory(selectedCategory, true);
-                }
             }
         }
 
@@ -129,6 +133,7 @@ namespace MeidoPhotoStudio.Plugin
                     translationArray = GetTranslations(category);
                     itemSelectorEnabled = true;
                 }
+
                 doguDropdown.SetDropdownItems(translationArray, 0);
             }
         }
@@ -136,16 +141,19 @@ namespace MeidoPhotoStudio.Plugin
         private string[] GetTranslations(string category)
         {
             IEnumerable<string> itemList = Constants.DoguDict[category];
+
             if (category == Constants.customDoguCategories[Constants.DoguCategory.HandItem])
             {
+                // TODO: itemList should not be reused
                 itemList = itemList.Select(item =>
                 {
-                    string handItemAsOdogu = Utility.HandItemToOdogu(item);
+                    var handItemAsOdogu = Utility.HandItemToOdogu(item);
+
                     return Translation.Has("propNames", handItemAsOdogu) ? handItemAsOdogu : item;
                 });
             }
 
-            string translationCategory = category == Constants.customDoguCategories[Constants.DoguCategory.BGSmall]
+            var translationCategory = category == Constants.customDoguCategories[Constants.DoguCategory.BGSmall]
                 ? "bgNames"
                 : "propNames";
 
@@ -154,15 +162,12 @@ namespace MeidoPhotoStudio.Plugin
 
         private void SpawnObject()
         {
-            string assetName = Constants.DoguDict[SelectedCategory][doguDropdown.SelectedItemIndex];
+            var assetName = Constants.DoguDict[SelectedCategory][doguDropdown.SelectedItemIndex];
+
             if (SelectedCategory == Constants.customDoguCategories[Constants.DoguCategory.BGSmall])
-            {
                 propManager.AddBgProp(assetName);
-            }
             else
-            {
                 propManager.AddGameProp(assetName);
-            }
         }
     }
 }

+ 30 - 28
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/BackgroundSelectorPane.cs

@@ -1,6 +1,6 @@
-using UnityEngine;
-using System.Linq;
 using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -15,47 +15,35 @@ namespace MeidoPhotoStudio.Plugin
         {
             this.environmentManager = environmentManager;
 
-            int theaterIndex = Constants.BGList.FindIndex(bg => bg == EnvironmentManager.defaultBg);
+            var theaterIndex = Constants.BGList.FindIndex(bg => bg == EnvironmentManager.defaultBg);
+
+            var bgList = new List<string>(Translation.GetList("bgNames", Constants.BGList));
 
-            List<string> bgList = new List<string>(Translation.GetList("bgNames", Constants.BGList));
             if (Constants.MyRoomCustomBGIndex >= 0)
-            {
                 bgList.AddRange(Constants.MyRoomCustomBGList.Select(kvp => kvp.Value));
-            }
 
-            bgDropdown = new Dropdown(bgList.ToArray(), theaterIndex);
+            bgDropdown = new(bgList.ToArray(), theaterIndex);
             bgDropdown.SelectionChange += (s, a) => ChangeBackground();
 
-            prevBGButton = new Button("<");
+            prevBGButton = new("<");
             prevBGButton.ControlEvent += (s, a) => bgDropdown.Step(-1);
 
-            nextBGButton = new Button(">");
+            nextBGButton = new(">");
             nextBGButton.ControlEvent += (s, a) => bgDropdown.Step(1);
         }
 
-        protected override void ReloadTranslation()
-        {
-            List<string> bgList = new List<string>(Translation.GetList("bgNames", Constants.BGList));
-            if (Constants.MyRoomCustomBGIndex >= 0)
-            {
-                bgList.AddRange(Constants.MyRoomCustomBGList.Select(kvp => kvp.Value));
-            }
-
-            updating = true;
-            bgDropdown.SetDropdownItems(bgList.ToArray());
-            updating = false;
-        }
-
         public override void Draw()
         {
             const float buttonHeight = 30;
-            GUILayoutOption[] arrowLayoutOptions = {
+
+            var arrowLayoutOptions = new[] {
                 GUILayout.Width(buttonHeight),
                 GUILayout.Height(buttonHeight)
             };
 
             const float dropdownButtonWidth = 153f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownLayoutOptions = new[] {
                 GUILayout.Height(buttonHeight),
                 GUILayout.Width(dropdownButtonWidth)
             };
@@ -67,12 +55,26 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.EndHorizontal();
         }
 
+        protected override void ReloadTranslation()
+        {
+            var bgList = new List<string>(Translation.GetList("bgNames", Constants.BGList));
+
+            if (Constants.MyRoomCustomBGIndex >= 0)
+                bgList.AddRange(Constants.MyRoomCustomBGList.Select(kvp => kvp.Value));
+
+            updating = true;
+            bgDropdown.SetDropdownItems(bgList.ToArray());
+            updating = false;
+        }
+
         private void ChangeBackground()
         {
-            if (updating) return;
-            int selectedIndex = bgDropdown.SelectedItemIndex;
-            bool isCreative = bgDropdown.SelectedItemIndex >= Constants.MyRoomCustomBGIndex;
-            string bg = isCreative
+            if (updating)
+                return;
+
+            var selectedIndex = bgDropdown.SelectedItemIndex;
+            var isCreative = bgDropdown.SelectedItemIndex >= Constants.MyRoomCustomBGIndex;
+            var bg = isCreative
                 ? Constants.MyRoomCustomBGList[selectedIndex - Constants.MyRoomCustomBGIndex].Key
                 : Constants.BGList[selectedIndex];
 

+ 35 - 20
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/CameraPane.cs

@@ -1,4 +1,4 @@
-using System.Linq;
+using System.Linq;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
@@ -9,6 +9,7 @@ namespace MeidoPhotoStudio.Plugin
         private readonly SelectionGrid cameraGrid;
         private readonly Slider zRotationSlider;
         private readonly Slider fovSlider;
+
         private string header;
 
         public CameraPane(CameraManager cameraManager)
@@ -16,50 +17,57 @@ namespace MeidoPhotoStudio.Plugin
             this.cameraManager = cameraManager;
             this.cameraManager.CameraChange += (s, a) => UpdatePane();
 
-            Camera camera = CameraUtility.MainCamera.camera;
-            Vector3 eulerAngles = camera.transform.eulerAngles;
+            var camera = CameraUtility.MainCamera.camera;
+            var eulerAngles = camera.transform.eulerAngles;
 
-            zRotationSlider = new Slider(Translation.Get("cameraPane", "zRotation"), 0f, 360f, eulerAngles.z)
+            zRotationSlider = new(Translation.Get("cameraPane", "zRotation"), 0f, 360f, eulerAngles.z)
             {
-                HasReset = true, HasTextField = true
+                HasReset = true,
+                HasTextField = true
             };
+
             zRotationSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
-                Vector3 newRotation = camera.transform.eulerAngles;
+                if (updating)
+                    return;
+
+                var newRotation = camera.transform.eulerAngles;
+
                 newRotation.z = zRotationSlider.Value;
                 camera.transform.rotation = Quaternion.Euler(newRotation);
             };
 
             var fieldOfView = camera.fieldOfView;
-            fovSlider = new Slider(Translation.Get("cameraPane", "fov"), 20f, 150f, fieldOfView, fieldOfView)
+
+            fovSlider = new(Translation.Get("cameraPane", "fov"), 20f, 150f, fieldOfView, fieldOfView)
             {
-                HasReset = true, HasTextField = true
+                HasReset = true,
+                HasTextField = true
             };
+
             fovSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 camera.fieldOfView = fovSlider.Value;
             };
-            cameraGrid = new SelectionGrid(
+
+            cameraGrid = new(
                 Enumerable.Range(1, cameraManager.CameraCount).Select(x => x.ToString()).ToArray()
             );
+
             cameraGrid.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 cameraManager.CurrentCameraIndex = cameraGrid.SelectedItemIndex;
             };
 
             header = Translation.Get("cameraPane", "header");
         }
 
-        protected override void ReloadTranslation()
-        {
-            zRotationSlider.Label = Translation.Get("cameraPane", "zRotation");
-            fovSlider.Label = Translation.Get("cameraPane", "fov");
-            header = Translation.Get("cameraPane", "header");
-        }
-
         public override void Draw()
         {
             MpsGui.Header(header);
@@ -73,7 +81,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             updating = true;
 
-            Camera camera = CameraUtility.MainCamera.camera;
+            var camera = CameraUtility.MainCamera.camera;
 
             zRotationSlider.Value = camera.transform.eulerAngles.z;
             fovSlider.Value = camera.fieldOfView;
@@ -82,5 +90,12 @@ namespace MeidoPhotoStudio.Plugin
 
             updating = false;
         }
+
+        protected override void ReloadTranslation()
+        {
+            zRotationSlider.Label = Translation.Get("cameraPane", "zRotation");
+            fovSlider.Label = Translation.Get("cameraPane", "fov");
+            header = Translation.Get("cameraPane", "header");
+        }
     }
 }

+ 22 - 18
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/DragPointPane.cs

@@ -4,37 +4,30 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class DragPointPane : BasePane
     {
-        private string header;
+        private enum Setting { Prop, Maid, Background, Size }
+
         private readonly Toggle propsCubeToggle;
         private readonly Toggle smallCubeToggle;
         private readonly Toggle maidCubeToggle;
         private readonly Toggle bgCubeToggle;
-        private enum Setting
-        {
-            Prop, Maid, Background, Size
-        }
+
+        private string header;
 
         public DragPointPane()
         {
             header = Translation.Get("movementCube", "header");
-            propsCubeToggle = new Toggle(Translation.Get("movementCube", "props"), PropManager.CubeActive);
-            smallCubeToggle = new Toggle(Translation.Get("movementCube", "small"));
-            maidCubeToggle = new Toggle(Translation.Get("movementCube", "maid"), MeidoDragPointManager.CubeActive);
-            bgCubeToggle = new Toggle(Translation.Get("movementCube", "bg"), EnvironmentManager.CubeActive);
 
+            propsCubeToggle = new(Translation.Get("movementCube", "props"), PropManager.CubeActive);
             propsCubeToggle.ControlEvent += (s, a) => ChangeDragPointSetting(Setting.Prop, propsCubeToggle.Value);
+
+            smallCubeToggle = new(Translation.Get("movementCube", "small"));
             smallCubeToggle.ControlEvent += (s, a) => ChangeDragPointSetting(Setting.Size, smallCubeToggle.Value);
+
+            maidCubeToggle = new(Translation.Get("movementCube", "maid"), MeidoDragPointManager.CubeActive);
             maidCubeToggle.ControlEvent += (s, a) => ChangeDragPointSetting(Setting.Maid, maidCubeToggle.Value);
-            bgCubeToggle.ControlEvent += (s, a) => ChangeDragPointSetting(Setting.Background, bgCubeToggle.Value);
-        }
 
-        protected override void ReloadTranslation()
-        {
-            header = Translation.Get("movementCube", "header");
-            propsCubeToggle.Label = Translation.Get("movementCube", "props");
-            smallCubeToggle.Label = Translation.Get("movementCube", "small");
-            maidCubeToggle.Label = Translation.Get("movementCube", "maid");
-            bgCubeToggle.Label = Translation.Get("movementCube", "bg");
+            bgCubeToggle = new(Translation.Get("movementCube", "bg"), EnvironmentManager.CubeActive);
+            bgCubeToggle.ControlEvent += (s, a) => ChangeDragPointSetting(Setting.Background, bgCubeToggle.Value);
         }
 
         public override void Draw()
@@ -50,6 +43,15 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.EndHorizontal();
         }
 
+        protected override void ReloadTranslation()
+        {
+            header = Translation.Get("movementCube", "header");
+            propsCubeToggle.Label = Translation.Get("movementCube", "props");
+            smallCubeToggle.Label = Translation.Get("movementCube", "small");
+            maidCubeToggle.Label = Translation.Get("movementCube", "maid");
+            bgCubeToggle.Label = Translation.Get("movementCube", "bg");
+        }
+
         private void ChangeDragPointSetting(Setting setting, bool value)
         {
             switch (setting)
@@ -68,6 +70,8 @@ namespace MeidoPhotoStudio.Plugin
                     EnvironmentManager.CubeSmall = value;
                     PropManager.CubeSmall = value;
                     break;
+                default:
+                    break;
             }
         }
     }

+ 36 - 14
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/BloomPane.cs

@@ -4,7 +4,6 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class BloomPane : EffectPane<BloomEffectManager>
     {
-        protected override BloomEffectManager EffectManager { get; set; }
         private readonly Slider intensitySlider;
         private readonly Slider blurSlider;
         private readonly Slider redSlider;
@@ -12,50 +11,73 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Slider blueSlider;
         private readonly Toggle hdrToggle;
 
+        protected override BloomEffectManager EffectManager { get; set; }
+
         public BloomPane(EffectManager effectManager) : base(effectManager)
         {
-            intensitySlider = new Slider(
+            intensitySlider = new(
                 Translation.Get("effectBloom", "intensity"), 0f, 100f, EffectManager.BloomValue
             );
+
             intensitySlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BloomValue = intensitySlider.Value;
             };
-            blurSlider = new Slider(Translation.Get("effectBloom", "blur"), 0f, 15f, EffectManager.BlurIterations);
+
+            blurSlider = new(Translation.Get("effectBloom", "blur"), 0f, 15f, EffectManager.BlurIterations);
             blurSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BlurIterations = (int)blurSlider.Value;
             };
-            redSlider = new Slider(
+
+            redSlider = new(
                 Translation.Get("backgroundWindow", "red"), 1f, 0.5f, EffectManager.BloomThresholdColorRed
             );
+
             redSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BloomThresholdColorRed = redSlider.Value;
             };
-            greenSlider = new Slider(
+
+            greenSlider = new(
                 Translation.Get("backgroundWindow", "green"), 1f, 0.5f, EffectManager.BloomThresholdColorGreen
             );
+
             greenSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BloomThresholdColorGreen = greenSlider.Value;
             };
-            blueSlider = new Slider(
+
+            blueSlider = new(
                 Translation.Get("backgroundWindow", "blue"), 1f, 0.5f, EffectManager.BloomThresholdColorBlue
             );
+
             blueSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BloomThresholdColorBlue = blueSlider.Value;
             };
-            hdrToggle = new Toggle(Translation.Get("effectBloom", "hdrToggle"), EffectManager.BloomHDR);
+
+            hdrToggle = new(Translation.Get("effectBloom", "hdrToggle"), EffectManager.BloomHDR);
             hdrToggle.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BloomHDR = hdrToggle.Value;
             };
         }
@@ -82,7 +104,7 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void DrawPane()
         {
-            GUILayoutOption sliderWidth = MpsGui.HalfSlider;
+            var sliderWidth = MpsGui.HalfSlider;
 
             GUILayout.BeginHorizontal();
             intensitySlider.Draw(sliderWidth);

+ 28 - 12
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/DepthOfFieldPane.cs

@@ -4,45 +4,61 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class DepthOfFieldPane : EffectPane<DepthOfFieldEffectManager>
     {
-        protected override DepthOfFieldEffectManager EffectManager { get; set; }
         private readonly Slider focalLengthSlider;
         private readonly Slider focalSizeSlider;
         private readonly Slider apertureSlider;
         private readonly Slider blurSlider;
         private readonly Toggle thicknessToggle;
 
+        protected override DepthOfFieldEffectManager EffectManager { get; set; }
+
         public DepthOfFieldPane(EffectManager effectManager) : base(effectManager)
         {
-            focalLengthSlider = new Slider(
+            focalLengthSlider = new(
                 Translation.Get("effectDof", "focalLength"), 0f, 10f, EffectManager.FocalLength
             );
-            focalSizeSlider = new Slider(Translation.Get("effectDof", "focalArea"), 0f, 2f, EffectManager.FocalSize);
-            apertureSlider = new Slider(Translation.Get("effectDof", "aperture"), 0f, 60f, EffectManager.Aperture);
-            blurSlider = new Slider(Translation.Get("effectDof", "blur"), 0f, 10f, EffectManager.MaxBlurSize);
-            thicknessToggle = new Toggle(Translation.Get("effectDof", "thicknessToggle"), EffectManager.VisualizeFocus);
+
             focalLengthSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.FocalLength = focalLengthSlider.Value;
             };
+
+            focalSizeSlider = new(Translation.Get("effectDof", "focalArea"), 0f, 2f, EffectManager.FocalSize);
             focalSizeSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.FocalSize = focalSizeSlider.Value;
             };
+
+            apertureSlider = new(Translation.Get("effectDof", "aperture"), 0f, 60f, EffectManager.Aperture);
             apertureSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.Aperture = apertureSlider.Value;
             };
+
+            blurSlider = new(Translation.Get("effectDof", "blur"), 0f, 10f, EffectManager.MaxBlurSize);
             blurSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.MaxBlurSize = blurSlider.Value;
             };
+
+            thicknessToggle = new(Translation.Get("effectDof", "thicknessToggle"), EffectManager.VisualizeFocus);
             thicknessToggle.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.VisualizeFocus = thicknessToggle.Value;
             };
         }
@@ -69,7 +85,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             focalLengthSlider.Draw();
 
-            GUILayoutOption sliderWidth = MpsGui.HalfSlider;
+            var sliderWidth = MpsGui.HalfSlider;
 
             GUILayout.BeginHorizontal();
             focalSizeSlider.Draw(sliderWidth);

+ 27 - 17
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/EffectPane.cs

@@ -4,17 +4,23 @@ namespace MeidoPhotoStudio.Plugin
 {
     public abstract class EffectPane<T> : BasePane where T : IEffectManager
     {
-        protected abstract T EffectManager { get; set; }
         protected readonly Toggle effectToggle;
         protected readonly Button resetEffectButton;
+
+        protected abstract T EffectManager { get; set; }
+
         private bool enabled;
+
         public override bool Enabled
         {
             get => enabled;
             set
             {
                 enabled = value;
-                if (updating) return;
+
+                if (updating)
+                    return;
+
                 EffectManager.SetEffectActive(enabled);
             }
         }
@@ -22,34 +28,31 @@ namespace MeidoPhotoStudio.Plugin
         protected EffectPane(EffectManager effectManager)
         {
             EffectManager = effectManager.Get<T>();
-            resetEffectButton = new Button(Translation.Get("effectsPane", "reset"));
+
+            resetEffectButton = new(Translation.Get("effectsPane", "reset"));
             resetEffectButton.ControlEvent += (s, a) => ResetEffect();
-            effectToggle = new Toggle(Translation.Get("effectsPane", "onToggle"));
-            effectToggle.ControlEvent += (s, a) => Enabled = effectToggle.Value;
-        }
 
-        protected override void ReloadTranslation()
-        {
-            updating = true;
-            effectToggle.Label = Translation.Get("effectsPane", "onToggle");
-            resetEffectButton.Label = Translation.Get("effectsPane", "reset");
-            TranslatePane();
-            updating = false;
+            effectToggle = new(Translation.Get("effectsPane", "onToggle"));
+            effectToggle.ControlEvent += (s, a) => Enabled = effectToggle.Value;
         }
 
         protected abstract void TranslatePane();
 
+        protected abstract void UpdateControls();
+
+        protected abstract void DrawPane();
+
         public override void UpdatePane()
         {
-            if (!EffectManager.Ready) return;
+            if (!EffectManager.Ready)
+                return;
+
             updating = true;
             effectToggle.Value = EffectManager.Active;
             UpdateControls();
             updating = false;
         }
 
-        protected abstract void UpdateControls();
-
         public override void Draw()
         {
             GUILayout.BeginHorizontal();
@@ -62,7 +65,14 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
-        protected abstract void DrawPane();
+        protected override void ReloadTranslation()
+        {
+            updating = true;
+            effectToggle.Label = Translation.Get("effectsPane", "onToggle");
+            resetEffectButton.Label = Translation.Get("effectsPane", "reset");
+            TranslatePane();
+            updating = false;
+        }
 
         private void ResetEffect()
         {

+ 14 - 14
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/EffectsPane.cs

@@ -4,9 +4,10 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class EffectsPane : BasePane
     {
-        private readonly Dictionary<string, BasePane> effectPanes = new Dictionary<string, BasePane>();
-        private readonly List<string> effectList = new List<string>();
+        private readonly Dictionary<string, BasePane> effectPanes = new();
+        private readonly List<string> effectList = new();
         private readonly SelectionGrid effectToggles;
+
         private BasePane currentEffectPane;
 
         public BasePane this[string effectUI]
@@ -22,22 +23,12 @@ namespace MeidoPhotoStudio.Plugin
 
         public EffectsPane()
         {
-            effectToggles = new SelectionGrid(new[] { "dummy" /* thicc */ });
+            effectToggles = new(new[] { "dummy" /* thicc */ });
             effectToggles.ControlEvent += (s, a) => SetEffectPane(effectList[effectToggles.SelectedItemIndex]);
         }
 
-        protected override void ReloadTranslation()
-        {
-            effectToggles.SetItems(Translation.GetArray("effectsPane", effectList));
-        }
-
-        private void SetEffectPane(string effectUI)
-        {
-            currentEffectPane = effectPanes[effectUI];
+        public override void UpdatePane() =>
             currentEffectPane.UpdatePane();
-        }
-
-        public override void UpdatePane() => currentEffectPane.UpdatePane();
 
         public override void Draw()
         {
@@ -47,5 +38,14 @@ namespace MeidoPhotoStudio.Plugin
             MpsGui.BlackLine();
             currentEffectPane.Draw();
         }
+
+        protected override void ReloadTranslation() =>
+            effectToggles.SetItems(Translation.GetArray("effectsPane", effectList));
+
+        private void SetEffectPane(string effectUI)
+        {
+            currentEffectPane = effectPanes[effectUI];
+            currentEffectPane.UpdatePane();
+        }
     }
 }

+ 49 - 23
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/FogPane.cs

@@ -4,7 +4,6 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class FogPane : EffectPane<FogEffectManager>
     {
-        protected override FogEffectManager EffectManager { get; set; }
         private readonly Slider distanceSlider;
         private readonly Slider densitySlider;
         private readonly Slider heightScaleSlider;
@@ -13,57 +12,84 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Slider greenSlider;
         private readonly Slider blueSlider;
 
+        protected override FogEffectManager EffectManager { get; set; }
+
         public FogPane(EffectManager effectManager) : base(effectManager)
         {
-            distanceSlider = new Slider(
+            distanceSlider = new(
                 Translation.Get("effectFog", "distance"), 0f, 30f, EffectManager.Distance
             );
-            densitySlider = new Slider(
-                Translation.Get("effectFog", "density"), 0f, 10f, EffectManager.Density
-            );
-            heightScaleSlider = new Slider(
-                Translation.Get("effectFog", "strength"), -5f, 20f, EffectManager.HeightScale
-            );
-            heightSlider = new Slider(
-                Translation.Get("effectFog", "height"), -10f, 10f, EffectManager.Height
-            );
-            Color initialFogColour = EffectManager.FogColour;
-            redSlider = new Slider(Translation.Get("backgroundWIndow", "red"), 0f, 1f, initialFogColour.r);
-            greenSlider = new Slider(Translation.Get("backgroundWIndow", "green"), 0f, 1f, initialFogColour.g);
-            blueSlider = new Slider(Translation.Get("backgroundWIndow", "blue"), 0f, 1f, initialFogColour.b);
+
             distanceSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.Distance = distanceSlider.Value;
             };
+
+            densitySlider = new(
+                Translation.Get("effectFog", "density"), 0f, 10f, EffectManager.Density
+            );
+
             densitySlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.Density = densitySlider.Value;
             };
+
+            heightScaleSlider = new(
+                Translation.Get("effectFog", "strength"), -5f, 20f, EffectManager.HeightScale
+            );
+
             heightScaleSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.HeightScale = heightScaleSlider.Value;
             };
+
+            heightSlider = new(
+                Translation.Get("effectFog", "height"), -10f, 10f, EffectManager.Height
+            );
+
             heightSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.Height = heightSlider.Value;
             };
+
+            var initialFogColour = EffectManager.FogColour;
+
+            redSlider = new(Translation.Get("backgroundWIndow", "red"), 0f, 1f, initialFogColour.r);
             redSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.FogColourRed = redSlider.Value;
             };
+
+            greenSlider = new(Translation.Get("backgroundWIndow", "green"), 0f, 1f, initialFogColour.g);
             greenSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.FogColourGreen = greenSlider.Value;
             };
+
+            blueSlider = new(Translation.Get("backgroundWIndow", "blue"), 0f, 1f, initialFogColour.b);
             blueSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.FogColourBlue = blueSlider.Value;
             };
         }
@@ -92,7 +118,7 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void DrawPane()
         {
-            GUILayoutOption sliderWidth = MpsGui.HalfSlider;
+            var sliderWidth = MpsGui.HalfSlider;
 
             GUILayout.BeginHorizontal();
             distanceSlider.Draw(sliderWidth);

+ 4 - 3
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/OtherEffectsPane.cs

@@ -17,14 +17,15 @@ namespace MeidoPhotoStudio.Plugin
             sepiaToneEffectManger = this.effectManager.Get<SepiaToneEffectManger>();
             blurEffectManager = this.effectManager.Get<BlurEffectManager>();
 
-            sepiaToggle = new Toggle(Translation.Get("otherEffectsPane", "sepiaToggle"));
+            sepiaToggle = new(Translation.Get("otherEffectsPane", "sepiaToggle"));
             sepiaToggle.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
                 sepiaToneEffectManger.SetEffectActive(sepiaToggle.Value);
             };
 
-            blurSlider = new Slider(Translation.Get("otherEffectsPane", "blurSlider"), 0f, 18f);
+            blurSlider = new(Translation.Get("otherEffectsPane", "blurSlider"), 0f, 18f);
             blurSlider.ControlEvent += (s, a) =>
             {
                 if (updating)

+ 22 - 10
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/EffectsPanes/VignettePane.cs

@@ -4,36 +4,48 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class VignettePane : EffectPane<VignetteEffectManager>
     {
-        protected override VignetteEffectManager EffectManager { get; set; }
         private readonly Slider intensitySlider;
         private readonly Slider blurSlider;
         private readonly Slider blurSpreadSlider;
         private readonly Slider aberrationSlider;
 
+        protected override VignetteEffectManager EffectManager { get; set; }
+
         public VignettePane(EffectManager effectManager) : base(effectManager)
         {
-            intensitySlider = new Slider(Translation.Get("effectVignette", "intensity"), -40f, 70f);
+            intensitySlider = new(Translation.Get("effectVignette", "intensity"), -40f, 70f);
             intensitySlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.Intensity = intensitySlider.Value;
             };
-            blurSlider = new Slider(Translation.Get("effectVignette", "blur"), 0f, 5f);
+
+            blurSlider = new(Translation.Get("effectVignette", "blur"), 0f, 5f);
             blurSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.Blur = blurSlider.Value;
             };
-            blurSpreadSlider = new Slider(Translation.Get("effectVignette", "blurSpread"), 0f, 40f);
+
+            blurSpreadSlider = new(Translation.Get("effectVignette", "blurSpread"), 0f, 40f);
             blurSpreadSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.BlurSpread = blurSpreadSlider.Value;
             };
-            aberrationSlider = new Slider(Translation.Get("effectVignette", "aberration"), -30f, 30f);
+
+            aberrationSlider = new(Translation.Get("effectVignette", "aberration"), -30f, 30f);
             aberrationSlider.ControlEvent += (s, a) =>
             {
-                if (updating) return;
+                if (updating)
+                    return;
+
                 EffectManager.ChromaticAberration = aberrationSlider.Value;
             };
         }
@@ -56,7 +68,7 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void DrawPane()
         {
-            GUILayoutOption sliderWidth = MpsGui.HalfSlider;
+            var sliderWidth = MpsGui.HalfSlider;
 
             GUILayout.BeginHorizontal();
             intensitySlider.Draw(sliderWidth);

+ 169 - 124
src/MeidoPhotoStudio.Plugin/GUI/Panes/BackgroundWindowPanes/LightsPane.cs

@@ -2,12 +2,20 @@ using System;
 using System.Collections.Generic;
 using UnityEngine;
 
+using static MeidoPhotoStudio.Plugin.DragPointLight;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static DragPointLight;
     public class LightsPane : BasePane
     {
         private static readonly string[] lightTypes = { "normal", "spot", "point" };
+        private static readonly Dictionary<LightProp, SliderProp> lightSliderProp;
+        private static readonly string[,] sliderNames = {
+            { "lights", "x" }, { "lights", "y" }, { "lights", "intensity" }, { "lights", "shadow" },
+            { "lights", "spot" }, { "lights", "range" }, { "backgroundWindow", "red" }, { "backgroundWindow", "green" },
+            { "backgroundWindow", "blue" }
+        };
+
         private readonly LightManager lightManager;
         private readonly Dictionary<LightProp, Slider> lightSlider;
         private readonly Dropdown lightDropdown;
@@ -19,32 +27,27 @@ namespace MeidoPhotoStudio.Plugin
         private readonly SelectionGrid lightTypeGrid;
         private readonly Toggle colorToggle;
         private readonly Toggle disableToggle;
+
         private MPSLightType currentLightType;
         private string lightHeader;
         private string resetLabel;
 
-        private static readonly Dictionary<LightProp, SliderProp> lightSliderProp;
-        private static readonly string[,] sliderNames = {
-            { "lights", "x" }, { "lights", "y" }, { "lights", "intensity" }, { "lights", "shadow" },
-            { "lights", "spot" }, { "lights", "range" }, { "backgroundWindow", "red" }, { "backgroundWindow", "green" },
-            { "backgroundWindow", "blue" }
-        };
-
         static LightsPane()
         {
-            Vector3 rotation = LightProperty.DefaultRotation.eulerAngles;
+            var rotation = LightProperty.DefaultRotation.eulerAngles;
             var range = GameMain.Instance.MainLight.GetComponent<Light>().range;
-            lightSliderProp = new Dictionary<LightProp, SliderProp>
+
+            lightSliderProp = new()
             {
-                [LightProp.LightRotX] = new SliderProp(0f, 360f, rotation.x, rotation.x),
-                [LightProp.LightRotY] = new SliderProp(0f, 360f, rotation.y, rotation.y),
-                [LightProp.Intensity] = new SliderProp(0f, 2f, 0.95f, 0.95f),
-                [LightProp.ShadowStrength] = new SliderProp(0f, 1f, 0.098f, 0.098f),
-                [LightProp.Range] = new SliderProp(0f, 150f, range, range),
-                [LightProp.SpotAngle] = new SliderProp(0f, 150f, 50f, 50f),
-                [LightProp.Red] = new SliderProp(0f, 1f, 1f, 1f),
-                [LightProp.Green] = new SliderProp(0f, 1f, 1f, 1f),
-                [LightProp.Blue] = new SliderProp(0f, 1f, 1f, 1f),
+                [LightProp.LightRotX] = new(0f, 360f, rotation.x, rotation.x),
+                [LightProp.LightRotY] = new(0f, 360f, rotation.y, rotation.y),
+                [LightProp.Intensity] = new(0f, 2f, 0.95f, 0.95f),
+                [LightProp.ShadowStrength] = new(0f, 1f, 0.098f, 0.098f),
+                [LightProp.Range] = new(0f, 150f, range, range),
+                [LightProp.SpotAngle] = new(0f, 150f, 50f, 50f),
+                [LightProp.Red] = new(0f, 1f, 1f, 1f),
+                [LightProp.Green] = new(0f, 1f, 1f, 1f),
+                [LightProp.Blue] = new(0f, 1f, 1f, 1f),
             };
         }
 
@@ -56,72 +59,181 @@ namespace MeidoPhotoStudio.Plugin
             this.lightManager.Select += (s, a) => UpdateCurrentLight();
             this.lightManager.ListModified += (s, a) => UpdateList();
 
-            lightTypeGrid = new SelectionGrid(Translation.GetArray("lightType", lightTypes));
+            lightTypeGrid = new(Translation.GetArray("lightType", lightTypes));
+
             lightTypeGrid.ControlEvent += (s, a) => SetCurrentLightType();
 
-            lightDropdown = new Dropdown(new[] { "Main" });
+            lightDropdown = new(new[] { "Main" });
+
             lightDropdown.SelectionChange += (s, a) => SetCurrentLight();
 
-            addLightButton = new Button("+");
+            addLightButton = new("+");
+
             addLightButton.ControlEvent += (s, a) => lightManager.AddLight();
 
-            deleteLightButton = new Button(Translation.Get("lightsPane", "delete"));
+            deleteLightButton = new(Translation.Get("lightsPane", "delete"));
+
             deleteLightButton.ControlEvent += (s, a) => lightManager.DeleteActiveLight();
 
-            disableToggle = new Toggle(Translation.Get("lightsPane", "disable"));
+            disableToggle = new(Translation.Get("lightsPane", "disable"));
+
             disableToggle.ControlEvent += (s, a) => lightManager.CurrentLight.IsDisabled = disableToggle.Value;
 
-            clearLightsButton = new Button(Translation.Get("lightsPane", "clear"));
+            clearLightsButton = new(Translation.Get("lightsPane", "clear"));
+
             clearLightsButton.ControlEvent += (s, a) => ClearLights();
 
             var numberOfLightProps = Enum.GetNames(typeof(LightProp)).Length;
-            lightSlider = new Dictionary<LightProp, Slider>(numberOfLightProps);
+
+            lightSlider = new(numberOfLightProps);
 
             for (var i = 0; i < numberOfLightProps; i++)
             {
                 var lightProp = (LightProp)i;
-                SliderProp sliderProp = lightSliderProp[lightProp];
+                var sliderProp = lightSliderProp[lightProp];
                 var slider = new Slider(Translation.Get(sliderNames[i, 0], sliderNames[i, 1]), sliderProp)
                 {
                     HasTextField = true,
                     HasReset = true
                 };
-                if (lightProp <= LightProp.LightRotY) slider.ControlEvent += (s, a) => SetLightRotation();
-                else slider.ControlEvent += (s, a) => SetLightProp(lightProp, slider.Value);
+
+                if (lightProp <= LightProp.LightRotY)
+                    slider.ControlEvent += (s, a) => SetLightRotation();
+                else
+                    slider.ControlEvent += (s, a) => SetLightProp(lightProp, slider.Value);
+
                 lightSlider[lightProp] = slider;
             }
 
-            colorToggle = new Toggle(Translation.Get("lightsPane", "colour"));
+            colorToggle = new(Translation.Get("lightsPane", "colour"));
+
             colorToggle.ControlEvent += (s, a) => SetColourMode();
 
-            resetPropsButton = new Button(Translation.Get("lightsPane", "resetProperties"));
+            resetPropsButton = new(Translation.Get("lightsPane", "resetProperties"));
+
             resetPropsButton.ControlEvent += (s, a) => ResetLightProps();
 
-            resetPositionButton = new Button(Translation.Get("lightsPane", "resetPosition"));
+            resetPositionButton = new(Translation.Get("lightsPane", "resetPosition"));
+
             resetPositionButton.ControlEvent += (s, a) => lightManager.CurrentLight.ResetLightPosition();
 
             lightHeader = Translation.Get("lightsPane", "header");
+
             resetLabel = Translation.Get("lightsPane", "resetLabel");
         }
 
+        public override void UpdatePane()
+        {
+            updating = true;
+
+            var currentLight = lightManager.CurrentLight;
+
+            currentLightType = currentLight.SelectedLightType;
+            lightTypeGrid.SelectedItemIndex = (int)currentLightType;
+            disableToggle.Value = currentLight.IsDisabled;
+            lightSlider[LightProp.LightRotX].Value = currentLight.Rotation.eulerAngles.x;
+            lightSlider[LightProp.LightRotY].Value = currentLight.Rotation.eulerAngles.y;
+            lightSlider[LightProp.Intensity].Value = currentLight.Intensity;
+            lightSlider[LightProp.ShadowStrength].Value = currentLight.ShadowStrength;
+            lightSlider[LightProp.Range].Value = currentLight.Range;
+            lightSlider[LightProp.SpotAngle].Value = currentLight.SpotAngle;
+            lightSlider[LightProp.Red].Value = currentLight.LightColour.r;
+            lightSlider[LightProp.Green].Value = currentLight.LightColour.g;
+            lightSlider[LightProp.Blue].Value = currentLight.LightColour.b;
+
+            updating = false;
+        }
+
+        public override void Draw()
+        {
+            var isMain = lightManager.SelectedLightIndex == 0;
+
+            var noExpandWidth = GUILayout.ExpandWidth(false);
+
+            MpsGui.Header(lightHeader);
+            MpsGui.WhiteLine();
+
+            GUILayout.BeginHorizontal();
+            lightDropdown.Draw(GUILayout.Width(84));
+            addLightButton.Draw(noExpandWidth);
+
+            GUILayout.FlexibleSpace();
+            GUI.enabled = !isMain;
+            deleteLightButton.Draw(noExpandWidth);
+            GUI.enabled = true;
+            clearLightsButton.Draw(noExpandWidth);
+            GUILayout.EndHorizontal();
+
+            var isDisabled = !isMain && lightManager.CurrentLight.IsDisabled;
+
+            GUILayout.BeginHorizontal();
+            GUI.enabled = !isDisabled;
+            lightTypeGrid.Draw(noExpandWidth);
+
+            if (!isMain)
+            {
+                GUI.enabled = true;
+                disableToggle.Draw();
+            }
+
+            if (lightManager.SelectedLightIndex == 0 && currentLightType == MPSLightType.Normal)
+                colorToggle.Draw();
+
+            GUILayout.EndHorizontal();
+
+            GUI.enabled = !isDisabled;
+
+            if (currentLightType != MPSLightType.Point)
+            {
+                lightSlider[LightProp.LightRotX].Draw();
+                lightSlider[LightProp.LightRotY].Draw();
+            }
+
+            lightSlider[LightProp.Intensity].Draw();
+
+            if (currentLightType == MPSLightType.Normal)
+                lightSlider[LightProp.ShadowStrength].Draw();
+            else
+                lightSlider[LightProp.Range].Draw();
+
+            if (currentLightType == MPSLightType.Spot)
+                lightSlider[LightProp.SpotAngle].Draw();
+
+            MpsGui.BlackLine();
+
+            lightSlider[LightProp.Red].Draw();
+            lightSlider[LightProp.Green].Draw();
+            lightSlider[LightProp.Blue].Draw();
+
+            GUILayout.BeginHorizontal();
+            GUILayout.Label(resetLabel, noExpandWidth);
+            resetPropsButton.Draw(noExpandWidth);
+            resetPositionButton.Draw(noExpandWidth);
+            GUILayout.EndHorizontal();
+
+            GUI.enabled = true;
+        }
+
         protected override void ReloadTranslation()
         {
             updating = true;
+
             lightTypeGrid.SetItems(Translation.GetArray("lightType", lightTypes));
             lightDropdown.SetDropdownItems(lightManager.LightNameList);
             deleteLightButton.Label = Translation.Get("lightsPane", "delete");
             disableToggle.Label = Translation.Get("lightsPane", "disable");
             clearLightsButton.Label = Translation.Get("lightsPane", "clear");
+
             for (var lightProp = LightProp.LightRotX; lightProp <= LightProp.Blue; lightProp++)
-            {
                 lightSlider[lightProp].Label =
                     Translation.Get(sliderNames[(int)lightProp, 0], sliderNames[(int)lightProp, 1]);
-            }
+
             colorToggle.Label = Translation.Get("lightsPane", "colour");
             resetPropsButton.Label = Translation.Get("lightsPane", "resetProperties");
             resetPositionButton.Label = Translation.Get("lightsPane", "resetPosition");
             lightHeader = Translation.Get("lightsPane", "header");
             resetLabel = Translation.Get("lightsPane", "resetLabel");
+
             updating = false;
         }
 
@@ -139,7 +251,9 @@ namespace MeidoPhotoStudio.Plugin
 
         private void SetCurrentLight()
         {
-            if (updating) return;
+            if (updating)
+                return;
+
             lightManager.SelectedLightIndex = lightDropdown.SelectedItemIndex;
             UpdatePane();
         }
@@ -152,11 +266,12 @@ namespace MeidoPhotoStudio.Plugin
 
         private void SetCurrentLightType()
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             currentLightType = (MPSLightType)lightTypeGrid.SelectedItemIndex;
 
-            DragPointLight currentLight = lightManager.CurrentLight;
+            var currentLight = lightManager.CurrentLight;
 
             currentLight.SetLightType(currentLightType);
 
@@ -166,21 +281,27 @@ namespace MeidoPhotoStudio.Plugin
 
         private void SetLightProp(LightProp prop, float value)
         {
-            if (updating) return;
+            if (updating)
+                return;
+
             lightManager.CurrentLight.SetProp(prop, value);
         }
 
         private void SetLightRotation()
         {
-            if (updating) return;
+            if (updating)
+                return;
+
             var lightRotX = lightSlider[LightProp.LightRotX].Value;
             var lightRotY = lightSlider[LightProp.LightRotY].Value;
+
             lightManager.CurrentLight.SetRotation(lightRotX, lightRotY);
         }
 
         private void UpdateList()
         {
-            string[] newList = lightManager.LightNameList;
+            var newList = lightManager.LightNameList;
+
             lightDropdown.SetDropdownItems(newList, lightManager.SelectedLightIndex);
             UpdatePane();
         }
@@ -188,110 +309,34 @@ namespace MeidoPhotoStudio.Plugin
         private void UpdateRotation()
         {
             updating = true;
-            LightProperty prop = lightManager.CurrentLight.CurrentLightProperty;
+
+            var prop = lightManager.CurrentLight.CurrentLightProperty;
+
             lightSlider[LightProp.LightRotX].Value = prop.Rotation.eulerAngles.x;
             lightSlider[LightProp.LightRotY].Value = prop.Rotation.eulerAngles.y;
+
             updating = false;
         }
 
         private void UpdateScale()
         {
             updating = true;
+
             lightSlider[LightProp.SpotAngle].Value = lightManager.CurrentLight.CurrentLightProperty.SpotAngle;
             lightSlider[LightProp.Range].Value = lightManager.CurrentLight.CurrentLightProperty.Range;
+
             updating = false;
         }
 
         private void UpdateCurrentLight()
         {
             updating = true;
+
             lightDropdown.SelectedItemIndex = lightManager.SelectedLightIndex;
-            updating = false;
-            UpdatePane();
-        }
 
-        public override void UpdatePane()
-        {
-            updating = true;
-            DragPointLight currentLight = lightManager.CurrentLight;
-            currentLightType = currentLight.SelectedLightType;
-            lightTypeGrid.SelectedItemIndex = (int)currentLightType;
-            disableToggle.Value = currentLight.IsDisabled;
-            lightSlider[LightProp.LightRotX].Value = currentLight.Rotation.eulerAngles.x;
-            lightSlider[LightProp.LightRotY].Value = currentLight.Rotation.eulerAngles.y;
-            lightSlider[LightProp.Intensity].Value = currentLight.Intensity;
-            lightSlider[LightProp.ShadowStrength].Value = currentLight.ShadowStrength;
-            lightSlider[LightProp.Range].Value = currentLight.Range;
-            lightSlider[LightProp.SpotAngle].Value = currentLight.SpotAngle;
-            lightSlider[LightProp.Red].Value = currentLight.LightColour.r;
-            lightSlider[LightProp.Green].Value = currentLight.LightColour.g;
-            lightSlider[LightProp.Blue].Value = currentLight.LightColour.b;
             updating = false;
-        }
-
-        public override void Draw()
-        {
-            var isMain = lightManager.SelectedLightIndex == 0;
-
-            GUILayoutOption noExpandWidth = GUILayout.ExpandWidth(false);
-
-            MpsGui.Header(lightHeader);
-            MpsGui.WhiteLine();
-
-            GUILayout.BeginHorizontal();
-            lightDropdown.Draw(GUILayout.Width(84));
-            addLightButton.Draw(noExpandWidth);
-
-            GUILayout.FlexibleSpace();
-            GUI.enabled = !isMain;
-            deleteLightButton.Draw(noExpandWidth);
-            GUI.enabled = true;
-            clearLightsButton.Draw(noExpandWidth);
-            GUILayout.EndHorizontal();
 
-            bool isDisabled = !isMain && lightManager.CurrentLight.IsDisabled;
-            GUILayout.BeginHorizontal();
-            GUI.enabled = !isDisabled;
-            lightTypeGrid.Draw(noExpandWidth);
-            if (!isMain)
-            {
-                GUI.enabled = true;
-                disableToggle.Draw();
-            }
-
-            if (lightManager.SelectedLightIndex == 0 && currentLightType == MPSLightType.Normal) 
-                colorToggle.Draw();
-            
-            GUILayout.EndHorizontal();
-
-            GUI.enabled = !isDisabled;
-
-            if (currentLightType != MPSLightType.Point)
-            {
-                lightSlider[LightProp.LightRotX].Draw();
-                lightSlider[LightProp.LightRotY].Draw();
-            }
-
-            lightSlider[LightProp.Intensity].Draw();
-
-            if (currentLightType == MPSLightType.Normal) lightSlider[LightProp.ShadowStrength].Draw();
-            else lightSlider[LightProp.Range].Draw();
-
-            if (currentLightType == MPSLightType.Spot) lightSlider[LightProp.SpotAngle].Draw();
-
-            MpsGui.BlackLine();
-
-            lightSlider[LightProp.Red].Draw();
-            lightSlider[LightProp.Green].Draw();
-            lightSlider[LightProp.Blue].Draw();
-
-            GUILayout.BeginHorizontal();
-            GUILayout.Label(resetLabel, noExpandWidth);
-            resetPropsButton.Draw(noExpandWidth);
-            resetPositionButton.Draw(noExpandWidth);
-            GUILayout.EndHorizontal();
-
-            GUI.enabled = true;
+            UpdatePane();
         }
     }
 }

+ 13 - 7
src/MeidoPhotoStudio.Plugin/GUI/Panes/BasePane.cs

@@ -6,18 +6,19 @@ namespace MeidoPhotoStudio.Plugin
     {
         protected BaseWindow parent;
         protected bool updating;
+
         public virtual bool Visible { get; set; }
         public virtual bool Enabled { get; set; }
 
-        protected BasePane() => Translation.ReloadTranslationEvent += OnReloadTranslation;
-
-        ~BasePane() => Translation.ReloadTranslationEvent -= OnReloadTranslation;
+        protected BasePane() =>
+            Translation.ReloadTranslationEvent += OnReloadTranslation;
 
-        private void OnReloadTranslation(object sender, EventArgs args) => ReloadTranslation();
+        // TODO: This does not work how I think it works. Probably just remove entirely.
+        ~BasePane() =>
+            Translation.ReloadTranslationEvent -= OnReloadTranslation;
 
-        public virtual void SetParent(BaseWindow window) => parent = window;
-
-        protected virtual void ReloadTranslation() { }
+        public virtual void SetParent(BaseWindow window) =>
+            parent = window;
 
         public virtual void UpdatePane() { }
 
@@ -26,5 +27,10 @@ namespace MeidoPhotoStudio.Plugin
         public virtual void Activate() { }
 
         public virtual void Deactivate() { }
+
+        protected virtual void ReloadTranslation() { }
+
+        private void OnReloadTranslation(object sender, EventArgs args) =>
+            ReloadTranslation();
     }
 }

+ 27 - 16
src/MeidoPhotoStudio.Plugin/GUI/Panes/CallWindowPanes/MaidSelectorPane.cs

@@ -6,23 +6,24 @@ namespace MeidoPhotoStudio.Plugin
     public class MaidSelectorPane : BasePane
     {
         private readonly MeidoManager meidoManager;
-        private Vector2 maidListScrollPos;
-        private Vector2 activeMaidListScrollPos;
         private readonly Button clearMaidsButton;
         private readonly Button callMaidsButton;
         private readonly Toggle activeMeidoListToggle;
 
+        private Vector2 maidListScrollPos;
+        private Vector2 activeMaidListScrollPos;
+
         public MaidSelectorPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
-            clearMaidsButton = new Button(Translation.Get("maidCallWindow", "clearButton"));
+
+            clearMaidsButton = new(Translation.Get("maidCallWindow", "clearButton"));
             clearMaidsButton.ControlEvent += (s, a) => this.meidoManager.ClearSelectList();
 
-            callMaidsButton = new Button(Translation.Get("maidCallWindow", "callButton"));
+            callMaidsButton = new(Translation.Get("maidCallWindow", "callButton"));
             callMaidsButton.ControlEvent += (s, a) => this.meidoManager.CallMeidos();
 
             activeMeidoListToggle = new(Translation.Get("maidCallWindow", "activeOnlyToggle"));
-
             this.meidoManager.BeginCallMeidos += (_, _) =>
             {
                 if (meidoManager.SelectedMeidoSet.Count == 0)
@@ -30,17 +31,11 @@ namespace MeidoPhotoStudio.Plugin
             };
         }
 
-        protected override void ReloadTranslation()
-        {
-            clearMaidsButton.Label = Translation.Get("maidCallWindow", "clearButton");
-            callMaidsButton.Label = Translation.Get("maidCallWindow", "callButton");
-            activeMeidoListToggle.Label = Translation.Get("maidCallWindow", "activeOnlyToggle");
-        }
-        
         public override void Activate()
         {
             base.Activate();
-            // Leaving this mode enabled pretty much softlocks meido selection so disable it on activation
+
+            // NOTE: Leaving this mode enabled pretty much softlocks meido selection so disable it on activation
             activeMeidoListToggle.Value = false;
         }
 
@@ -65,22 +60,30 @@ namespace MeidoPhotoStudio.Plugin
                 ? meidoManager.ActiveMeidoList
                 : meidoManager.Meidos;
 
-            var labelStyle = new GUIStyle(GUI.skin.label) { fontSize = 14 };
+            var labelStyle = new GUIStyle(GUI.skin.label)
+            {
+                fontSize = 14,
+            };
 
             var selectLabelStyle = new GUIStyle(labelStyle)
             {
-                normal = { textColor = Color.black },
+                normal = {
+                    textColor = Color.black,
+                },
                 alignment = TextAnchor.UpperRight,
             };
 
             var labelSelectedStyle = new GUIStyle(labelStyle)
             {
-                normal = { textColor = Color.black },
+                normal = {
+                    textColor = Color.black,
+                },
             };
 
             var windowRect = parent.WindowRect;
             var windowHeight = windowRect.height;
             var buttonWidth = windowRect.width - 30f;
+
             const float buttonHeight = 85f;
             const float offsetTop = 130f;
 
@@ -104,6 +107,7 @@ namespace MeidoPhotoStudio.Plugin
                 if (selectedMaid)
                 {
                     var selectedIndex = meidoManager.SelectMeidoList.IndexOf(meido.StockNo) + 1;
+
                     GUI.DrawTexture(new(5f, y + 5f, buttonWidth - 10f, buttonHeight - 10f), Texture2D.whiteTexture);
 
                     GUI.Label(
@@ -122,5 +126,12 @@ namespace MeidoPhotoStudio.Plugin
 
             GUI.EndScrollView();
         }
+
+        protected override void ReloadTranslation()
+        {
+            clearMaidsButton.Label = Translation.Get("maidCallWindow", "clearButton");
+            callMaidsButton.Label = Translation.Get("maidCallWindow", "callButton");
+            activeMeidoListToggle.Label = Translation.Get("maidCallWindow", "activeOnlyToggle");
+        }
     }
 }

+ 57 - 36
src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/MaidFaceBlendPane.cs

@@ -7,6 +7,8 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class MaidFaceBlendPane : BasePane
     {
+        private static readonly string[] tabTranslations = { "baseTab", "customTab" };
+
         private readonly MeidoManager meidoManager;
         private readonly SelectionGrid faceBlendSourceGrid;
         private readonly Dropdown faceBlendCategoryDropdown;
@@ -15,90 +17,98 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Dropdown faceBlendDropdown;
         private readonly Button facePrevButton;
         private readonly Button faceNextButton;
-        private static readonly string[] tabTranslations = { "baseTab", "customTab" };
+
         private bool facePresetMode;
         private bool faceListEnabled;
+
         private Dictionary<string, List<string>> CurrentFaceDict => facePresetMode
             ? Constants.CustomFaceDict : Constants.FaceDict;
+
         private List<string> CurrentFaceGroupList => facePresetMode
             ? Constants.CustomFaceGroupList : Constants.FaceGroupList;
-        private string SelectedFaceGroup => CurrentFaceGroupList[faceBlendCategoryDropdown.SelectedItemIndex];
-        private List<string> CurrentFaceList => CurrentFaceDict[SelectedFaceGroup];
-        private int SelectedFaceIndex => faceBlendDropdown.SelectedItemIndex;
-        private string SelectedFace => CurrentFaceList[SelectedFaceIndex];
+
+        private string SelectedFaceGroup =>
+            CurrentFaceGroupList[faceBlendCategoryDropdown.SelectedItemIndex];
+
+        private List<string> CurrentFaceList =>
+            CurrentFaceDict[SelectedFaceGroup];
+
+        private int SelectedFaceIndex =>
+            faceBlendDropdown.SelectedItemIndex;
+
+        private string SelectedFace =>
+            CurrentFaceList[SelectedFaceIndex];
 
         public MaidFaceBlendPane(MeidoManager meidoManager)
         {
             Constants.CustomFaceChange += OnPresetChange;
+
             this.meidoManager = meidoManager;
 
-            faceBlendSourceGrid = new SelectionGrid(Translation.GetArray("maidFaceWindow", tabTranslations));
+            faceBlendSourceGrid = new(Translation.GetArray("maidFaceWindow", tabTranslations));
+
             faceBlendSourceGrid.ControlEvent += (s, a) =>
             {
-                facePresetMode = faceBlendSourceGrid.SelectedItemIndex == 1;
-                if (updating) return;
-                string[] list = facePresetMode
+                facePresetMode = faceBlendSourceGrid.SelectedItemIndex is 1;
+
+                if (updating)
+                    return;
+
+                var list = facePresetMode
                     ? CurrentFaceGroupList.ToArray()
                     : Translation.GetArray("faceBlendCategory", Constants.FaceGroupList);
+
                 faceBlendCategoryDropdown.SetDropdownItems(list, 0);
             };
 
-            faceBlendCategoryDropdown = new Dropdown(
+            faceBlendCategoryDropdown = new(
                 Translation.GetArray("faceBlendCategory", Constants.FaceGroupList)
             );
+
             faceBlendCategoryDropdown.SelectionChange += (s, a) =>
             {
                 faceListEnabled = CurrentFaceList.Count > 0;
                 faceBlendDropdown.SetDropdownItems(UIFaceList(), 0);
             };
 
-            prevCategoryButton = new Button("<");
+            prevCategoryButton = new("<");
             prevCategoryButton.ControlEvent += (s, a) => faceBlendCategoryDropdown.Step(-1);
 
-            nextCategoryButton = new Button(">");
+            nextCategoryButton = new(">");
             nextCategoryButton.ControlEvent += (s, a) => faceBlendCategoryDropdown.Step(1);
 
-            faceBlendDropdown = new Dropdown(UIFaceList());
+            faceBlendDropdown = new(UIFaceList());
             faceBlendDropdown.SelectionChange += (s, a) =>
             {
-                if (!faceListEnabled || updating) return;
+                if (!faceListEnabled || updating)
+                    return;
+
                 this.meidoManager.ActiveMeido.SetFaceBlendSet(SelectedFace);
             };
 
-            facePrevButton = new Button("<");
+            facePrevButton = new("<");
             facePrevButton.ControlEvent += (s, a) => faceBlendDropdown.Step(-1);
 
-            faceNextButton = new Button(">");
+            faceNextButton = new(">");
             faceNextButton.ControlEvent += (s, a) => faceBlendDropdown.Step(1);
 
             faceListEnabled = CurrentFaceList.Count > 0;
         }
 
-        protected override void ReloadTranslation()
-        {
-            updating = true;
-            faceBlendSourceGrid.SetItems(Translation.GetArray("maidFaceWindow", tabTranslations));
-            if (!facePresetMode)
-            {
-                faceBlendCategoryDropdown.SetDropdownItems(
-                    Translation.GetArray("faceBlendCategory", Constants.FaceGroupList)
-                );
-            }
-            updating = false;
-        }
-
         public override void Draw()
         {
             const float buttonHeight = 30;
-            GUILayoutOption[] arrowLayoutOptions = {
+
+            var arrowLayoutOptions = new[] {
                 GUILayout.Width(buttonHeight),
-                GUILayout.Height(buttonHeight)
+                GUILayout.Height(buttonHeight),
             };
 
             const float dropdownButtonWidth = 153f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownLayoutOptions = new[] {
                 GUILayout.Height(buttonHeight),
-                GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             GUI.enabled = meidoManager.HasActiveMeido;
@@ -122,15 +132,26 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
-        private string[] UIFaceList()
+        protected override void ReloadTranslation()
         {
-            return CurrentFaceList.Count == 0
+            updating = true;
+            faceBlendSourceGrid.SetItems(Translation.GetArray("maidFaceWindow", tabTranslations));
+
+            if (!facePresetMode)
+                faceBlendCategoryDropdown.SetDropdownItems(
+                    Translation.GetArray("faceBlendCategory", Constants.FaceGroupList)
+                );
+
+            updating = false;
+        }
+
+        private string[] UIFaceList() =>
+            CurrentFaceList.Count is 0
                 ? (new[] { "No Face Presets" })
                 : CurrentFaceList.Select(face => facePresetMode
                     ? Path.GetFileNameWithoutExtension(face)
                     : Translation.Get("faceBlendPresetsDropdown", face)
                 ).ToArray();
-        }
 
         private void OnPresetChange(object sender, PresetChangeEventArgs args)
         {

+ 89 - 56
src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/MaidFaceSliderPane.cs

@@ -1,16 +1,16 @@
 using System;
-using System.IO;
 using System.Collections.Generic;
+using System.IO;
+using System.Linq;
 using Newtonsoft.Json;
 using UnityEngine;
-using System.Linq;
+using static MeidoPhotoStudio.Plugin.Meido;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using static Meido;
     public class MaidFaceSliderPane : BasePane
     {
-        private static readonly Dictionary<string, float> SliderLimits = new Dictionary<string, float>()
+        private static readonly Dictionary<string, float> SliderLimits = new()
         {
             // Eye Shut
             ["eyeclose"] = 1f,
@@ -61,54 +61,35 @@ namespace MeidoPhotoStudio.Plugin
             // Tongue Base
             ["tangopen"] = 1f
         };
+
         private readonly MeidoManager meidoManager;
         private readonly Dictionary<string, BaseControl> faceControls;
-        private bool hasTangOpen;
 
-        public MaidFaceSliderPane(MeidoManager meidoManager)
-        {
-            this.meidoManager = meidoManager;
-            faceControls = new Dictionary<string, BaseControl>();
-
-            foreach (string key in faceKeys)
-            {
-                string uiName = Translation.Get("faceBlendValues", key);
-                Slider slider = new Slider(uiName, 0f, SliderLimits[key]);
-                string myKey = key;
-                slider.ControlEvent += (s, a) => SetFaceValue(myKey, slider.Value);
-                faceControls[key] = slider;
-            }
-
-            foreach (string key in faceToggleKeys)
-            {
-                string uiName = Translation.Get("faceBlendValues", key);
-                Toggle toggle = new Toggle(uiName);
-                string myKey = key;
-                toggle.ControlEvent += (s, a) => SetFaceValue(myKey, toggle.Value);
-                faceControls[key] = toggle;
-            }
-
-            InitializeSliderLimits(faceControls);
-        }
+        private bool hasTangOpen;
 
         private static void InitializeSliderLimits(Dictionary<string, BaseControl> controls)
         {
             try
             {
-                string sliderLimitsPath = Path.Combine(Constants.databasePath, "face_slider_limits.json");
-                string sliderLimitsJson = File.ReadAllText(sliderLimitsPath);
+                var sliderLimitsPath = Path.Combine(Constants.databasePath, "face_slider_limits.json");
+                var sliderLimitsJson = File.ReadAllText(sliderLimitsPath);
 
                 foreach (var kvp in JsonConvert.DeserializeObject<Dictionary<string, float>>(sliderLimitsJson))
                 {
-                    string key = kvp.Key;
+                    var key = kvp.Key;
+
                     if (faceKeys.Contains(key) && controls.ContainsKey(key))
                     {
-                        float limit = kvp.Value;
+                        var limit = kvp.Value;
+
                         limit = kvp.Value >= 1f ? limit : SliderLimits[key];
-                        Slider slider = (Slider)controls[kvp.Key];
+
+                        var slider = (Slider)controls[kvp.Key];
+
                         slider.SetBounds(slider.Left, limit);
                     }
-                    else Utility.LogWarning($"'{key}' is not a valid face key");
+                    else
+                        Utility.LogWarning($"'{key}' is not a valid face key");
                 }
             }
             catch (IOException e)
@@ -121,42 +102,64 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        protected override void ReloadTranslation()
+        public MaidFaceSliderPane(MeidoManager meidoManager)
         {
-            for (int i = 0; i < faceKeys.Length; i++)
+            this.meidoManager = meidoManager;
+
+            faceControls = new();
+
+            foreach (var key in faceKeys)
             {
-                Slider slider = (Slider)faceControls[faceKeys[i]];
-                slider.Label = Translation.Get("faceBlendValues", faceKeys[i]);
+                var uiName = Translation.Get("faceBlendValues", key);
+                var slider = new Slider(uiName, 0f, SliderLimits[key]);
+                var sliderKey = key;
+
+                slider.ControlEvent += (s, a) => SetFaceValue(sliderKey, slider.Value);
+
+                faceControls[key] = slider;
             }
 
-            for (int i = 0; i < faceToggleKeys.Length; i++)
+            foreach (var key in faceToggleKeys)
             {
-                Toggle toggle = (Toggle)faceControls[faceToggleKeys[i]];
-                toggle.Label = Translation.Get("faceBlendValues", faceToggleKeys[i]);
+                var uiName = Translation.Get("faceBlendValues", key);
+                var toggle = new Toggle(uiName);
+                var sliderKey = key;
+
+                toggle.ControlEvent += (s, a) => SetFaceValue(sliderKey, toggle.Value);
+
+                faceControls[key] = toggle;
             }
+
+            InitializeSliderLimits(faceControls);
         }
 
         public override void UpdatePane()
         {
             updating = true;
-            Meido meido = meidoManager.ActiveMeido;
-            for (int i = 0; i < faceKeys.Length; i++)
+            var meido = meidoManager.ActiveMeido;
+
+            for (var i = 0; i < faceKeys.Length; i++)
             {
-                Slider slider = (Slider)faceControls[faceKeys[i]];
+                var slider = (Slider)faceControls[faceKeys[i]];
+
                 try
                 {
                     slider.Value = meido.GetFaceBlendValue(faceKeys[i]);
                 }
-                catch { }
+                catch { /* Ignored */ }
             }
 
-            for (int i = 0; i < faceToggleKeys.Length; i++)
+            for (var i = 0; i < faceToggleKeys.Length; i++)
             {
-                string hash = faceToggleKeys[i];
-                Toggle toggle = (Toggle)faceControls[hash];
+                var hash = faceToggleKeys[i];
+                var toggle = (Toggle)faceControls[hash];
+
                 toggle.Value = meido.GetFaceBlendValue(hash) > 0f;
-                if (hash == "toothoff") toggle.Value = !toggle.Value;
+
+                if (hash == "toothoff")
+                    toggle.Value = !toggle.Value;
             }
+
             hasTangOpen = meido.Body.Face.morph.Contains("tangopen");
             updating = false;
         }
@@ -176,7 +179,10 @@ namespace MeidoPhotoStudio.Plugin
             DrawSliders("mouthup", "mouthdw");
             DrawSliders("mouthhe", "mouthuphalf");
             DrawSliders("tangout", "tangup");
-            if (hasTangOpen) DrawSliders("tangopen");
+
+            if (hasTangOpen)
+                DrawSliders("tangopen");
+
             MpsGui.WhiteLine();
             DrawToggles("hoho2", "shock", "nosefook");
             DrawToggles("namida", "yodare", "toothoff");
@@ -185,29 +191,56 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            for (var i = 0; i < faceKeys.Length; i++)
+            {
+                var slider = (Slider)faceControls[faceKeys[i]];
+
+                slider.Label = Translation.Get("faceBlendValues", faceKeys[i]);
+            }
+
+            for (var i = 0; i < faceToggleKeys.Length; i++)
+            {
+                var toggle = (Toggle)faceControls[faceToggleKeys[i]];
+
+                toggle.Label = Translation.Get("faceBlendValues", faceToggleKeys[i]);
+            }
+        }
+
         private void DrawSliders(params string[] keys)
         {
             GUILayout.BeginHorizontal();
-            foreach (string key in keys) faceControls[key].Draw(MpsGui.HalfSlider);
+
+            foreach (var key in keys)
+                faceControls[key].Draw(MpsGui.HalfSlider);
+
             GUILayout.EndHorizontal();
         }
 
         private void DrawToggles(params string[] keys)
         {
             GUILayout.BeginHorizontal();
-            foreach (string key in keys) faceControls[key].Draw();
+
+            foreach (var key in keys)
+                faceControls[key].Draw();
+
             GUILayout.EndHorizontal();
         }
 
         private void SetFaceValue(string key, float value)
         {
-            if (updating) return;
+            if (updating)
+                return;
+
             meidoManager.ActiveMeido.SetFaceBlendValue(key, value);
         }
 
         private void SetFaceValue(string key, bool value)
         {
-            if (key == "toothoff") value = !value;
+            if (key == "toothoff")
+                value = !value;
+
             SetFaceValue(key, value ? 1f : 0f);
         }
     }

+ 17 - 13
src/MeidoPhotoStudio.Plugin/GUI/Panes/FaceWindowPanes/SaveFacePane.cs

@@ -8,31 +8,26 @@ namespace MeidoPhotoStudio.Plugin
         private readonly ComboBox categoryComboBox;
         private readonly TextField faceNameTextField;
         private readonly Button saveFaceButton;
+
         private string categoryHeader;
         private string nameHeader;
 
         public SaveFacePane(MeidoManager meidoManager)
         {
-            Constants.CustomFaceChange += (s, a)
-                => categoryComboBox.SetDropdownItems(Constants.CustomFaceGroupList.ToArray());
+            Constants.CustomFaceChange += (s, a) =>
+                categoryComboBox.SetDropdownItems(Constants.CustomFaceGroupList.ToArray());
 
             this.meidoManager = meidoManager;
 
             categoryHeader = Translation.Get("faceSave", "categoryHeader");
             nameHeader = Translation.Get("faceSave", "nameHeader");
 
-            saveFaceButton = new Button(Translation.Get("faceSave", "saveButton"));
+            saveFaceButton = new(Translation.Get("faceSave", "saveButton"));
             saveFaceButton.ControlEvent += (s, a) => SaveFace();
 
-            categoryComboBox = new ComboBox(Constants.CustomFaceGroupList.ToArray());
-            faceNameTextField = new TextField();
-        }
+            categoryComboBox = new(Constants.CustomFaceGroupList.ToArray());
 
-        protected override void ReloadTranslation()
-        {
-            categoryHeader = Translation.Get("faceSave", "categoryHeader");
-            nameHeader = Translation.Get("faceSave", "nameHeader");
-            saveFaceButton.Label = Translation.Get("faceSave", "saveButton");
+            faceNameTextField = new();
         }
 
         public override void Draw()
@@ -51,11 +46,20 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            categoryHeader = Translation.Get("faceSave", "categoryHeader");
+            nameHeader = Translation.Get("faceSave", "nameHeader");
+            saveFaceButton.Label = Translation.Get("faceSave", "saveButton");
+        }
+
         private void SaveFace()
         {
-            if (!meidoManager.HasActiveMeido) return;
+            if (!meidoManager.HasActiveMeido)
+                return;
+
+            var meido = meidoManager.ActiveMeido;
 
-            Meido meido = meidoManager.ActiveMeido;
             Constants.AddFacePreset(meido.SerializeFace(), faceNameTextField.Value, categoryComboBox.Value);
             faceNameTextField.Value = string.Empty;
         }

+ 11 - 8
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BG2WindowPane.cs

@@ -5,11 +5,13 @@ namespace MeidoPhotoStudio.Plugin
     public class BG2WindowPane : BaseMainWindowPane
     {
         private static readonly string[] tabNames = { "props", "myRoom", "mod" };
+
         private readonly MeidoManager meidoManager;
         private readonly PropManager propManager;
         private readonly AttachPropPane attachPropPane;
         private readonly PropManagerPane propManagerPane;
         private readonly SelectionGrid propTabs;
+
         private BasePane currentPropsPane;
 
         public BG2WindowPane(MeidoManager meidoManager, PropManager propManager)
@@ -26,14 +28,10 @@ namespace MeidoPhotoStudio.Plugin
             attachPropPane = AddPane(new AttachPropPane(this.meidoManager, propManager));
             propManagerPane = AddPane(new PropManagerPane(propManager));
 
-            propTabs = new SelectionGrid(Translation.GetArray("propsPaneTabs", tabNames));
+            propTabs = new(Translation.GetArray("propsPaneTabs", tabNames));
             propTabs.ControlEvent += (s, a) => currentPropsPane = Panes[propTabs.SelectedItemIndex];
-            currentPropsPane = Panes[0];
-        }
 
-        protected override void ReloadTranslation()
-        {
-            propTabs.SetItems(Translation.GetArray("propsPaneTabs", tabNames));
+            currentPropsPane = Panes[0];
         }
 
         public override void Draw()
@@ -43,7 +41,8 @@ namespace MeidoPhotoStudio.Plugin
             MpsGui.WhiteLine();
             currentPropsPane.Draw();
 
-            if (propTabs.SelectedItemIndex != 0) return;
+            if (propTabs.SelectedItemIndex != 0)
+                return;
 
             propManagerPane.Draw();
             scrollPos = GUILayout.BeginScrollView(scrollPos);
@@ -53,7 +52,11 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void UpdatePanes()
         {
-            if (ActiveWindow) base.UpdatePanes();
+            if (ActiveWindow)
+                base.UpdatePanes();
         }
+
+        protected override void ReloadTranslation() =>
+            propTabs.SetItems(Translation.GetArray("propsPaneTabs", tabNames));
     }
 }

+ 6 - 8
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BGWindowPane.cs

@@ -17,14 +17,13 @@ namespace MeidoPhotoStudio.Plugin
             SceneWindow sceneWindow, CameraManager cameraManager
         )
         {
-            sceneManagerButton = new Button(Translation.Get("backgroundWindow", "manageScenesButton"));
+            sceneManagerButton = new(Translation.Get("backgroundWindow", "manageScenesButton"));
             sceneManagerButton.ControlEvent += (s, a) => sceneWindow.Visible = !sceneWindow.Visible;
 
             backgroundSelectorPane = AddPane(new BackgroundSelectorPane(environmentManager));
             cameraPane = AddPane(new CameraPane(cameraManager));
             dragPointPane = AddPane(new DragPointPane());
             lightsPane = AddPane(new LightsPane(lightManager));
-
             effectsPane = AddPane(new EffectsPane()
             {
                 ["bloom"] = new BloomPane(effectManager),
@@ -36,11 +35,6 @@ namespace MeidoPhotoStudio.Plugin
             otherEffectsPane = AddPane(new OtherEffectsPane(effectManager));
         }
 
-        protected override void ReloadTranslation()
-        {
-            sceneManagerButton.Label = Translation.Get("backgroundWindow", "manageScenesButton");
-        }
-
         public override void Draw()
         {
             tabsPane.Draw();
@@ -60,7 +54,11 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void UpdatePanes()
         {
-            if (ActiveWindow) base.UpdatePanes();
+            if (ActiveWindow)
+                base.UpdatePanes();
         }
+
+        protected override void ReloadTranslation() =>
+            sceneManagerButton.Label = Translation.Get("backgroundWindow", "manageScenesButton");
     }
 }

+ 3 - 1
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/BaseMainWindowPane.cs

@@ -3,6 +3,8 @@ namespace MeidoPhotoStudio.Plugin
     public abstract class BaseMainWindowPane : BaseWindow
     {
         protected TabsPane tabsPane;
-        public void SetTabsPane(TabsPane tabsPane) => this.tabsPane = tabsPane;
+
+        public void SetTabsPane(TabsPane tabsPane) =>
+            this.tabsPane = tabsPane;
     }
 }

+ 12 - 10
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/CallWindowPane.cs

@@ -12,11 +12,12 @@ namespace MeidoPhotoStudio.Plugin
         public CallWindowPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
-            placementDropdown = new Dropdown(
+
+            placementDropdown = new(
                 Translation.GetArray("placementDropdown", MaidPlacementUtility.placementTypes)
             );
 
-            placementOKButton = new Button(Translation.Get("maidCallWindow", "okButton"));
+            placementOKButton = new(Translation.Get("maidCallWindow", "okButton"));
             placementOKButton.ControlEvent += (o, a) => this.meidoManager.PlaceMeidos(
                 MaidPlacementUtility.placementTypes[placementDropdown.SelectedItemIndex]
             );
@@ -24,14 +25,6 @@ namespace MeidoPhotoStudio.Plugin
             maidSelectorPane = AddPane(new MaidSelectorPane(this.meidoManager));
         }
 
-        protected override void ReloadTranslation()
-        {
-            placementDropdown.SetDropdownItems(
-                Translation.GetArray("placementDropdown", MaidPlacementUtility.placementTypes)
-            );
-            placementOKButton.Label = Translation.Get("maidCallWindow", "okButton");
-        }
-
         public override void Draw()
         {
             tabsPane.Draw();
@@ -43,5 +36,14 @@ namespace MeidoPhotoStudio.Plugin
 
             maidSelectorPane.Draw();
         }
+
+        protected override void ReloadTranslation()
+        {
+            placementDropdown.SetDropdownItems(
+                Translation.GetArray("placementDropdown", MaidPlacementUtility.placementTypes)
+            );
+
+            placementOKButton.Label = Translation.Get("maidCallWindow", "okButton");
+        }
     }
 }

+ 10 - 8
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/FaceWindowPane.cs

@@ -22,15 +22,10 @@ namespace MeidoPhotoStudio.Plugin
             maidFaceBlendPane = AddPane(new MaidFaceBlendPane(this.meidoManager));
             saveFacePane = AddPane(new SaveFacePane(this.meidoManager));
 
-            saveFaceToggle = new Toggle(Translation.Get("maidFaceWindow", "savePaneToggle"));
+            saveFaceToggle = new(Translation.Get("maidFaceWindow", "savePaneToggle"));
             saveFaceToggle.ControlEvent += (s, a) => saveFaceMode = !saveFaceMode;
         }
 
-        protected override void ReloadTranslation()
-        {
-            saveFaceToggle.Label = Translation.Get("maidFaceWindow", "savePaneToggle");
-        }
-
         public override void Draw()
         {
             tabsPane.Draw();
@@ -46,19 +41,26 @@ namespace MeidoPhotoStudio.Plugin
             saveFaceToggle.Draw();
             GUI.enabled = true;
 
-            if (saveFaceMode) saveFacePane.Draw();
+            if (saveFaceMode)
+                saveFacePane.Draw();
 
             GUILayout.EndScrollView();
         }
 
         public override void UpdatePanes()
         {
-            if (!meidoManager.HasActiveMeido) return;
+            if (!meidoManager.HasActiveMeido)
+                return;
+
             if (ActiveWindow)
             {
                 meidoManager.ActiveMeido.StopBlink();
+
                 base.UpdatePanes();
             }
         }
+
+        protected override void ReloadTranslation() =>
+            saveFaceToggle.Label = Translation.Get("maidFaceWindow", "savePaneToggle");
     }
 }

+ 37 - 29
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/PoseWindowPane.cs

@@ -20,6 +20,7 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Toggle savePoseToggle;
         private readonly Toggle saveHandToggle;
         private readonly Button flipButton;
+
         private bool savePoseMode;
         private bool saveHandMode;
         private string handPresetHeader;
@@ -36,45 +37,33 @@ namespace MeidoPhotoStudio.Plugin
             maidFaceLookPane = AddPane(new MaidFaceLookPane(meidoManager));
             maidFaceLookPane.Enabled = false;
 
-            freeLookToggle = new Toggle(Translation.Get("freeLookPane", "freeLookToggle"), false);
+            freeLookToggle = new(Translation.Get("freeLookPane", "freeLookToggle"), false);
             freeLookToggle.ControlEvent += (s, a) => SetMaidFreeLook();
 
-            savePoseToggle = new Toggle(Translation.Get("posePane", "saveToggle"));
+            savePoseToggle = new(Translation.Get("posePane", "saveToggle"));
             savePoseToggle.ControlEvent += (s, a) => savePoseMode = !savePoseMode;
 
-            mpnAttachPropPane = new MpnAttachPropPane(this.meidoManager);
+            // TODO: Why are only some panes added to the pane list?
+            mpnAttachPropPane = new(this.meidoManager);
 
             maidDressingPane = AddPane(new MaidDressingPane(this.meidoManager));
-
             maidIKPane = AddPane(new MaidIKPane(this.meidoManager));
-
             gravityControlPane = AddPane(new GravityControlPane(this.meidoManager));
-
             copyPosePane = AddPane(new CopyPosePane(this.meidoManager));
 
-            saveHandToggle = new Toggle(Translation.Get("handPane", "saveToggle"));
+            saveHandToggle = new(Translation.Get("handPane", "saveToggle"));
             saveHandToggle.ControlEvent += (s, a) => saveHandMode = !saveHandMode;
 
             handPresetPane = AddPane(new HandPresetPane(meidoManager));
             saveHandPane = AddPane(new SaveHandPane(meidoManager));
 
-            flipButton = new Button(Translation.Get("flipIK", "flipButton"));
+            flipButton = new(Translation.Get("flipIK", "flipButton"));
             flipButton.ControlEvent += (s, a) => this.meidoManager.ActiveMeido.IKManager.Flip();
 
             handPresetHeader = Translation.Get("handPane", "header");
             flipIKHeader = Translation.Get("flipIK", "header");
         }
 
-        protected override void ReloadTranslation()
-        {
-            freeLookToggle.Label = Translation.Get("freeLookPane", "freeLookToggle");
-            savePoseToggle.Label = Translation.Get("posePane", "saveToggle");
-            saveHandToggle.Label = Translation.Get("handPane", "saveToggle");
-            flipButton.Label = Translation.Get("flipIK", "flipButton");
-            handPresetHeader = Translation.Get("handPane", "header");
-            flipIKHeader = Translation.Get("flipIK", "header");
-        }
-
         public override void Draw()
         {
             tabsPane.Draw();
@@ -95,8 +84,10 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.EndHorizontal();
             GUI.enabled = true;
 
-            if (savePoseMode) savePosePane.Draw();
-            else maidFaceLookPane.Draw();
+            if (savePoseMode)
+                savePosePane.Draw();
+            else
+                maidFaceLookPane.Draw();
 
             mpnAttachPropPane.Draw();
 
@@ -108,8 +99,10 @@ namespace MeidoPhotoStudio.Plugin
             saveHandToggle.Draw();
             GUI.enabled = true;
 
-            if (saveHandMode) saveHandPane.Draw();
-            else handPresetPane.Draw();
+            if (saveHandMode)
+                saveHandPane.Draw();
+            else
+                handPresetPane.Draw();
 
             gravityControlPane.Draw();
 
@@ -125,23 +118,38 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.EndScrollView();
         }
 
-        private void SetMaidFreeLook()
-        {
-            if (updating) return;
-            meidoManager.ActiveMeido.FreeLook = freeLookToggle.Value;
-        }
-
         public override void UpdatePanes()
         {
-            if (meidoManager.ActiveMeido == null) return;
+            if (meidoManager.ActiveMeido == null)
+                return;
 
             if (ActiveWindow)
             {
                 updating = true;
                 freeLookToggle.Value = meidoManager.ActiveMeido?.FreeLook ?? false;
                 updating = false;
+
                 base.UpdatePanes();
             }
         }
+
+        protected override void ReloadTranslation()
+        {
+            freeLookToggle.Label = Translation.Get("freeLookPane", "freeLookToggle");
+            savePoseToggle.Label = Translation.Get("posePane", "saveToggle");
+            saveHandToggle.Label = Translation.Get("handPane", "saveToggle");
+            flipButton.Label = Translation.Get("flipIK", "flipButton");
+            handPresetHeader = Translation.Get("handPane", "header");
+            flipIKHeader = Translation.Get("flipIK", "header");
+        }
+
+
+        private void SetMaidFreeLook()
+        {
+            if (updating)
+                return;
+
+            meidoManager.ActiveMeido.FreeLook = freeLookToggle.Value;
+        }
     }
 }

+ 40 - 45
src/MeidoPhotoStudio.Plugin/GUI/Panes/MainWindowPanes/SettingsWindowPane.cs

@@ -10,9 +10,11 @@ namespace MeidoPhotoStudio.Plugin
         private static readonly string[] headerTranslationKeys = {
             "controls", "controlsGeneral", "controlsMaids", "controlsCamera", "controlsDragPoint", "controlsScene"
         };
-        private static readonly Dictionary<string, string> headers = new Dictionary<string, string>();
+
+        private static readonly Dictionary<string, string> headers = new();
         private static readonly string[] actionTranslationKeys;
         private static readonly string[] actionLabels;
+
         private readonly Button reloadTranslationButton;
         private readonly Button reloadAllPresetsButton;
         private readonly KeyRebindButton[] rebindButtons;
@@ -29,25 +31,24 @@ namespace MeidoPhotoStudio.Plugin
         {
             rebindButtons = new KeyRebindButton[actionTranslationKeys.Length];
 
-            for (int i = 0; i < rebindButtons.Length; i++)
+            for (var i = 0; i < rebindButtons.Length; i++)
             {
-                MpsKey action = (MpsKey)i;
-                KeyRebindButton button = new KeyRebindButton(KeyCode.None);
+                var action = (MpsKey)i;
+                var button = new KeyRebindButton(KeyCode.None);
+
                 button.ControlEvent += (s, a) => InputManager.Rebind(action, button.KeyCode);
                 rebindButtons[i] = button;
 
                 actionLabels[i] = Translation.Get("controls", actionTranslationKeys[i]);
             }
 
-            for (int i = 0; i < headerTranslationKeys.Length; i++)
-            {
+            for (var i = 0; i < headerTranslationKeys.Length; i++)
                 headers[headerTranslationKeys[i]] = Translation.Get("settingsHeaders", headerTranslationKeys[i]);
-            }
 
-            reloadTranslationButton = new Button(Translation.Get("settingsLabels", "reloadTranslation"));
+            reloadTranslationButton = new(Translation.Get("settingsLabels", "reloadTranslation"));
             reloadTranslationButton.ControlEvent += (s, a) => Translation.ReinitializeTranslation();
 
-            reloadAllPresetsButton = new Button(Translation.Get("settingsLabels", "reloadAllPresets"));
+            reloadAllPresetsButton = new(Translation.Get("settingsLabels", "reloadAllPresets"));
             reloadAllPresetsButton.ControlEvent += (s, a) =>
             {
                 Constants.InitializeCustomFaceBlends();
@@ -56,22 +57,6 @@ namespace MeidoPhotoStudio.Plugin
             };
         }
 
-        protected override void ReloadTranslation()
-        {
-            for (int i = 0; i < rebindButtons.Length; i++)
-            {
-                actionLabels[i] = Translation.Get("controls", actionTranslationKeys[i]);
-            }
-
-            for (int i = 0; i < headerTranslationKeys.Length; i++)
-            {
-                headers[headerTranslationKeys[i]] = Translation.Get("settingsHeaders", headerTranslationKeys[i]);
-            }
-
-            reloadTranslationButton.Label = Translation.Get("settingsLabels", "reloadTranslation");
-            reloadAllPresetsButton.Label = Translation.Get("settingsLabels", "reloadAllPresets");
-        }
-
         public override void Draw()
         {
             scrollPos = GUILayout.BeginScrollView(scrollPos);
@@ -81,10 +66,9 @@ namespace MeidoPhotoStudio.Plugin
 
             MpsGui.Header(headers["controlsGeneral"]);
             MpsGui.WhiteLine();
-            for (MpsKey key = MpsKey.Activate; key <= MpsKey.ToggleMessage; key++)
-            {
+
+            for (var key = MpsKey.Activate; key <= MpsKey.ToggleMessage; key++)
                 DrawSetting(key);
-            }
 
             MpsGui.Header(headers["controlsMaids"]);
             MpsGui.WhiteLine();
@@ -92,24 +76,21 @@ namespace MeidoPhotoStudio.Plugin
 
             MpsGui.Header(headers["controlsCamera"]);
             MpsGui.WhiteLine();
-            for (MpsKey key = MpsKey.CameraLayer; key <= MpsKey.CameraLoad; key++)
-            {
+
+            for (var key = MpsKey.CameraLayer; key <= MpsKey.CameraLoad; key++)
                 DrawSetting(key);
-            }
 
             MpsGui.Header(headers["controlsDragPoint"]);
             MpsGui.WhiteLine();
-            for (MpsKey key = MpsKey.DragSelect; key <= MpsKey.DragFinger; key++)
-            {
+
+            for (var key = MpsKey.DragSelect; key <= MpsKey.DragFinger; key++)
                 DrawSetting(key);
-            }
 
             MpsGui.Header(headers["controlsScene"]);
             MpsGui.WhiteLine();
-            for (MpsKey key = MpsKey.SaveScene; key <= MpsKey.OpenSceneManager; key++)
-            {
+
+            for (var key = MpsKey.SaveScene; key <= MpsKey.OpenSceneManager; key++)
                 DrawSetting(key);
-            }
 
             GUI.enabled = !InputManager.Listening;
 
@@ -124,27 +105,41 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        public override void UpdatePanes()
+        {
+            for (var i = 0; i < rebindButtons.Length; i++)
+                rebindButtons[i].KeyCode = InputManager.GetActionKey((MpsKey)i);
+        }
+
+        protected override void ReloadTranslation()
+        {
+            for (var i = 0; i < rebindButtons.Length; i++)
+                actionLabels[i] = Translation.Get("controls", actionTranslationKeys[i]);
+
+            for (var i = 0; i < headerTranslationKeys.Length; i++)
+                headers[headerTranslationKeys[i]] = Translation.Get("settingsHeaders", headerTranslationKeys[i]);
+
+            reloadTranslationButton.Label = Translation.Get("settingsLabels", "reloadTranslation");
+            reloadAllPresetsButton.Label = Translation.Get("settingsLabels", "reloadAllPresets");
+        }
+
         private void DrawSetting(MpsKey key)
         {
-            int keyIndex = (int)key;
+            var keyIndex = (int)key;
+
             GUILayout.BeginHorizontal();
             GUILayout.Label(actionLabels[keyIndex]);
             GUILayout.FlexibleSpace();
             rebindButtons[keyIndex].Draw(GUILayout.Width(90f));
+
             if (GUILayout.Button("×", GUILayout.ExpandWidth(false)))
             {
                 rebindButtons[keyIndex].KeyCode = KeyCode.None;
                 InputManager.Rebind(key, KeyCode.None);
             }
+
             GUILayout.EndHorizontal();
         }
 
-        public override void UpdatePanes()
-        {
-            for (int i = 0; i < rebindButtons.Length; i++)
-            {
-                rebindButtons[i].KeyCode = InputManager.GetActionKey((MpsKey)i);
-            }
-        }
     }
 }

+ 49 - 29
src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/MaidSwitcherPane.cs

@@ -14,13 +14,13 @@ namespace MeidoPhotoStudio.Plugin
             this.meidoManager = meidoManager;
             this.meidoManager.UpdateMeido += (s, a) => UpdatePane();
 
-            previousButton = new Button("<");
+            previousButton = new("<");
             previousButton.ControlEvent += (s, a) => ChangeMaid(-1);
 
-            nextButton = new Button(">");
+            nextButton = new(">");
             nextButton.ControlEvent += (s, a) => ChangeMaid(1);
 
-            editToggle = new Toggle("Edit", true);
+            editToggle = new("Edit", true);
             editToggle.ControlEvent += (s, a) => SetEditMaid();
         }
 
@@ -29,20 +29,35 @@ namespace MeidoPhotoStudio.Plugin
             const float boxSize = 70;
             const int margin = (int)(boxSize / 2.8f);
 
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button);
+            var buttonStyle = new GUIStyle(GUI.skin.button);
+
             buttonStyle.margin.top = margin;
 
-            GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
+            var labelStyle = new GUIStyle(GUI.skin.label);
+
             labelStyle.margin.top = margin;
 
-            GUIStyle boxStyle = new GUIStyle(GUI.skin.box) { margin = new RectOffset(0, 0, 0, 0) };
-            GUIStyle horizontalStyle = new GUIStyle { padding = new RectOffset(4, 4, 0, 0) };
+            var boxStyle = new GUIStyle(GUI.skin.box)
+            {
+                margin = new RectOffset(0, 0, 0, 0),
+            };
 
-            GUILayoutOption[] buttonOptions = new[] { GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(false) };
-            GUILayoutOption[] boxLayoutOptions = new[] { GUILayout.Height(boxSize), GUILayout.Width(boxSize) };
+            var horizontalStyle = new GUIStyle
+            {
+                padding = new RectOffset(4, 4, 0, 0),
+            };
+
+            var buttonOptions = new[] {
+                GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(false)
+            };
+
+            var boxLayoutOptions = new[] {
+                GUILayout.Height(boxSize), GUILayout.Width(boxSize)
+            };
 
             GUI.enabled = meidoManager.HasActiveMeido;
-            Meido meido = meidoManager.ActiveMeido;
+
+            var meido = meidoManager.ActiveMeido;
 
             GUILayout.BeginHorizontal(horizontalStyle, GUILayout.Height(boxSize));
 
@@ -50,10 +65,12 @@ namespace MeidoPhotoStudio.Plugin
 
             GUILayout.Space(20);
 
-            if (meidoManager.HasActiveMeido && meido.Portrait) MpsGui.DrawTexture(meido.Portrait, boxLayoutOptions);
-            else GUILayout.Box(GUIContent.none, boxStyle, boxLayoutOptions);
+            if (meidoManager.HasActiveMeido && meido.Portrait)
+                MpsGui.DrawTexture(meido.Portrait, boxLayoutOptions);
+            else
+                GUILayout.Box(GUIContent.none, boxStyle, boxLayoutOptions);
 
-            string label = meidoManager.HasActiveMeido ? $"{meido.LastName}\n{meido.FirstName}" : string.Empty;
+            var label = meidoManager.HasActiveMeido ? $"{meido.LastName}\n{meido.FirstName}" : string.Empty;
 
             GUILayout.Label(label, labelStyle, GUILayout.ExpandWidth(false));
 
@@ -63,35 +80,38 @@ namespace MeidoPhotoStudio.Plugin
 
             GUILayout.EndHorizontal();
 
-            Rect previousRect = GUILayoutUtility.GetLastRect();
+            var previousRect = GUILayoutUtility.GetLastRect();
 
-            if (MeidoPhotoStudio.EditMode) editToggle.Draw(new Rect(previousRect.x + 4f, previousRect.y, 40f, 20f));
+            if (MeidoPhotoStudio.EditMode)
+                editToggle.Draw(new Rect(previousRect.x + 4f, previousRect.y, 40f, 20f));
 
-            Rect labelRect = new Rect(previousRect.width - 45f, previousRect.y, 40f, 20f);
-            GUIStyle slotStyle = new GUIStyle()
+            var labelRect = new Rect(previousRect.width - 45f, previousRect.y, 40f, 20f);
+            var slotStyle = new GUIStyle()
             {
                 alignment = TextAnchor.UpperRight,
-                fontSize = 13
+                fontSize = 13,
             };
+
             slotStyle.padding.right = 5;
             slotStyle.normal.textColor = Color.white;
 
-            if (meidoManager.HasActiveMeido) GUI.Label(labelRect, $"{meidoManager.ActiveMeido.Slot + 1}", slotStyle);
+            if (meidoManager.HasActiveMeido)
+                GUI.Label(labelRect, $"{meidoManager.ActiveMeido.Slot + 1}", slotStyle);
         }
 
         public override void UpdatePane()
         {
-            if (meidoManager.HasActiveMeido)
-            {
-                this.updating = true;
-                editToggle.Value = meidoManager.ActiveMeido.IsEditMaid;
-                this.updating = false;
-            }
+            if (!meidoManager.HasActiveMeido)
+                return;
+
+            updating = true;
+            editToggle.Value = meidoManager.ActiveMeido.IsEditMaid;
+            updating = false;
         }
 
         private void ChangeMaid(int dir)
         {
-            int selected = Utility.Wrap(
+            var selected = Utility.Wrap(
                 meidoManager.SelectedMeido + (int)Mathf.Sign(dir), 0, meidoManager.ActiveMeidoList.Count
             );
 
@@ -100,20 +120,20 @@ namespace MeidoPhotoStudio.Plugin
 
         private void SetEditMaid()
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             if (!editToggle.Value)
             {
                 updating = true;
                 editToggle.Value = true;
                 updating = false;
+
                 return;
             }
 
             if (meidoManager.HasActiveMeido)
-            {
                 meidoManager.SetEditMaid(meidoManager.ActiveMeido);
-            }
         }
     }
 }

+ 15 - 10
src/MeidoPhotoStudio.Plugin/GUI/Panes/OtherPanes/TabsPane.cs

@@ -6,40 +6,45 @@ namespace MeidoPhotoStudio.Plugin
     public class TabsPane : BasePane
     {
         private static readonly string[] tabNames = { "call", "pose", "face", "bg", "bg2" };
+
         private readonly SelectionGrid Tabs;
+
         private Constants.Window selectedTab;
+
+        public event EventHandler TabChange;
+
         public Constants.Window SelectedTab
         {
             get => selectedTab;
             set => Tabs.SelectedItemIndex = (int)value;
         }
-        public event EventHandler TabChange;
 
         public TabsPane()
         {
             Translation.ReloadTranslationEvent += (s, a) => ReloadTranslation();
-            Tabs = new SelectionGrid(Translation.GetArray("tabs", tabNames));
+            Tabs = new(Translation.GetArray("tabs", tabNames));
             Tabs.ControlEvent += (s, a) => OnChangeTab();
         }
 
+        public override void Draw()
+        {
+            Tabs.Draw(GUILayout.ExpandWidth(false));
+            MpsGui.BlackLine();
+        }
+
         protected override void ReloadTranslation()
         {
             updating = true;
             Tabs.SetItems(Translation.GetArray("tabs", tabNames), Tabs.SelectedItemIndex);
             updating = false;
         }
-
         private void OnChangeTab()
         {
-            if (updating) return;
+            if (updating)
+                return;
+
             selectedTab = (Constants.Window)Tabs.SelectedItemIndex;
             TabChange?.Invoke(null, EventArgs.Empty);
         }
-
-        public override void Draw()
-        {
-            Tabs.Draw(GUILayout.ExpandWidth(false));
-            MpsGui.BlackLine();
-        }
     }
 }

+ 28 - 22
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/CopyPosePane.cs

@@ -1,5 +1,4 @@
 using System.Linq;
-using System.Collections.Generic;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
@@ -9,35 +8,30 @@ namespace MeidoPhotoStudio.Plugin
         private readonly MeidoManager meidoManager;
         private readonly Button copyButton;
         private readonly Dropdown meidoDropdown;
+
         private int[] copyMeidoSlot;
-        private bool PlentyOfMaids => meidoManager.ActiveMeidoList.Count >= 2;
-        private Meido FromMeido => meidoManager.HasActiveMeido
-            ? meidoManager.ActiveMeidoList[copyMeidoSlot[meidoDropdown.SelectedItemIndex]]
-            : null;
         private string copyIKHeader;
 
+        private bool PlentyOfMaids =>
+            meidoManager.ActiveMeidoList.Count >= 2;
+
+        private Meido FromMeido =>
+            meidoManager.HasActiveMeido
+                ? meidoManager.ActiveMeidoList[copyMeidoSlot[meidoDropdown.SelectedItemIndex]]
+                : null;
+
         public CopyPosePane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
 
-            meidoDropdown = new Dropdown(new[] { Translation.Get("systemMessage", "noMaids") });
+            meidoDropdown = new(new[] { Translation.Get("systemMessage", "noMaids") });
 
-            copyButton = new Button(Translation.Get("copyPosePane", "copyButton"));
+            copyButton = new(Translation.Get("copyPosePane", "copyButton"));
             copyButton.ControlEvent += (s, a) => CopyPose();
 
             copyIKHeader = Translation.Get("copyPosePane", "header");
         }
 
-        protected override void ReloadTranslation()
-        {
-            if (!PlentyOfMaids)
-            {
-                meidoDropdown.SetDropdownItem(0, Translation.Get("systemMessage", "noMaids"));
-            }
-            copyButton.Label = Translation.Get("copyPosePane", "copyButton");
-            copyIKHeader = Translation.Get("copyPosePane", "header");
-        }
-
         public override void Draw()
         {
             GUI.enabled = PlentyOfMaids;
@@ -53,28 +47,40 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
-        public override void UpdatePane() => SetMeidoDropdown();
+        public override void UpdatePane() =>
+            SetMeidoDropdown();
+
+        protected override void ReloadTranslation()
+        {
+            if (!PlentyOfMaids)
+                meidoDropdown.SetDropdownItem(0, Translation.Get("systemMessage", "noMaids"));
+
+            copyButton.Label = Translation.Get("copyPosePane", "copyButton");
+            copyIKHeader = Translation.Get("copyPosePane", "header");
+        }
 
         private void CopyPose()
         {
-            if (meidoManager.ActiveMeidoList.Count >= 2) meidoManager.ActiveMeido.CopyPose(FromMeido);
+            if (meidoManager.ActiveMeidoList.Count >= 2)
+                meidoManager.ActiveMeido.CopyPose(FromMeido);
         }
 
         private void SetMeidoDropdown()
         {
             if (meidoManager.ActiveMeidoList.Count >= 2)
             {
-                IEnumerable<Meido> copyMeidoList = meidoManager.ActiveMeidoList
+                var copyMeidoList = meidoManager.ActiveMeidoList
                     .Where(meido => meido.Slot != meidoManager.ActiveMeido.Slot);
 
                 copyMeidoSlot = copyMeidoList.Select(meido => meido.Slot).ToArray();
 
-                string[] dropdownList = copyMeidoList
+                var dropdownList = copyMeidoList
                     .Select((meido, i) => $"{copyMeidoSlot[i] + 1}: {meido.LastName} {meido.FirstName}").ToArray();
 
                 meidoDropdown.SetDropdownItems(dropdownList, 0);
             }
-            else meidoDropdown.SetDropdownItems(new[] { Translation.Get("systemMessage", "noMaids") });
+            else
+                meidoDropdown.SetDropdownItems(new[] { Translation.Get("systemMessage", "noMaids") });
         }
     }
 }

+ 24 - 14
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/GravityControlPane.cs

@@ -8,19 +8,20 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Toggle hairToggle;
         private readonly Toggle skirtToggle;
         private readonly Toggle globalToggle;
+
         private string header;
 
         public GravityControlPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
 
-            hairToggle = new Toggle(Translation.Get("gravityControlPane", "hairToggle"));
+            hairToggle = new(Translation.Get("gravityControlPane", "hairToggle"));
             hairToggle.ControlEvent += (s, a) => ToggleGravity(hairToggle.Value, skirt: false);
 
-            skirtToggle = new Toggle(Translation.Get("gravityControlPane", "skirtToggle"));
+            skirtToggle = new(Translation.Get("gravityControlPane", "skirtToggle"));
             skirtToggle.ControlEvent += (s, a) => ToggleGravity(skirtToggle.Value, skirt: true);
 
-            globalToggle = new Toggle(Translation.Get("gravityControlPane", "globalToggle"));
+            globalToggle = new(Translation.Get("gravityControlPane", "globalToggle"));
             globalToggle.ControlEvent += (s, a) => SetGlobalGravity(globalToggle.Value);
 
             header = Translation.Get("gravityControlPane", "gravityHeader");
@@ -36,13 +37,15 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void Draw()
         {
-            bool enabled = meidoManager.HasActiveMeido;
+            var enabled = meidoManager.HasActiveMeido;
+
             GUI.enabled = enabled;
 
             MpsGui.Header(header);
             MpsGui.WhiteLine();
 
-            Meido meido = meidoManager.ActiveMeido;
+            var meido = meidoManager.ActiveMeido;
+
             GUILayout.BeginHorizontal();
 
             GUI.enabled = enabled && meido.HairGravityControl.Valid;
@@ -61,9 +64,10 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void UpdatePane()
         {
-            if (!meidoManager.HasActiveMeido) return;
+            if (!meidoManager.HasActiveMeido)
+                return;
 
-            Meido meido = meidoManager.ActiveMeido;
+            var meido = meidoManager.ActiveMeido;
 
             updating = true;
 
@@ -75,23 +79,29 @@ namespace MeidoPhotoStudio.Plugin
 
         private void ToggleGravity(bool value, bool skirt = false)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             if (meidoManager.GlobalGravity)
             {
-                foreach (Meido meido in meidoManager.ActiveMeidoList)
+                foreach (var meido in meidoManager.ActiveMeidoList)
                 {
-                    if (skirt) meido.SkirtGravityActive = value;
-                    else meido.HairGravityActive = value;
+                    if (skirt)
+                        meido.SkirtGravityActive = value;
+                    else
+                        meido.HairGravityActive = value;
                 }
             }
             else
             {
-                if (skirt) meidoManager.ActiveMeido.SkirtGravityActive = value;
-                else meidoManager.ActiveMeido.HairGravityActive = value;
+                if (skirt)
+                    meidoManager.ActiveMeido.SkirtGravityActive = value;
+                else
+                    meidoManager.ActiveMeido.HairGravityActive = value;
             }
         }
 
-        private void SetGlobalGravity(bool value) => meidoManager.GlobalGravity = value;
+        private void SetGlobalGravity(bool value) =>
+            meidoManager.GlobalGravity = value;
     }
 }

+ 32 - 21
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/HandPresetPane.cs

@@ -1,5 +1,5 @@
-using System.IO;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using UnityEngine;
 
@@ -16,38 +16,46 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Button previousPresetButton;
         private readonly Button leftHandButton;
         private readonly Button rightHandButton;
-        private string SelectedCategory => Constants.CustomHandGroupList[presetCategoryDropdown.SelectedItemIndex];
-        private List<string> CurrentPresetList => Constants.CustomHandDict[SelectedCategory];
-        private string CurrentPreset => CurrentPresetList[presetDropdown.SelectedItemIndex];
+
         private string previousCategory;
         private bool presetListEnabled = true;
 
+        private string SelectedCategory =>
+            Constants.CustomHandGroupList[presetCategoryDropdown.SelectedItemIndex];
+
+        private List<string> CurrentPresetList =>
+            Constants.CustomHandDict[SelectedCategory];
+
+        private string CurrentPreset =>
+            CurrentPresetList[presetDropdown.SelectedItemIndex];
+
         public HandPresetPane(MeidoManager meidoManager)
         {
             Constants.CustomHandChange += OnPresetChange;
+
             this.meidoManager = meidoManager;
 
-            presetCategoryDropdown = new Dropdown(Constants.CustomHandGroupList.ToArray());
+            presetCategoryDropdown = new(Constants.CustomHandGroupList.ToArray());
             presetCategoryDropdown.SelectionChange += (s, a) => ChangePresetCategory();
 
-            nextCategoryButton = new Button(">");
+            nextCategoryButton = new(">");
             nextCategoryButton.ControlEvent += (s, a) => presetCategoryDropdown.Step(1);
 
-            previousCategoryButton = new Button("<");
+            previousCategoryButton = new("<");
             previousCategoryButton.ControlEvent += (s, a) => presetCategoryDropdown.Step(-1);
 
-            presetDropdown = new Dropdown(UIPresetList());
+            presetDropdown = new(UIPresetList());
 
-            nextPresetButton = new Button(">");
+            nextPresetButton = new(">");
             nextPresetButton.ControlEvent += (s, a) => presetDropdown.Step(1);
 
-            previousPresetButton = new Button("<");
+            previousPresetButton = new("<");
             previousPresetButton.ControlEvent += (s, a) => presetDropdown.Step(-1);
 
-            leftHandButton = new Button(Translation.Get("handPane", "leftHand"));
+            leftHandButton = new(Translation.Get("handPane", "leftHand"));
             leftHandButton.ControlEvent += (s, a) => SetHandPreset(right: false);
 
-            rightHandButton = new Button(Translation.Get("handPane", "rightHand"));
+            rightHandButton = new(Translation.Get("handPane", "rightHand"));
             rightHandButton.ControlEvent += (s, a) => SetHandPreset(right: true);
 
             previousCategory = SelectedCategory;
@@ -58,13 +66,15 @@ namespace MeidoPhotoStudio.Plugin
         {
             leftHandButton.Label = Translation.Get("handPane", "leftHand");
             rightHandButton.Label = Translation.Get("handPane", "rightHand");
-            if (CurrentPresetList.Count == 0) presetDropdown.SetDropdownItems(UIPresetList());
+
+            if (CurrentPresetList.Count == 0)
+                presetDropdown.SetDropdownItems(UIPresetList());
         }
 
         public override void Draw()
         {
-            GUILayoutOption dropdownWidth = GUILayout.Width(156f);
-            GUILayoutOption noExpandWidth = GUILayout.ExpandWidth(false);
+            var dropdownWidth = GUILayout.Width(156f);
+            var noExpandWidth = GUILayout.ExpandWidth(false);
 
             GUI.enabled = meidoManager.HasActiveMeido;
 
@@ -93,7 +103,9 @@ namespace MeidoPhotoStudio.Plugin
         private void ChangePresetCategory()
         {
             presetListEnabled = CurrentPresetList.Count > 0;
-            if (previousCategory == SelectedCategory) presetDropdown.SelectedItemIndex = 0;
+
+            if (previousCategory == SelectedCategory)
+                presetDropdown.SelectedItemIndex = 0;
             else
             {
                 previousCategory = SelectedCategory;
@@ -103,7 +115,8 @@ namespace MeidoPhotoStudio.Plugin
 
         private void SetHandPreset(bool right = false)
         {
-            if (!meidoManager.HasActiveMeido) return;
+            if (!meidoManager.HasActiveMeido)
+                return;
 
             meidoManager.ActiveMeido.SetHandPreset(CurrentPreset, right);
         }
@@ -124,11 +137,9 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private string[] UIPresetList()
-        {
-            return CurrentPresetList.Count == 0
+        private string[] UIPresetList() =>
+            CurrentPresetList.Count == 0
                 ? new[] { Translation.Get("handPane", "noPresetsMessage") }
                 : CurrentPresetList.Select(Path.GetFileNameWithoutExtension).ToArray();
-        }
     }
 }

+ 164 - 131
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidDressingPane.cs

@@ -1,11 +1,10 @@
-using System;
 using System.Collections.Generic;
 using UnityEngine;
+using static MeidoPhotoStudio.Plugin.Meido;
 using static TBody;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using static Meido;
     public class MaidDressingPane : BasePane
     {
         public static readonly SlotID[] ClothingSlots =
@@ -35,6 +34,8 @@ namespace MeidoPhotoStudio.Plugin
             SlotID.accKami_2_, SlotID.accKami_3_
         };
 
+        private static readonly string[] maskLabels = { "all", "underwear", "nude" };
+
         private readonly MeidoManager meidoManager;
         private readonly Dictionary<SlotID, Toggle> clothingToggles;
         private readonly Dictionary<SlotID, bool> loadedSlots;
@@ -43,51 +44,168 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Toggle curlingFrontToggle;
         private readonly Toggle curlingBackToggle;
         private readonly Toggle pantsuShiftToggle;
+
         private bool detailedClothing;
-        private static readonly string[] maskLabels = { "all", "underwear", "nude" };
 
         public MaidDressingPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
 
-            clothingToggles = new Dictionary<SlotID, Toggle>(ClothingSlots.Length);
-            loadedSlots = new Dictionary<SlotID, bool>(ClothingSlots.Length);
-            foreach (SlotID slot in ClothingSlots)
+            clothingToggles = new(ClothingSlots.Length);
+            loadedSlots = new(ClothingSlots.Length);
+
+            foreach (var slot in ClothingSlots)
             {
                 var slotToggle = new Toggle(Translation.Get("clothing", slot.ToString()));
+
                 slotToggle.ControlEvent += (s, a) => ToggleClothing(slot, slotToggle.Value);
                 clothingToggles.Add(slot, slotToggle);
                 loadedSlots[slot] = true;
             }
 
-            detailedClothingToggle = new Toggle(Translation.Get("clothing", "detail"));
+            detailedClothingToggle = new(Translation.Get("clothing", "detail"));
             detailedClothingToggle.ControlEvent += (s, a) => UpdateDetailedClothing();
 
-            curlingFrontToggle = new Toggle(Translation.Get("clothing", "curlingFront"));
+            curlingFrontToggle = new(Translation.Get("clothing", "curlingFront"));
             curlingFrontToggle.ControlEvent += (s, a) => ToggleCurling(Curl.Front, curlingFrontToggle.Value);
-            curlingBackToggle = new Toggle(Translation.Get("clothing", "curlingBack"));
+
+            curlingBackToggle = new(Translation.Get("clothing", "curlingBack"));
             curlingBackToggle.ControlEvent += (s, a) => ToggleCurling(Curl.Back, curlingBackToggle.Value);
-            pantsuShiftToggle = new Toggle(Translation.Get("clothing", "shiftPanties"));
+
+            pantsuShiftToggle = new(Translation.Get("clothing", "shiftPanties"));
             pantsuShiftToggle.ControlEvent += (s, a) => ToggleCurling(Curl.Shift, pantsuShiftToggle.Value);
 
-            maskModeGrid = new SelectionGrid(Translation.GetArray("clothing", maskLabels));
+            maskModeGrid = new(Translation.GetArray("clothing", maskLabels));
             maskModeGrid.ControlEvent += (s, a) => SetMaskMode((Mask)maskModeGrid.SelectedItemIndex);
 
             UpdateDetailedClothing();
         }
 
+        public override void UpdatePane()
+        {
+            if (!meidoManager.HasActiveMeido)
+                return;
+
+            updating = true;
+
+            var meido = meidoManager.ActiveMeido;
+            var body = meido.Maid.body0;
+
+            foreach (var clothingSlot in ClothingSlots)
+            {
+                var toggleValue = false;
+                var hasSlot = false;
+
+                if (clothingSlot == SlotID.wear)
+                {
+                    foreach (var wearSlot in WearSlots)
+                    {
+                        if (body.GetMask(wearSlot))
+                            toggleValue = true;
+
+                        if (body.GetSlotLoaded(wearSlot))
+                            hasSlot = true;
+
+                        if (hasSlot && toggleValue)
+                            break;
+                    }
+                }
+                else if (clothingSlot == SlotID.megane)
+                {
+                    toggleValue = body.GetMask(SlotID.megane) || body.GetMask(SlotID.accHead);
+                    hasSlot = body.GetSlotLoaded(SlotID.megane) || body.GetSlotLoaded(SlotID.accHead);
+                }
+                else if (!detailedClothing && clothingSlot == SlotID.headset)
+                {
+                    foreach (var headwearSlot in HeadwearSlots)
+                    {
+                        if (body.GetMask(headwearSlot))
+                            toggleValue = true;
+
+                        if (body.GetSlotLoaded(headwearSlot))
+                            hasSlot = true;
+
+                        if (hasSlot && toggleValue)
+                            break;
+                    }
+                }
+                else
+                {
+                    toggleValue = body.GetMask(clothingSlot);
+                    hasSlot = body.GetSlotLoaded(clothingSlot);
+                }
+
+                clothingToggles[clothingSlot].Value = hasSlot && toggleValue;
+                loadedSlots[clothingSlot] = hasSlot;
+            }
+
+            curlingFrontToggle.Value = meido.CurlingFront;
+            curlingBackToggle.Value = meido.CurlingBack;
+            pantsuShiftToggle.Value = meido.PantsuShift;
+
+            var maskMode = meido.CurrentMaskMode;
+
+            maskModeGrid.SelectedItemIndex = maskMode == MaskMode.Nude ? (int)Mask.Nude : (int)maskMode;
+
+            updating = false;
+        }
+
+        public override void Draw()
+        {
+            GUI.enabled = Enabled = meidoManager.HasActiveMeido;
+
+            detailedClothingToggle.Draw();
+
+            MpsGui.BlackLine();
+
+            maskModeGrid.Draw();
+
+            MpsGui.BlackLine();
+
+            DrawSlotGroup(SlotID.wear, SlotID.skirt);
+            DrawSlotGroup(SlotID.bra, SlotID.panz);
+            DrawSlotGroup(SlotID.headset, SlotID.megane);
+            DrawSlotGroup(SlotID.accUde, SlotID.glove, SlotID.accSenaka);
+            DrawSlotGroup(SlotID.stkg, SlotID.shoes, SlotID.body);
+
+            if (detailedClothing)
+            {
+                MpsGui.BlackLine();
+                DrawSlotGroup(SlotID.accShippo, SlotID.accHat);
+                DrawSlotGroup(SlotID.accKami_1_, SlotID.accKami_2_, SlotID.accKami_3_);
+                DrawSlotGroup(SlotID.accKamiSubL, SlotID.accKamiSubR);
+                DrawSlotGroup(SlotID.accMiMiL, SlotID.accMiMiR);
+                DrawSlotGroup(SlotID.accNipL, SlotID.accNipR);
+                DrawSlotGroup(SlotID.accHana, SlotID.accKubi, SlotID.accKubiwa);
+                DrawSlotGroup(SlotID.accHeso, SlotID.accAshi, SlotID.accXXX);
+            }
+
+            MpsGui.BlackLine();
+
+            GUILayout.BeginHorizontal();
+            curlingFrontToggle.Draw();
+            GUILayout.FlexibleSpace();
+            curlingBackToggle.Draw();
+            GUILayout.FlexibleSpace();
+            pantsuShiftToggle.Draw();
+            GUILayout.FlexibleSpace();
+            GUILayout.EndHorizontal();
+
+            GUI.enabled = true;
+        }
+
         protected override void ReloadTranslation()
         {
-            foreach (SlotID slot in ClothingSlots)
+            foreach (var slot in ClothingSlots)
             {
-                Toggle clothingToggle = clothingToggles[slot];
+                var clothingToggle = clothingToggles[slot];
+
                 if (slot == SlotID.headset)
-                {
                     clothingToggle.Label = detailedClothing
                         ? Translation.Get("clothing", "headset")
                         : Translation.Get("clothing", "headwear");
-                }
-                else clothingToggle.Label = Translation.Get("clothing", slot.ToString());
+                else
+                    clothingToggle.Label = Translation.Get("clothing", slot.ToString());
             }
 
             updating = true;
@@ -102,132 +220,90 @@ namespace MeidoPhotoStudio.Plugin
 
         private void ToggleClothing(SlotID slot, bool enabled)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             if (slot == SlotID.body)
             {
                 meidoManager.ActiveMeido.SetBodyMask(enabled);
+
                 return;
             }
 
-            TBody body = meidoManager.ActiveMeido.Maid.body0;
+            var body = meidoManager.ActiveMeido.Maid.body0;
 
             if (!detailedClothing && slot == SlotID.headset)
             {
                 updating = true;
-                foreach (SlotID wearSlot in HeadwearSlots)
+
+                foreach (var wearSlot in HeadwearSlots)
                 {
                     body.SetMask(wearSlot, enabled);
                     clothingToggles[wearSlot].Value = enabled;
                 }
+
                 updating = false;
             }
             else
             {
                 if (slot == SlotID.wear)
-                {
-                    foreach (SlotID wearSlot in WearSlots) body.SetMask(wearSlot, enabled);
-                }
+                    foreach (var wearSlot in WearSlots)
+                        body.SetMask(wearSlot, enabled);
                 else if (slot == SlotID.megane)
                 {
                     body.SetMask(SlotID.megane, enabled);
                     body.SetMask(SlotID.accHead, enabled);
                 }
-                else body.SetMask(slot, enabled);
+                else
+                    body.SetMask(slot, enabled);
             }
         }
 
         private void ToggleCurling(Curl curl, bool enabled)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             meidoManager.ActiveMeido.SetCurling(curl, enabled);
 
-            if (!enabled) return;
+            if (!enabled)
+                return;
 
             updating = true;
-            if (curl == Curl.Front && curlingBackToggle.Value) curlingBackToggle.Value = false;
-            else if (curl == Curl.Back && curlingFrontToggle.Value) curlingFrontToggle.Value = false;
+
+            if (curl == Curl.Front && curlingBackToggle.Value)
+                curlingBackToggle.Value = false;
+            else if (curl == Curl.Back && curlingFrontToggle.Value)
+                curlingFrontToggle.Value = false;
 
             updating = false;
         }
 
         private void SetMaskMode(Mask mask)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
             meidoManager.ActiveMeido.SetMaskMode(mask);
 
             UpdatePane();
         }
 
-        public override void UpdatePane()
-        {
-            if (!meidoManager.HasActiveMeido) return;
-
-            updating = true;
-
-            Meido meido = meidoManager.ActiveMeido;
-            TBody body = meido.Maid.body0;
-
-            foreach (SlotID clothingSlot in ClothingSlots)
-            {
-                var toggleValue = false;
-                var hasSlot = false;
-                if (clothingSlot == SlotID.wear)
-                {
-                    foreach (SlotID wearSlot in WearSlots)
-                    {
-                        if (body.GetMask(wearSlot)) toggleValue = true;
-                        if (body.GetSlotLoaded(wearSlot)) hasSlot = true;
-                        if (hasSlot && toggleValue) break;
-                    }
-                }
-                else if (clothingSlot == SlotID.megane)
-                {
-                    toggleValue = body.GetMask(SlotID.megane) || body.GetMask(SlotID.accHead);
-                    hasSlot = body.GetSlotLoaded(SlotID.megane) || body.GetSlotLoaded(SlotID.accHead);
-                }
-                else if (!detailedClothing && clothingSlot == SlotID.headset)
-                {
-                    foreach (SlotID headwearSlot in HeadwearSlots)
-                    {
-                        if (body.GetMask(headwearSlot)) toggleValue = true;
-                        if (body.GetSlotLoaded(headwearSlot)) hasSlot = true;
-                        if (hasSlot && toggleValue) break;
-                    }
-                }
-                else
-                {
-                    toggleValue = body.GetMask(clothingSlot);
-                    hasSlot = body.GetSlotLoaded(clothingSlot);
-                }
-
-                clothingToggles[clothingSlot].Value = hasSlot && toggleValue;
-                loadedSlots[clothingSlot] = hasSlot;
-            }
-
-            curlingFrontToggle.Value = meido.CurlingFront;
-            curlingBackToggle.Value = meido.CurlingBack;
-            pantsuShiftToggle.Value = meido.PantsuShift;
-
-            MaskMode maskMode = meido.CurrentMaskMode;
-
-            maskModeGrid.SelectedItemIndex = maskMode == MaskMode.Nude ? (int)Mask.Nude : (int)maskMode;
-
-            updating = false;
-        }
-
         private void DrawSlotGroup(params SlotID[] slots)
         {
             GUILayout.BeginHorizontal();
+
             for (var i = 0; i < slots.Length; i++)
             {
-                SlotID slot = slots[i];
+                var slot = slots[i];
+
                 GUI.enabled = Enabled && loadedSlots[slot];
                 clothingToggles[slot].Draw();
-                if (i < slots.Length - 1) GUILayout.FlexibleSpace();
+
+                if (i < slots.Length - 1)
+                    GUILayout.FlexibleSpace();
             }
+
             GUILayout.EndHorizontal();
 
             GUI.enabled = Enabled;
@@ -239,51 +315,8 @@ namespace MeidoPhotoStudio.Plugin
             clothingToggles[SlotID.headset].Label = detailedClothing
                 ? Translation.Get("clothing", "headset")
                 : Translation.Get("clothing", "headwear");
-            UpdatePane();
-        }
-
-        public override void Draw()
-        {
-            GUI.enabled = Enabled = meidoManager.HasActiveMeido;
-
-            detailedClothingToggle.Draw();
-
-            MpsGui.BlackLine();
-
-            maskModeGrid.Draw();
-
-            MpsGui.BlackLine();
-
-            DrawSlotGroup(SlotID.wear, SlotID.skirt);
-            DrawSlotGroup(SlotID.bra, SlotID.panz);
-            DrawSlotGroup(SlotID.headset, SlotID.megane);
-            DrawSlotGroup(SlotID.accUde, SlotID.glove, SlotID.accSenaka);
-            DrawSlotGroup(SlotID.stkg, SlotID.shoes, SlotID.body);
-
-            if (detailedClothing)
-            {
-                MpsGui.BlackLine();
-                DrawSlotGroup(SlotID.accShippo, SlotID.accHat);
-                DrawSlotGroup(SlotID.accKami_1_, SlotID.accKami_2_, SlotID.accKami_3_);
-                DrawSlotGroup(SlotID.accKamiSubL, SlotID.accKamiSubR);
-                DrawSlotGroup(SlotID.accMiMiL, SlotID.accMiMiR);
-                DrawSlotGroup(SlotID.accNipL, SlotID.accNipR);
-                DrawSlotGroup(SlotID.accHana, SlotID.accKubi, SlotID.accKubiwa);
-                DrawSlotGroup(SlotID.accHeso, SlotID.accAshi, SlotID.accXXX);
-            }
 
-            MpsGui.BlackLine();
-
-            GUILayout.BeginHorizontal();
-            curlingFrontToggle.Draw();
-            GUILayout.FlexibleSpace();
-            curlingBackToggle.Draw();
-            GUILayout.FlexibleSpace();
-            pantsuShiftToggle.Draw();
-            GUILayout.FlexibleSpace();
-            GUILayout.EndHorizontal();
-
-            GUI.enabled = true;
+            UpdatePane();
         }
     }
 }

+ 32 - 22
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidFreeLookPane.cs

@@ -9,68 +9,69 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Slider lookYSlider;
         private readonly Toggle headToCamToggle;
         private readonly Toggle eyeToCamToggle;
+
         private string bindLabel;
 
         public MaidFaceLookPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
-            lookXSlider = new Slider(Translation.Get("freeLookPane", "xSlider"), -0.6f, 0.6f);
+
+            lookXSlider = new(Translation.Get("freeLookPane", "xSlider"), -0.6f, 0.6f);
             lookXSlider.ControlEvent += (s, a) => SetMaidLook();
 
-            lookYSlider = new Slider(Translation.Get("freeLookPane", "ySlider"), 0.5f, -0.55f);
+            lookYSlider = new(Translation.Get("freeLookPane", "ySlider"), 0.5f, -0.55f);
             lookYSlider.ControlEvent += (s, a) => SetMaidLook();
 
-            headToCamToggle = new Toggle(Translation.Get("freeLookPane", "headToCamToggle"));
+            headToCamToggle = new(Translation.Get("freeLookPane", "headToCamToggle"));
             headToCamToggle.ControlEvent += (s, a) => SetHeadToCam(headToCamToggle.Value, eye: false);
 
-            eyeToCamToggle = new Toggle(Translation.Get("freeLookPane", "eyeToCamToggle"));
+            eyeToCamToggle = new(Translation.Get("freeLookPane", "eyeToCamToggle"));
             eyeToCamToggle.ControlEvent += (s, a) => SetHeadToCam(eyeToCamToggle.Value, eye: true);
 
             bindLabel = Translation.Get("freeLookPane", "bindLabel");
         }
 
-        protected override void ReloadTranslation()
-        {
-            lookXSlider.Label = Translation.Get("freeLookPane", "xSlider");
-            lookYSlider.Label = Translation.Get("freeLookPane", "ySlider");
-            headToCamToggle.Label = Translation.Get("freeLookPane", "headToCamToggle");
-            eyeToCamToggle.Label = Translation.Get("freeLookPane", "eyeToCamToggle");
-            bindLabel = Translation.Get("freeLookPane", "bindLabel");
-        }
-
         public void SetHeadToCam(bool value, bool eye = false)
         {
-            if (updating) return;
+            if (updating)
+                return;
 
-            Meido meido = meidoManager.ActiveMeido;
+            var meido = meidoManager.ActiveMeido;
 
-            if (eye) meido.EyeToCam = value;
-            else meido.HeadToCam = value;
+            if (eye)
+                meido.EyeToCam = value;
+            else
+                meido.HeadToCam = value;
         }
 
         public void SetMaidLook()
         {
-            if (updating) return;
+            if (updating)
+                return;
+
+            var body = meidoManager.ActiveMeido.Body;
 
-            TBody body = meidoManager.ActiveMeido.Body;
             body.offsetLookTarget = new Vector3(lookYSlider.Value, 1f, lookXSlider.Value);
         }
 
         public void SetBounds()
         {
-            float left = 0.5f;
-            float right = -0.55f;
+            var left = 0.5f;
+            var right = -0.55f;
+
             if (meidoManager.ActiveMeido.Stop)
             {
                 left *= 0.6f;
                 right *= 0.6f;
             }
+
             lookYSlider.SetBounds(left, right);
         }
 
         public override void UpdatePane()
         {
-            Meido meido = meidoManager.ActiveMeido;
+            var meido = meidoManager.ActiveMeido;
+
             updating = true;
             SetBounds();
             lookXSlider.Value = meido.Body.offsetLookTarget.z;
@@ -98,5 +99,14 @@ namespace MeidoPhotoStudio.Plugin
 
             GUI.enabled = true;
         }
+
+        protected override void ReloadTranslation()
+        {
+            lookXSlider.Label = Translation.Get("freeLookPane", "xSlider");
+            lookYSlider.Label = Translation.Get("freeLookPane", "ySlider");
+            headToCamToggle.Label = Translation.Get("freeLookPane", "headToCamToggle");
+            eyeToCamToggle.Label = Translation.Get("freeLookPane", "eyeToCamToggle");
+            bindLabel = Translation.Get("freeLookPane", "bindLabel");
+        }
     }
 }

+ 24 - 19
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidIKPane.cs

@@ -17,31 +17,16 @@ namespace MeidoPhotoStudio.Plugin
         {
             this.meidoManager = meidoManager;
 
-            ikToggle = new Toggle(Translation.Get("maidPoseWindow", "ikToggle"), true);
+            ikToggle = new(Translation.Get("maidPoseWindow", "ikToggle"), true);
             ikToggle.ControlEvent += (s, a) => SetIK(IKToggle.IK, ikToggle.Value);
 
-            releaseIKToggle = new Toggle(Translation.Get("maidPoseWindow", "releaseToggle"));
+            releaseIKToggle = new(Translation.Get("maidPoseWindow", "releaseToggle"));
             releaseIKToggle.ControlEvent += (s, a) => SetIK(IKToggle.Release, releaseIKToggle.Value);
 
-            boneIKToggle = new Toggle(Translation.Get("maidPoseWindow", "boneToggle"));
+            boneIKToggle = new(Translation.Get("maidPoseWindow", "boneToggle"));
             boneIKToggle.ControlEvent += (s, a) => SetIK(IKToggle.Bone, boneIKToggle.Value);
         }
 
-        protected override void ReloadTranslation()
-        {
-            ikToggle.Label = Translation.Get("maidPoseWindow", "ikToggle");
-            releaseIKToggle.Label = Translation.Get("maidPoseWindow", "releaseToggle");
-            boneIKToggle.Label = Translation.Get("maidPoseWindow", "boneToggle");
-        }
-
-        private void SetIK(IKToggle toggle, bool value)
-        {
-            if (updating) return;
-            if (toggle == IKToggle.IK) meidoManager.ActiveMeido.IK = value;
-            else if (toggle == IKToggle.Release) meidoManager.ActiveMeido.Stop = false;
-            else if (toggle == IKToggle.Bone) meidoManager.ActiveMeido.Bone = value;
-        }
-
         public override void UpdatePane()
         {
             updating = true;
@@ -53,7 +38,7 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void Draw()
         {
-            bool active = meidoManager.HasActiveMeido;
+            var active = meidoManager.HasActiveMeido;
 
             GUILayout.BeginHorizontal();
             GUI.enabled = active;
@@ -67,5 +52,25 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.EndHorizontal();
             GUI.enabled = true;
         }
+
+        protected override void ReloadTranslation()
+        {
+            ikToggle.Label = Translation.Get("maidPoseWindow", "ikToggle");
+            releaseIKToggle.Label = Translation.Get("maidPoseWindow", "releaseToggle");
+            boneIKToggle.Label = Translation.Get("maidPoseWindow", "boneToggle");
+        }
+
+        private void SetIK(IKToggle toggle, bool value)
+        {
+            if (updating)
+                return;
+
+            if (toggle == IKToggle.IK)
+                meidoManager.ActiveMeido.IK = value;
+            else if (toggle == IKToggle.Release)
+                meidoManager.ActiveMeido.Stop = false;
+            else if (toggle == IKToggle.Bone)
+                meidoManager.ActiveMeido.Bone = value;
+        }
     }
 }

+ 58 - 40
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MaidPoseSelectorPane.cs

@@ -1,5 +1,5 @@
-using System.IO;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using UnityEngine;
 
@@ -8,6 +8,7 @@ namespace MeidoPhotoStudio.Plugin
     public class MaidPoseSelectorPane : BasePane
     {
         private static readonly string[] tabTranslations = new[] { "baseTab", "customTab" };
+
         private readonly MeidoManager meidoManager;
         private readonly Button poseLeftButton;
         private readonly Button poseRightButton;
@@ -16,43 +17,56 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Dropdown poseGroupDropdown;
         private readonly Dropdown poseDropdown;
         private readonly SelectionGrid poseModeGrid;
-        private Dictionary<string, List<string>> CurrentPoseDict
-            => customPoseMode ? Constants.CustomPoseDict : Constants.PoseDict;
-        private List<string> CurrentPoseGroupList
-            => customPoseMode ? Constants.CustomPoseGroupList : Constants.PoseGroupList;
-        private string SelectedPoseGroup => CurrentPoseGroupList[poseGroupDropdown.SelectedItemIndex];
-        private List<string> CurrentPoseList => CurrentPoseDict[SelectedPoseGroup];
-        private int SelectedPoseIndex => poseDropdown.SelectedItemIndex;
-        private string SelectedPose => CurrentPoseList[SelectedPoseIndex];
-        private PoseInfo CurrentPoseInfo => new PoseInfo(SelectedPoseGroup, SelectedPose, customPoseMode);
+
         private bool customPoseMode;
         private bool poseListEnabled;
         private string previousPoseGroup;
 
+        private Dictionary<string, List<string>> CurrentPoseDict =>
+            customPoseMode ? Constants.CustomPoseDict : Constants.PoseDict;
+
+        private List<string> CurrentPoseGroupList =>
+            customPoseMode ? Constants.CustomPoseGroupList : Constants.PoseGroupList;
+
+        private string SelectedPoseGroup =>
+            CurrentPoseGroupList[poseGroupDropdown.SelectedItemIndex];
+
+        private List<string> CurrentPoseList =>
+            CurrentPoseDict[SelectedPoseGroup];
+
+        private int SelectedPoseIndex =>
+            poseDropdown.SelectedItemIndex;
+
+        private string SelectedPose =>
+            CurrentPoseList[SelectedPoseIndex];
+
+        private PoseInfo CurrentPoseInfo =>
+            new(SelectedPoseGroup, SelectedPose, customPoseMode);
+
         public MaidPoseSelectorPane(MeidoManager meidoManager)
         {
             Constants.CustomPoseChange += OnPresetChange;
             this.meidoManager = meidoManager;
 
-            poseModeGrid = new SelectionGrid(Translation.GetArray("posePane", tabTranslations));
+            poseModeGrid = new(Translation.GetArray("posePane", tabTranslations));
             poseModeGrid.ControlEvent += (s, a) => SetPoseMode();
 
-            poseGroupDropdown = new Dropdown(Translation.GetArray("poseGroupDropdown", Constants.PoseGroupList));
+            poseGroupDropdown = new(Translation.GetArray("poseGroupDropdown", Constants.PoseGroupList));
             poseGroupDropdown.SelectionChange += (s, a) => ChangePoseGroup();
 
-            poseDropdown = new Dropdown(UIPoseList());
+            poseDropdown = new(UIPoseList());
             poseDropdown.SelectionChange += (s, a) => ChangePose();
 
-            poseGroupLeftButton = new Button("<");
+            poseGroupLeftButton = new("<");
             poseGroupLeftButton.ControlEvent += (s, a) => poseGroupDropdown.Step(-1);
 
-            poseGroupRightButton = new Button(">");
+            poseGroupRightButton = new(">");
             poseGroupRightButton.ControlEvent += (s, a) => poseGroupDropdown.Step(1);
 
-            poseLeftButton = new Button("<");
+            poseLeftButton = new("<");
             poseLeftButton.ControlEvent += (s, a) => poseDropdown.Step(-1);
 
-            poseRightButton = new Button(">");
+            poseRightButton = new(">");
             poseRightButton.ControlEvent += (s, a) => poseDropdown.Step(1);
 
             customPoseMode = poseModeGrid.SelectedItemIndex == 1;
@@ -60,31 +74,20 @@ namespace MeidoPhotoStudio.Plugin
             poseListEnabled = CurrentPoseList.Count > 0;
         }
 
-        protected override void ReloadTranslation()
-        {
-            updating = true;
-            poseModeGrid.SetItems(Translation.GetArray("posePane", tabTranslations));
-            if (!customPoseMode)
-            {
-                poseGroupDropdown.SetDropdownItems(
-                    Translation.GetArray("poseGroupDropdown", Constants.PoseGroupList)
-                );
-            }
-            updating = false;
-        }
-
         public override void Draw()
         {
             const float buttonHeight = 30f;
-            GUILayoutOption[] arrowLayoutOptions = {
+
+            var arrowLayoutOptions = new[] {
                 GUILayout.Width(buttonHeight),
-                GUILayout.Height(buttonHeight)
+                GUILayout.Height(buttonHeight),
             };
 
             const float dropdownButtonWidth = 153f;
-            GUILayoutOption[] dropdownLayoutOptions = new GUILayoutOption[] {
+
+            var dropdownLayoutOptions = new GUILayoutOption[] {
                 GUILayout.Height(buttonHeight),
-                GUILayout.Width(dropdownButtonWidth)
+                GUILayout.Width(dropdownButtonWidth),
             };
 
             GUI.enabled = meidoManager.HasActiveMeido && !meidoManager.ActiveMeido.Stop;
@@ -159,6 +162,21 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
+        protected override void ReloadTranslation()
+        {
+            updating = true;
+            poseModeGrid.SetItems(Translation.GetArray("posePane", tabTranslations));
+
+            if (!customPoseMode)
+            {
+                poseGroupDropdown.SetDropdownItems(
+                    Translation.GetArray("poseGroupDropdown", Constants.PoseGroupList)
+                );
+            }
+
+            updating = false;
+        }
+
         private void OnPresetChange(object sender, PresetChangeEventArgs args)
         {
             if (args == PresetChangeEventArgs.Empty)
@@ -192,7 +210,7 @@ namespace MeidoPhotoStudio.Plugin
 
             customPoseMode = poseModeGrid.SelectedItemIndex == 1;
 
-            string[] list = customPoseMode
+            var list = customPoseMode
                 ? CurrentPoseGroupList.ToArray()
                 : Translation.GetArray("poseGroupDropdown", CurrentPoseGroupList);
 
@@ -218,17 +236,17 @@ namespace MeidoPhotoStudio.Plugin
 
         private void ChangePose()
         {
-            if (!poseListEnabled || updating) return;
+            if (!poseListEnabled || updating)
+                return;
+
             meidoManager.ActiveMeido.SetPose(CurrentPoseInfo);
         }
 
-        private string[] UIPoseList()
-        {
-            return CurrentPoseList.Count == 0
+        private string[] UIPoseList() =>
+            CurrentPoseList.Count == 0
                 ? new[] { "No Poses" }
                 : CurrentPoseList
                     .Select((pose, i) => $"{i + 1}:{(customPoseMode ? Path.GetFileNameWithoutExtension(pose) : pose)}")
                     .ToArray();
-        }
     }
 }

+ 28 - 22
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/MpnAttachPropPane.cs

@@ -1,5 +1,5 @@
-using System.Linq;
 using System.Collections.Generic;
+using System.Linq;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
@@ -13,50 +13,43 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Button attachPropButton;
         private readonly Button detachPropButton;
         private readonly Button detachAllButton;
+
         private string header;
 
         public MpnAttachPropPane(MeidoManager meidoManager)
         {
             this.meidoManager = meidoManager;
 
-            mpnAttachDropdown = new Dropdown(new[] { string.Empty });
+            mpnAttachDropdown = new(new[] { string.Empty });
 
-            if (!Constants.MpnAttachInitialized) Constants.MenuFilesChange += InitializeMpnAttach;
+            if (!Constants.MpnAttachInitialized)
+                Constants.MenuFilesChange += InitializeMpnAttach;
 
             SetDropdownList();
 
-            previousPropButton = new Button("<");
+            previousPropButton = new("<");
             previousPropButton.ControlEvent += (s, a) => mpnAttachDropdown.Step(-1);
 
-            nextPropButton = new Button(">");
+            nextPropButton = new(">");
             nextPropButton.ControlEvent += (s, a) => mpnAttachDropdown.Step(1);
 
-            attachPropButton = new Button(Translation.Get("attachMpnPropPane", "attachButton"));
+            attachPropButton = new(Translation.Get("attachMpnPropPane", "attachButton"));
             attachPropButton.ControlEvent += (s, a) => AttachProp();
 
-            detachPropButton = new Button(Translation.Get("attachMpnPropPane", "detachButton"));
+            detachPropButton = new(Translation.Get("attachMpnPropPane", "detachButton"));
             detachPropButton.ControlEvent += (s, a) => AttachProp(detach: true);
 
-            detachAllButton = new Button(Translation.Get("attachMpnPropPane", "detachAllButton"));
+            detachAllButton = new(Translation.Get("attachMpnPropPane", "detachAllButton"));
             detachAllButton.ControlEvent += (s, a) => DetachAll();
 
             header = Translation.Get("attachMpnPropPane", "header");
         }
 
-        protected override void ReloadTranslation()
-        {
-            attachPropButton.Label = Translation.Get("attachMpnPropPane", "attachButton");
-            detachPropButton.Label = Translation.Get("attachMpnPropPane", "detachButton");
-            detachAllButton.Label = Translation.Get("attachMpnPropPane", "detachAllButton");
-            header = Translation.Get("attachMpnPropPane", "header");
-            SetDropdownList();
-        }
-
         public override void Draw()
         {
             GUI.enabled = meidoManager.HasActiveMeido && Constants.MpnAttachInitialized;
 
-            GUILayoutOption noExpand = GUILayout.ExpandWidth(false);
+            var noExpand = GUILayout.ExpandWidth(false);
 
             MpsGui.Header(header);
             MpsGui.WhiteLine();
@@ -76,9 +69,20 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            attachPropButton.Label = Translation.Get("attachMpnPropPane", "attachButton");
+            detachPropButton.Label = Translation.Get("attachMpnPropPane", "detachButton");
+            detachAllButton.Label = Translation.Get("attachMpnPropPane", "detachAllButton");
+            header = Translation.Get("attachMpnPropPane", "header");
+
+            SetDropdownList();
+        }
+
         private void InitializeMpnAttach(object sender, MenuFilesEventArgs args)
         {
-            if (args.Type == MenuFilesEventArgs.EventType.MpnAttach) SetDropdownList();
+            if (args.Type == MenuFilesEventArgs.EventType.MpnAttach)
+                SetDropdownList();
         }
 
         private void SetDropdownList()
@@ -94,16 +98,18 @@ namespace MeidoPhotoStudio.Plugin
 
         private void AttachProp(bool detach = false)
         {
-            if (!meidoManager.HasActiveMeido) return;
+            if (!meidoManager.HasActiveMeido)
+                return;
 
-            MpnAttachProp prop = Constants.MpnAttachPropList[mpnAttachDropdown.SelectedItemIndex];
+            var prop = Constants.MpnAttachPropList[mpnAttachDropdown.SelectedItemIndex];
 
             meidoManager.ActiveMeido.SetMpnProp(prop, detach);
         }
 
         private void DetachAll()
         {
-            if (!meidoManager.HasActiveMeido) return;
+            if (!meidoManager.HasActiveMeido)
+                return;
 
             meidoManager.ActiveMeido.DetachAllMpnAttach();
         }

+ 17 - 15
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/SaveHandPane.cs

@@ -9,13 +9,14 @@ namespace MeidoPhotoStudio.Plugin
         private readonly TextField handNameTextField;
         private readonly Button saveLeftHandButton;
         private readonly Button saveRightHandButton;
+
         private string categoryHeader;
         private string nameHeader;
 
         public SaveHandPane(MeidoManager meidoManager)
         {
-            Constants.CustomHandChange += (s, a)
-                => categoryComboBox.SetDropdownItems(Constants.CustomHandGroupList.ToArray());
+            Constants.CustomHandChange += (s, a) =>
+                categoryComboBox.SetDropdownItems(Constants.CustomHandGroupList.ToArray());
 
             this.meidoManager = meidoManager;
 
@@ -23,23 +24,15 @@ namespace MeidoPhotoStudio.Plugin
 
             nameHeader = Translation.Get("handPane", "nameHeader");
 
-            saveLeftHandButton = new Button(Translation.Get("handPane", "saveLeftButton"));
+            saveLeftHandButton = new(Translation.Get("handPane", "saveLeftButton"));
             saveLeftHandButton.ControlEvent += (s, a) => SaveHand(right: false);
 
-            saveRightHandButton = new Button(Translation.Get("handPane", "saveRightButton"));
+            saveRightHandButton = new(Translation.Get("handPane", "saveRightButton"));
             saveRightHandButton.ControlEvent += (s, a) => SaveHand(right: true);
 
-            categoryComboBox = new ComboBox(Constants.CustomHandGroupList.ToArray());
-
-            handNameTextField = new TextField();
-        }
+            categoryComboBox = new(Constants.CustomHandGroupList.ToArray());
 
-        protected override void ReloadTranslation()
-        {
-            categoryHeader = Translation.Get("handPane", "categoryHeader");
-            nameHeader = Translation.Get("handPane", "nameHeader");
-            saveLeftHandButton.Label = Translation.Get("handPane", "saveLeftButton");
-            saveRightHandButton.Label = Translation.Get("handPane", "saveRightButton");
+            handNameTextField = new();
         }
 
         public override void Draw()
@@ -60,9 +53,18 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            categoryHeader = Translation.Get("handPane", "categoryHeader");
+            nameHeader = Translation.Get("handPane", "nameHeader");
+            saveLeftHandButton.Label = Translation.Get("handPane", "saveLeftButton");
+            saveRightHandButton.Label = Translation.Get("handPane", "saveRightButton");
+        }
+
         private void SaveHand(bool right)
         {
-            byte[] handBinary = meidoManager.ActiveMeido.IKManager.SerializeHand(right);
+            var handBinary = meidoManager.ActiveMeido.IKManager.SerializeHand(right);
+
             Constants.AddHand(handBinary, right, handNameTextField.Value, categoryComboBox.Value);
             handNameTextField.Value = string.Empty;
         }

+ 16 - 13
src/MeidoPhotoStudio.Plugin/GUI/Panes/PoseWindowPanes/SavePosePane.cs

@@ -9,32 +9,27 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Button savePoseButton;
         private readonly TextField poseNameTextField;
         private readonly ComboBox categoryComboBox;
+
         private string categoryHeader;
         private string nameHeader;
 
         public SavePosePane(MeidoManager meidoManager)
         {
-            Constants.CustomPoseChange += (s, a)
-                => categoryComboBox.SetDropdownItems(Constants.CustomPoseGroupList.ToArray());
+            Constants.CustomPoseChange += (s, a) =>
+                categoryComboBox.SetDropdownItems(Constants.CustomPoseGroupList.ToArray());
 
             this.meidoManager = meidoManager;
 
             categoryHeader = Translation.Get("posePane", "categoryHeader");
             nameHeader = Translation.Get("posePane", "nameHeader");
 
-            savePoseButton = new Button(Translation.Get("posePane", "saveButton"));
+            savePoseButton = new(Translation.Get("posePane", "saveButton"));
             savePoseButton.ControlEvent += OnSavePose;
 
-            categoryComboBox = new ComboBox(Constants.CustomPoseGroupList.ToArray());
-            poseNameTextField = new TextField();
-            poseNameTextField.ControlEvent += OnSavePose;
-        }
+            categoryComboBox = new(Constants.CustomPoseGroupList.ToArray());
 
-        protected override void ReloadTranslation()
-        {
-            categoryHeader = Translation.Get("posePane", "categoryHeader");
-            nameHeader = Translation.Get("posePane", "nameHeader");
-            savePoseButton.Label = Translation.Get("posePane", "saveButton");
+            poseNameTextField = new();
+            poseNameTextField.ControlEvent += OnSavePose;
         }
 
         public override void Draw()
@@ -53,9 +48,17 @@ namespace MeidoPhotoStudio.Plugin
             GUI.enabled = true;
         }
 
+        protected override void ReloadTranslation()
+        {
+            categoryHeader = Translation.Get("posePane", "categoryHeader");
+            nameHeader = Translation.Get("posePane", "nameHeader");
+            savePoseButton.Label = Translation.Get("posePane", "saveButton");
+        }
+
         private void OnSavePose(object sender, EventArgs args)
         {
-            byte[] anmBinary = meidoManager.ActiveMeido.SerializePose();
+            var anmBinary = meidoManager.ActiveMeido.SerializePose();
+
             Constants.AddPose(anmBinary, poseNameTextField.Value, categoryComboBox.Value);
             poseNameTextField.Value = string.Empty;
         }

+ 27 - 21
src/MeidoPhotoStudio.Plugin/GUI/Panes/SceneManagerPanes/SceneManagerDirectoryPane.cs

@@ -5,13 +5,15 @@ namespace MeidoPhotoStudio.Plugin
     public class SceneManagerDirectoryPane : BasePane
     {
         public static readonly int listWidth = 200;
+
         private readonly SceneManager sceneManager;
         private readonly SceneModalWindow sceneModalWindow;
         private readonly Button createDirectoryButton;
         private readonly Button deleteDirectoryButton;
         private readonly TextField directoryTextField;
         private readonly Button cancelButton;
-        private readonly Texture2D selectedTexture = Utility.MakeTex(2, 2, new Color(0.5f, 0.5f, 0.5f, 0.4f));
+        private readonly Texture2D selectedTexture = Utility.MakeTex(2, 2, new(0.5f, 0.5f, 0.5f, 0.4f));
+
         private Vector2 listScrollPos;
         private bool createDirectoryMode;
 
@@ -20,13 +22,13 @@ namespace MeidoPhotoStudio.Plugin
             this.sceneManager = sceneManager;
             this.sceneModalWindow = sceneModalWindow;
 
-            createDirectoryButton = new Button(Translation.Get("sceneManager", "createDirectoryButton"));
+            createDirectoryButton = new(Translation.Get("sceneManager", "createDirectoryButton"));
             createDirectoryButton.ControlEvent += (s, a) => createDirectoryMode = true;
 
-            deleteDirectoryButton = new Button(Translation.Get("sceneManager", "deleteDirectoryButton"));
+            deleteDirectoryButton = new(Translation.Get("sceneManager", "deleteDirectoryButton"));
             deleteDirectoryButton.ControlEvent += (s, a) => this.sceneModalWindow.ShowDirectoryDialogue();
 
-            directoryTextField = new TextField();
+            directoryTextField = new();
             directoryTextField.ControlEvent += (s, a) =>
             {
                 sceneManager.AddDirectory(directoryTextField.Value);
@@ -34,26 +36,21 @@ namespace MeidoPhotoStudio.Plugin
                 directoryTextField.Value = string.Empty;
             };
 
-            cancelButton = new Button("X");
+            cancelButton = new("X");
             cancelButton.ControlEvent += (s, a) => createDirectoryMode = false;
         }
 
-        protected override void ReloadTranslation()
-        {
-            createDirectoryButton.Label = Translation.Get("sceneManager", "createDirectoryButton");
-            deleteDirectoryButton.Label = Translation.Get("sceneManager", "deleteDirectoryButton");
-        }
-
         public override void Draw()
         {
-            GUIStyle directoryStyle = new GUIStyle(GUI.skin.button)
+            var directoryStyle = new GUIStyle(GUI.skin.button)
             {
                 fontSize = Utility.GetPix(12),
                 alignment = TextAnchor.MiddleLeft,
-                margin = new RectOffset(0, 0, 0, 0)
+                margin = new(0, 0, 0, 0),
             };
 
-            GUIStyle directorySelectedStyle = new GUIStyle(directoryStyle);
+            var directorySelectedStyle = new GUIStyle(directoryStyle);
+
             directorySelectedStyle.normal.textColor = Color.white;
             directorySelectedStyle.normal.background = selectedTexture;
             directorySelectedStyle.hover.background = selectedTexture;
@@ -62,23 +59,25 @@ namespace MeidoPhotoStudio.Plugin
 
             listScrollPos = GUILayout.BeginScrollView(listScrollPos);
 
-            for (int i = 0; i < sceneManager.CurrentDirectoryList.Count; i++)
+            for (var i = 0; i < sceneManager.CurrentDirectoryList.Count; i++)
             {
-                GUIStyle style = i == sceneManager.CurrentDirectoryIndex ? directorySelectedStyle : directoryStyle;
-                string directoryName = sceneManager.CurrentDirectoryList[i];
+                var style = i == sceneManager.CurrentDirectoryIndex ? directorySelectedStyle : directoryStyle;
+                var directoryName = sceneManager.CurrentDirectoryList[i];
+
                 if (GUILayout.Button(directoryName, style, GUILayout.Height(Utility.GetPix(20))))
-                {
                     sceneManager.SelectDirectory(i);
-                }
             }
 
             GUILayout.EndScrollView();
 
             GUILayout.BeginHorizontal();
 
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button) { fontSize = Utility.GetPix(12) };
+            var buttonStyle = new GUIStyle(GUI.skin.button)
+            {
+                fontSize = Utility.GetPix(12),
+            };
 
-            GUILayoutOption buttonHeight = GUILayout.Height(Utility.GetPix(20));
+            var buttonHeight = GUILayout.Height(Utility.GetPix(20));
 
             if (createDirectoryMode)
             {
@@ -92,9 +91,16 @@ namespace MeidoPhotoStudio.Plugin
                 deleteDirectoryButton.Draw(buttonStyle, buttonHeight, GUILayout.ExpandWidth(false));
                 GUI.enabled = true;
             }
+
             GUILayout.EndHorizontal();
 
             GUILayout.EndVertical();
         }
+
+        protected override void ReloadTranslation()
+        {
+            createDirectoryButton.Label = Translation.Get("sceneManager", "createDirectoryButton");
+            deleteDirectoryButton.Label = Translation.Get("sceneManager", "deleteDirectoryButton");
+        }
     }
 }

+ 20 - 14
src/MeidoPhotoStudio.Plugin/GUI/Panes/SceneManagerPanes/SceneManagerScenePane.cs

@@ -15,19 +15,19 @@ namespace MeidoPhotoStudio.Plugin
             this.sceneManager = sceneManager;
             this.sceneModalWindow = sceneModalWindow;
 
-            addSceneButton = new Button("+");
+            addSceneButton = new("+");
             addSceneButton.ControlEvent += (s, a) => sceneManager.SaveScene(overwrite: false);
         }
 
         public override void Draw()
         {
-            GUIStyle sceneImageStyle = new GUIStyle(GUI.skin.label)
+            var sceneImageStyle = new GUIStyle(GUI.skin.label)
             {
                 alignment = TextAnchor.MiddleCenter,
                 padding = new RectOffset(0, 0, 0, 0)
             };
 
-            GUIStyle addSceneStyle = new GUIStyle(GUI.skin.button)
+            var addSceneStyle = new GUIStyle(GUI.skin.button)
             {
                 alignment = TextAnchor.MiddleCenter,
                 fontSize = 60
@@ -35,14 +35,18 @@ namespace MeidoPhotoStudio.Plugin
 
             GUILayout.BeginVertical();
 
-            float sceneWidth = SceneManager.sceneDimensions.x * thumbnailScale;
-            float sceneHeight = SceneManager.sceneDimensions.y * thumbnailScale;
-            float sceneGridWidth = parent.WindowRect.width - SceneManagerDirectoryPane.listWidth;
+            var sceneWidth = SceneManager.sceneDimensions.x * thumbnailScale;
+            var sceneHeight = SceneManager.sceneDimensions.y * thumbnailScale;
+            var sceneGridWidth = parent.WindowRect.width - SceneManagerDirectoryPane.listWidth;
 
-            GUILayoutOption[] sceneLayoutOptions = new[] { GUILayout.Height(sceneHeight), GUILayout.Width(sceneWidth) };
+            var sceneLayoutOptions = new[]
+            {
+                GUILayout.Height(sceneHeight),
+                GUILayout.Width(sceneWidth),
+            };
 
-            int columns = Mathf.Max(1, (int)(sceneGridWidth / sceneWidth));
-            int rows = (int)Mathf.Ceil(sceneManager.SceneList.Count + (1 / (float)columns));
+            var columns = Mathf.Max(1, (int)(sceneGridWidth / sceneWidth));
+            var rows = (int)Mathf.Ceil(sceneManager.SceneList.Count + 1 / (float)columns);
 
             sceneScrollPos = GUILayout.BeginScrollView(sceneScrollPos);
 
@@ -50,19 +54,20 @@ namespace MeidoPhotoStudio.Plugin
             GUILayout.FlexibleSpace();
             GUILayout.BeginVertical();
 
-            int currentScene = -1;
-            for (int i = 0; i < rows; i++)
+            var currentScene = -1;
+
+            for (var i = 0; i < rows; i++)
             {
                 GUILayout.BeginHorizontal();
-                for (int j = 0; j < columns; j++, currentScene++)
+
+                for (var j = 0; j < columns; j++, currentScene++)
                 {
                     if (currentScene == -1)
-                    {
                         addSceneButton.Draw(addSceneStyle, sceneLayoutOptions);
-                    }
                     else if (currentScene < sceneManager.SceneList.Count)
                     {
                         var scene = sceneManager.SceneList[currentScene];
+
                         if (GUILayout.Button(scene.Thumbnail, sceneImageStyle, sceneLayoutOptions))
                         {
                             sceneManager.SelectScene(currentScene);
@@ -70,6 +75,7 @@ namespace MeidoPhotoStudio.Plugin
                         }
                     }
                 }
+
                 GUILayout.EndHorizontal();
             }
 

+ 46 - 25
src/MeidoPhotoStudio.Plugin/GUI/Panes/SceneManagerPanes/SceneManagerTitleBar.cs

@@ -5,69 +5,75 @@ namespace MeidoPhotoStudio.Plugin
     public class SceneManagerTitleBarPane : BasePane
     {
         private static readonly string[] sortModes = new[] { "sortName", "sortCreated", "sortModified" };
+
         private readonly SceneManager sceneManager;
         private readonly Button kankyoToggle;
         private readonly Button refreshButton;
         private readonly Dropdown sortDropdown;
         private readonly Toggle descendingToggle;
         private readonly Button closeButton;
-        private string sortLabel;
+
         public event System.EventHandler CloseChange;
 
+        private string sortLabel;
+
         public SceneManagerTitleBarPane(SceneManager sceneManager)
         {
             this.sceneManager = sceneManager;
-            kankyoToggle = new Button(Translation.Get("sceneManager", "kankyoToggle"));
+            kankyoToggle = new(Translation.Get("sceneManager", "kankyoToggle"));
             kankyoToggle.ControlEvent += (s, a) => sceneManager.ToggleKankyoMode();
 
-            refreshButton = new Button(Translation.Get("sceneManager", "refreshButton"));
+            refreshButton = new(Translation.Get("sceneManager", "refreshButton"));
             refreshButton.ControlEvent += (s, a) => sceneManager.Refresh();
 
-            sortDropdown = new Dropdown(
+            sortDropdown = new(
                 Translation.GetArray("sceneManager", sortModes), (int)sceneManager.CurrentSortMode
             );
+
             sortDropdown.SelectionChange += (s, a) =>
             {
-                SceneManager.SortMode sortMode = (SceneManager.SortMode)sortDropdown.SelectedItemIndex;
-                if (sceneManager.CurrentSortMode == sortMode) return;
+                var sortMode = (SceneManager.SortMode)sortDropdown.SelectedItemIndex;
+
+                if (sceneManager.CurrentSortMode == sortMode)
+                    return;
+
                 sceneManager.SortScenes(sortMode);
             };
 
-            descendingToggle = new Toggle(
+            descendingToggle = new(
                 Translation.Get("sceneManager", "descendingToggle"), sceneManager.SortDescending
             );
+
             descendingToggle.ControlEvent += (s, a) =>
             {
                 sceneManager.SortDescending = descendingToggle.Value;
                 sceneManager.SortScenes(sceneManager.CurrentSortMode);
             };
 
-            closeButton = new Button("X");
+            closeButton = new("X");
             closeButton.ControlEvent += (s, a) => CloseChange?.Invoke(this, System.EventArgs.Empty);
 
             sortLabel = Translation.Get("sceneManager", "sortLabel");
         }
 
-        protected override void ReloadTranslation()
-        {
-            kankyoToggle.Label = Translation.Get("sceneManager", "kankyoToggle");
-            refreshButton.Label = Translation.Get("sceneManager", "refreshButton");
-            sortDropdown.SetDropdownItems(Translation.GetArray("sceneManager", sortModes));
-            descendingToggle.Label = Translation.Get("sceneManager", "descendingToggle");
-            sortLabel = Translation.Get("sceneManager", "sortLabel");
-        }
-
         public override void Draw()
         {
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button) { fontSize = Utility.GetPix(12) };
+            var buttonStyle = new GUIStyle(GUI.skin.button)
+            {
+                fontSize = Utility.GetPix(12),
+            };
+
+            var buttonHeight = GUILayout.Height(Utility.GetPix(20));
 
-            GUILayoutOption buttonHeight = GUILayout.Height(Utility.GetPix(20));
             GUILayout.BeginHorizontal();
 
             GUILayout.BeginHorizontal(GUILayout.Width(Utility.GetPix(SceneManagerDirectoryPane.listWidth)));
 
-            Color originalColour = GUI.backgroundColor;
-            if (sceneManager.KankyoMode) GUI.backgroundColor = Color.green;
+            var originalColour = GUI.backgroundColor;
+
+            if (sceneManager.KankyoMode)
+                GUI.backgroundColor = Color.green;
+
             kankyoToggle.Draw(buttonStyle, buttonHeight);
             GUI.backgroundColor = originalColour;
 
@@ -81,18 +87,24 @@ namespace MeidoPhotoStudio.Plugin
 
             GUILayout.Space(Utility.GetPix(15));
 
-            GUIStyle labelStyle = new GUIStyle(GUI.skin.label) { fontSize = buttonStyle.fontSize };
+            var labelStyle = new GUIStyle(GUI.skin.label)
+            {
+                fontSize = buttonStyle.fontSize,
+            };
 
             GUILayout.Label(sortLabel, labelStyle);
 
-            GUIStyle dropdownStyle = new GUIStyle(DropdownHelper.DefaultDropdownStyle)
+            var dropdownStyle = new GUIStyle(DropdownHelper.DefaultDropdownStyle)
             {
-                fontSize = buttonStyle.fontSize
+                fontSize = buttonStyle.fontSize,
             };
 
             sortDropdown.Draw(buttonStyle, dropdownStyle, buttonHeight, GUILayout.Width(Utility.GetPix(100)));
 
-            GUIStyle toggleStyle = new GUIStyle(GUI.skin.toggle) { fontSize = buttonStyle.fontSize };
+            var toggleStyle = new GUIStyle(GUI.skin.toggle)
+            {
+                fontSize = buttonStyle.fontSize,
+            };
 
             descendingToggle.Draw(toggleStyle);
 
@@ -104,5 +116,14 @@ namespace MeidoPhotoStudio.Plugin
 
             GUILayout.EndHorizontal();
         }
+
+        protected override void ReloadTranslation()
+        {
+            kankyoToggle.Label = Translation.Get("sceneManager", "kankyoToggle");
+            refreshButton.Label = Translation.Get("sceneManager", "refreshButton");
+            sortDropdown.SetDropdownItems(Translation.GetArray("sceneManager", sortModes));
+            descendingToggle.Label = Translation.Get("sceneManager", "descendingToggle");
+            sortLabel = Translation.Get("sceneManager", "sortLabel");
+        }
     }
 }

+ 37 - 28
src/MeidoPhotoStudio.Plugin/GUI/Windows/BaseWindow.cs

@@ -6,12 +6,19 @@ namespace MeidoPhotoStudio.Plugin
     public abstract class BaseWindow : BasePane
     {
         private static int id = 765;
-        private static int ID => id++;
+
+        private static int ID =>
+            id++;
+
         public readonly int windowID = ID;
+
         protected readonly List<BasePane> Panes = new();
-        protected Vector2 scrollPos;
+
         public bool ActiveWindow { get; set; }
+
+        protected Vector2 scrollPos;
         protected Rect windowRect = new(0f, 0f, 480f, 270f);
+
         public virtual Rect WindowRect
         {
             get => windowRect;
@@ -28,32 +35,6 @@ namespace MeidoPhotoStudio.Plugin
                 windowRect = value;
             }
         }
-        protected Vector2 MiddlePosition => new(
-            (float)Screen.width / 2 - windowRect.width / 2, (float)Screen.height / 2 - windowRect.height / 2
-        );
-
-        protected T AddPane<T>(T pane) where T : BasePane
-        {
-            Panes.Add(pane);
-            pane.SetParent(this);
-            return pane;
-        }
-
-        public override void SetParent(BaseWindow window)
-        {
-            foreach (var pane in Panes) 
-                pane.SetParent(window);
-        }
-
-        private void HandleZoom()
-        {
-            if (Input.mouseScrollDelta.y == 0f || !Visible) return;
-
-            var mousePos = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
-
-            if (WindowRect.Contains(mousePos))
-                Input.ResetInputAxes();
-        }
 
         public virtual void Update() =>
             HandleZoom();
@@ -70,6 +51,12 @@ namespace MeidoPhotoStudio.Plugin
                 pane.UpdatePane();
         }
 
+        public override void SetParent(BaseWindow window)
+        {
+            foreach (var pane in Panes)
+                pane.SetParent(window);
+        }
+
         public override void Activate()
         {
             base.Activate();
@@ -85,5 +72,27 @@ namespace MeidoPhotoStudio.Plugin
             foreach (var pane in Panes)
                 pane.Deactivate();
         }
+
+        protected Vector2 MiddlePosition =>
+            new((float)Screen.width / 2 - windowRect.width / 2, (float)Screen.height / 2 - windowRect.height / 2);
+
+        protected T AddPane<T>(T pane) where T : BasePane
+        {
+            Panes.Add(pane);
+            pane.SetParent(this);
+
+            return pane;
+        }
+
+        private void HandleZoom()
+        {
+            if (Input.mouseScrollDelta.y == 0f || !Visible)
+                return;
+
+            var mousePos = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
+
+            if (WindowRect.Contains(mousePos))
+                Input.ResetInputAxes();
+        }
     }
 }

+ 62 - 42
src/MeidoPhotoStudio.Plugin/GUI/Windows/MainWindow.cs

@@ -11,9 +11,11 @@ namespace MeidoPhotoStudio.Plugin
         private readonly LightManager lightManager;
         private readonly TabsPane tabsPane;
         private readonly Button settingsButton;
+
         private BaseMainWindowPane currentWindowPane;
         private string settingsButtonLabel;
         private string closeButtonLabel;
+        private Constants.Window selectedWindow;
 
         public override Rect WindowRect
         {
@@ -21,13 +23,16 @@ namespace MeidoPhotoStudio.Plugin
             {
                 value.width = 240f;
                 value.height = Screen.height * 0.9f;
-                if (MeidoPhotoStudio.EditMode) value.height *= 0.85f;
+
+                if (MeidoPhotoStudio.EditMode)
+                    value.height *= 0.85f;
+
                 value.x = Mathf.Clamp(value.x, 0, Screen.width - value.width);
                 value.y = Mathf.Clamp(value.y, -value.height + 30, Screen.height - 50);
+
                 windowRect = value;
             }
         }
-        private Constants.Window selectedWindow;
 
         public BaseMainWindowPane this[Constants.Window id]
         {
@@ -47,10 +52,10 @@ namespace MeidoPhotoStudio.Plugin
             this.lightManager = lightManager;
             this.lightManager.Select += (s, a) => ChangeWindow(Constants.Window.BG);
 
-            windowPanes = new Dictionary<Constants.Window, BaseMainWindowPane>();
-            WindowRect = new Rect(Screen.width, Screen.height * 0.08f, 240f, Screen.height * 0.9f);
+            windowPanes = new();
+            WindowRect = new(Screen.width, Screen.height * 0.08f, 240f, Screen.height * 0.9f);
 
-            tabsPane = new TabsPane();
+            tabsPane = new();
             tabsPane.TabChange += (s, a) => ChangeTab();
 
             settingsButtonLabel = Translation.Get("settingsLabels", "settingsButton");
@@ -59,7 +64,8 @@ namespace MeidoPhotoStudio.Plugin
             settingsButton = new(settingsButtonLabel);
             settingsButton.ControlEvent += (s, a) =>
             {
-                if (selectedWindow == Constants.Window.Settings) ChangeTab();
+                if (selectedWindow == Constants.Window.Settings)
+                    ChangeTab();
                 else
                 {
                     settingsButton.Label = closeButtonLabel;
@@ -68,53 +74,34 @@ namespace MeidoPhotoStudio.Plugin
             };
         }
 
-        protected override void ReloadTranslation()
-        {
-            settingsButtonLabel = Translation.Get("settingsLabels", "settingsButton");
-            closeButtonLabel = Translation.Get("settingsLabels", "closeSettingsButton");
-            settingsButton.Label = selectedWindow == Constants.Window.Settings ? closeButtonLabel : settingsButtonLabel;
-        }
-
-        public override void Activate()
-        {
-            base.Activate();
-            updating = true;
-            tabsPane.SelectedTab = Constants.Window.Call;
-            updating = false;
-            Visible = true;
-        }
-
         public void AddWindow(Constants.Window id, BaseMainWindowPane window)
         {
             if (windowPanes.ContainsKey(id))
-            {
                 Panes.Remove(windowPanes[id]);
-            }
+
             windowPanes[id] = window;
             windowPanes[id].SetTabsPane(tabsPane);
             windowPanes[id].SetParent(this);
+
             Panes.Add(windowPanes[id]);
         }
 
-        private void ChangeTab()
+        public override void Activate()
         {
-            settingsButton.Label = Translation.Get("settingsLabels", "settingsButton");
-            SetCurrentWindow(tabsPane.SelectedTab);
-        }
+            base.Activate();
 
-        private void SetCurrentWindow(Constants.Window window)
-        {
-            if (currentWindowPane != null) currentWindowPane.ActiveWindow = false;
-            selectedWindow = window;
-            currentWindowPane = windowPanes[selectedWindow];
-            currentWindowPane.ActiveWindow = true;
-            currentWindowPane.UpdatePanes();
+            updating = true;
+            tabsPane.SelectedTab = Constants.Window.Call;
+            updating = false;
+            Visible = true;
         }
 
         public override void Update()
         {
             base.Update();
-            if (InputManager.GetKeyDown(MpsKey.ToggleUI)) Visible = !Visible;
+
+            if (InputManager.GetKeyDown(MpsKey.ToggleUI))
+                Visible = !Visible;
         }
 
         public override void Draw()
@@ -125,37 +112,70 @@ namespace MeidoPhotoStudio.Plugin
 
             GUILayout.FlexibleSpace();
 
-            GUIStyle labelStyle = new GUIStyle(GUI.skin.label)
+            var labelStyle = new GUIStyle(GUI.skin.label)
             {
                 fontSize = 10,
-                alignment = TextAnchor.LowerLeft
+                alignment = TextAnchor.LowerLeft,
             };
 
             GUILayout.BeginHorizontal();
             GUILayout.Label(MeidoPhotoStudio.pluginString, labelStyle);
             GUILayout.FlexibleSpace();
+
             GUI.enabled = !InputManager.Listening;
+
             settingsButton.Draw(GUILayout.ExpandWidth(false));
+
             GUI.enabled = true;
+
             GUILayout.EndHorizontal();
 
             GUI.DragWindow();
         }
 
+        protected override void ReloadTranslation()
+        {
+            settingsButtonLabel = Translation.Get("settingsLabels", "settingsButton");
+            closeButtonLabel = Translation.Get("settingsLabels", "closeSettingsButton");
+            settingsButton.Label = selectedWindow == Constants.Window.Settings ? closeButtonLabel : settingsButtonLabel;
+        }
+
+        private void ChangeTab()
+        {
+            settingsButton.Label = Translation.Get("settingsLabels", "settingsButton");
+            SetCurrentWindow(tabsPane.SelectedTab);
+        }
+
+        private void SetCurrentWindow(Constants.Window window)
+        {
+            if (currentWindowPane != null)
+                currentWindowPane.ActiveWindow = false;
+
+            selectedWindow = window;
+            currentWindowPane = windowPanes[selectedWindow];
+            currentWindowPane.ActiveWindow = true;
+            currentWindowPane.UpdatePanes();
+        }
+
         private void UpdateMeido(object sender, MeidoUpdateEventArgs args)
         {
             if (args.FromMeido)
             {
-                Constants.Window newWindow = args.IsBody ? Constants.Window.Pose : Constants.Window.Face;
+                var newWindow = args.IsBody ? Constants.Window.Pose : Constants.Window.Face;
+
                 ChangeWindow(newWindow);
             }
-            else currentWindowPane.UpdatePanes();
+            else
+                currentWindowPane.UpdatePanes();
         }
 
         private void ChangeWindow(Constants.Window window)
         {
-            if (selectedWindow == window) currentWindowPane.UpdatePanes();
-            else tabsPane.SelectedTab = window;
+            if (selectedWindow == window)
+                currentWindowPane.UpdatePanes();
+            else
+                tabsPane.SelectedTab = window;
+
             Visible = true;
         }
     }

+ 48 - 40
src/MeidoPhotoStudio.Plugin/GUI/Windows/MessageWindow.cs

@@ -10,6 +10,9 @@ namespace MeidoPhotoStudio.Plugin
         private readonly Slider fontSizeSlider;
         private readonly TextArea messageTextArea;
         private readonly Button okButton;
+
+        private int fontSize = 25;
+
         public override Rect WindowRect
         {
             set
@@ -19,62 +22,32 @@ namespace MeidoPhotoStudio.Plugin
                 base.WindowRect = value;
             }
         }
-        private int fontSize = 25;
 
         public MessageWindow(MessageWindowManager messageWindowManager)
         {
+            this.messageWindowManager = messageWindowManager;
+
             WindowRect = WindowRect;
             windowRect.x = MiddlePosition.x;
             windowRect.y = Screen.height - WindowRect.height;
-            this.messageWindowManager = messageWindowManager;
-            nameTextField = new TextField();
 
-            fontSizeSlider = new Slider(MessageWindowManager.FontBounds);
+            nameTextField = new();
+
+            fontSizeSlider = new(MessageWindowManager.FontBounds);
             fontSizeSlider.ControlEvent += ChangeFontSize;
 
-            messageTextArea = new TextArea();
+            messageTextArea = new();
 
-            okButton = new Button("OK");
+            okButton = new("OK");
             okButton.ControlEvent += ShowMessage;
         }
 
-        private void ToggleVisibility()
-        {
-            if (messageWindowManager.ShowingMessage) messageWindowManager.CloseMessagePanel();
-            else Visible = !Visible;
-        }
-
-        private void ChangeFontSize(object sender, EventArgs args)
-        {
-            fontSize = (int)fontSizeSlider.Value;
-
-            if (updating)
-                return;
-
-            messageWindowManager.FontSize = fontSize;
-        }
-
-        private void ShowMessage(object sender, EventArgs args)
-        {
-            Visible = false;
-            messageWindowManager.ShowMessage(nameTextField.Value, messageTextArea.Value);
-        }
-
-        private void ResetUI()
-        {
-            updating = true;
-
-            fontSizeSlider.Value = MessageWindowManager.FontBounds.Left;
-            nameTextField.Value = string.Empty;
-            messageTextArea.Value = string.Empty;
-
-            updating = false;
-        }
-
         public override void Update()
         {
             base.Update();
-            if (InputManager.GetKeyDown(MpsKey.ToggleMessage)) ToggleVisibility();
+
+            if (InputManager.GetKeyDown(MpsKey.ToggleMessage))
+                ToggleVisibility();
         }
 
         public override void Draw()
@@ -103,5 +76,40 @@ namespace MeidoPhotoStudio.Plugin
 
         public override void Activate() =>
             ResetUI();
+
+        private void ToggleVisibility()
+        {
+            if (messageWindowManager.ShowingMessage)
+                messageWindowManager.CloseMessagePanel();
+            else
+                Visible = !Visible;
+        }
+
+        private void ChangeFontSize(object sender, EventArgs args)
+        {
+            fontSize = (int)fontSizeSlider.Value;
+
+            if (updating)
+                return;
+
+            messageWindowManager.FontSize = fontSize;
+        }
+
+        private void ShowMessage(object sender, EventArgs args)
+        {
+            Visible = false;
+            messageWindowManager.ShowMessage(nameTextField.Value, messageTextArea.Value);
+        }
+
+        private void ResetUI()
+        {
+            updating = true;
+
+            fontSizeSlider.Value = MessageWindowManager.FontBounds.Left;
+            nameTextField.Value = string.Empty;
+            messageTextArea.Value = string.Empty;
+
+            updating = false;
+        }
     }
 }

+ 70 - 57
src/MeidoPhotoStudio.Plugin/GUI/Windows/SceneModalWindow.cs

@@ -5,47 +5,52 @@ namespace MeidoPhotoStudio.Plugin
     public class SceneModalWindow : BaseWindow
     {
         private static readonly Texture2D infoHighlight = Utility.MakeTex(2, 2, new Color(0f, 0f, 0f, 0.8f));
+
         private readonly SceneManager sceneManager;
+        private readonly Button okButton;
+        private readonly Button cancelButton;
+        private readonly Button deleteButton;
+        private readonly Button overwriteButton;
+
+        private bool visible;
+        private string deleteDirectoryMessage;
+        private string deleteSceneMessage;
+        private string directoryDeleteCommit;
+        private string sceneDeleteCommit;
+        private string sceneLoadCommit;
+        private string infoKankyo;
+        private string infoMaidSingular;
+        private string infoMaidPlural;
+        private bool directoryMode;
+        private bool deleteScene;
+
         public override Rect WindowRect
         {
             set
             {
                 value.width = Mathf.Clamp(Screen.width * 0.3f, 360f, 500f);
                 value.height = directoryMode ? 150f : Mathf.Clamp(Screen.height * 0.4f, 240f, 380f);
+
                 base.WindowRect = value;
             }
         }
-        private bool visible;
+
         public override bool Visible
         {
             get => visible;
             set
             {
                 visible = value;
-                if (value)
-                {
-                    WindowRect = WindowRect;
-                    windowRect.x = MiddlePosition.x;
-                    windowRect.y = MiddlePosition.y;
-                }
+
+                if (!value)
+                    return;
+
+                WindowRect = WindowRect;
+                windowRect.x = MiddlePosition.x;
+                windowRect.y = MiddlePosition.y;
             }
         }
 
-        private readonly Button okButton;
-        private readonly Button cancelButton;
-        private readonly Button deleteButton;
-        private readonly Button overwriteButton;
-        private string deleteDirectoryMessage;
-        private string deleteSceneMessage;
-        private string directoryDeleteCommit;
-        private string sceneDeleteCommit;
-        private string sceneLoadCommit;
-        private string infoKankyo;
-        private string infoMaidSingular;
-        private string infoMaidPlural;
-        private bool directoryMode;
-        private bool deleteScene;
-
         public SceneModalWindow(SceneManager sceneManager)
         {
             ReloadTranslation();
@@ -54,20 +59,21 @@ namespace MeidoPhotoStudio.Plugin
 
             windowRect.x = MiddlePosition.x;
             windowRect.y = MiddlePosition.y;
-            okButton = new Button(sceneLoadCommit);
+
+            okButton = new(sceneLoadCommit);
             okButton.ControlEvent += (s, a) => Commit();
 
-            cancelButton = new Button("Cancel");
+            cancelButton = new("Cancel");
             cancelButton.ControlEvent += (s, a) => Cancel();
 
-            deleteButton = new Button("Delete");
+            deleteButton = new("Delete");
             deleteButton.ControlEvent += (s, a) =>
             {
                 okButton.Label = sceneDeleteCommit;
                 deleteScene = true;
             };
 
-            overwriteButton = new Button("Overwrite");
+            overwriteButton = new("Overwrite");
             overwriteButton.ControlEvent += (s, a) =>
             {
                 sceneManager.OverwriteScene();
@@ -75,53 +81,43 @@ namespace MeidoPhotoStudio.Plugin
             };
         }
 
-        protected override void ReloadTranslation()
-        {
-            deleteDirectoryMessage = Translation.Get("sceneManagerModal", "deleteDirectoryConfirm");
-            deleteSceneMessage = Translation.Get("sceneManagerModal", "deleteFileConfirm");
-            directoryDeleteCommit = Translation.Get("sceneManagerModal", "deleteDirectoryButton");
-            sceneDeleteCommit = Translation.Get("sceneManagerModal", "deleteFileCommit");
-            sceneLoadCommit = Translation.Get("sceneManagerModal", "fileLoadCommit");
-            infoKankyo = Translation.Get("sceneManagerModal", "infoKankyo");
-            infoMaidSingular = Translation.Get("sceneManagerModal", "infoMaidSingular");
-            infoMaidPlural = Translation.Get("sceneManagerModal", "infoMaidPlural");
-        }
-
         public override void Draw()
         {
-            GUILayout.BeginArea(new Rect(10f, 10f, WindowRect.width - 20f, WindowRect.height - 20f));
+            GUILayout.BeginArea(new(10f, 10f, WindowRect.width - 20f, WindowRect.height - 20f));
 
             // thumbnail
             if (!directoryMode)
             {
-                MPSScene scene = sceneManager.CurrentScene;
-                Texture2D thumb = scene.Thumbnail;
+                var scene = sceneManager.CurrentScene;
+                var thumb = scene.Thumbnail;
 
-                float scale = Mathf.Min(
+                var scale = Mathf.Min(
                     (WindowRect.width - 20f) / thumb.width, (WindowRect.height - 110f) / thumb.height
                 );
-                float width = Mathf.Min(thumb.width, thumb.width * scale);
-                float height = Mathf.Min(thumb.height, thumb.height * scale);
+
+                var width = Mathf.Min(thumb.width, thumb.width * scale);
+                var height = Mathf.Min(thumb.height, thumb.height * scale);
 
                 GUILayout.BeginHorizontal();
                 GUILayout.FlexibleSpace();
 
                 MpsGui.DrawTexture(thumb, GUILayout.Width(width), GUILayout.Height(height));
 
-                GUIStyle labelStyle = new GUIStyle(GUI.skin.label)
+                var labelStyle = new GUIStyle(GUI.skin.label)
                 {
                     fontSize = Utility.GetPix(12),
-                    alignment = TextAnchor.MiddleCenter
+                    alignment = TextAnchor.MiddleCenter,
                 };
+
                 labelStyle.normal.background = infoHighlight;
 
-                Rect labelBox = GUILayoutUtility.GetLastRect();
+                var labelBox = GUILayoutUtility.GetLastRect();
 
                 var infoString = scene.Environment
                     ? infoKankyo
                     : string.Format(scene.NumberOfMaids == 1 ? infoMaidSingular : infoMaidPlural, scene.NumberOfMaids);
 
-                Vector2 labelSize = labelStyle.CalcSize(new GUIContent(infoString));
+                var labelSize = labelStyle.CalcSize(new GUIContent(infoString));
 
                 labelBox = new Rect(
                     labelBox.x + 10, labelBox.y + labelBox.height - (labelSize.y + 10),
@@ -157,10 +153,10 @@ namespace MeidoPhotoStudio.Plugin
                 }
             }
 
-            GUIStyle messageStyle = new GUIStyle(GUI.skin.label)
+            var messageStyle = new GUIStyle(GUI.skin.label)
             {
                 alignment = TextAnchor.MiddleCenter,
-                fontSize = Utility.GetPix(12)
+                fontSize = Utility.GetPix(12),
             };
 
             GUILayout.FlexibleSpace();
@@ -171,12 +167,12 @@ namespace MeidoPhotoStudio.Plugin
 
             // Buttons
 
-            GUIStyle buttonStyle = new GUIStyle(GUI.skin.button)
+            var buttonStyle = new GUIStyle(GUI.skin.button)
             {
-                fontSize = Utility.GetPix(12)
+                fontSize = Utility.GetPix(12),
             };
 
-            GUILayoutOption buttonHeight = GUILayout.Height(Utility.GetPix(20));
+            var buttonHeight = GUILayout.Height(Utility.GetPix(20));
 
             GUILayout.BeginHorizontal();
 
@@ -216,6 +212,18 @@ namespace MeidoPhotoStudio.Plugin
             Modal.Show(this);
         }
 
+        protected override void ReloadTranslation()
+        {
+            deleteDirectoryMessage = Translation.Get("sceneManagerModal", "deleteDirectoryConfirm");
+            deleteSceneMessage = Translation.Get("sceneManagerModal", "deleteFileConfirm");
+            directoryDeleteCommit = Translation.Get("sceneManagerModal", "deleteDirectoryButton");
+            sceneDeleteCommit = Translation.Get("sceneManagerModal", "deleteFileCommit");
+            sceneLoadCommit = Translation.Get("sceneManagerModal", "fileLoadCommit");
+            infoKankyo = Translation.Get("sceneManagerModal", "infoKankyo");
+            infoMaidSingular = Translation.Get("sceneManagerModal", "infoMaidSingular");
+            infoMaidPlural = Translation.Get("sceneManagerModal", "infoMaidPlural");
+        }
+
         private void Commit()
         {
             if (directoryMode)
@@ -230,7 +238,8 @@ namespace MeidoPhotoStudio.Plugin
                     sceneManager.DeleteScene();
                     deleteScene = false;
                 }
-                else sceneManager.LoadScene(sceneManager.CurrentScene);
+                else
+                    sceneManager.LoadScene(sceneManager.CurrentScene);
 
                 Modal.Close();
             }
@@ -238,12 +247,16 @@ namespace MeidoPhotoStudio.Plugin
 
         private void Cancel()
         {
-            if (directoryMode) Modal.Close();
+            if (directoryMode)
+                Modal.Close();
             else
             {
-                if (deleteScene) deleteScene = false;
-                else Modal.Close();
+                if (deleteScene)
+                    deleteScene = false;
+                else
+                    Modal.Close();
             }
+
             okButton.Label = sceneLoadCommit;
         }
     }

+ 23 - 17
src/MeidoPhotoStudio.Plugin/GUI/Windows/SceneWindow.cs

@@ -5,20 +5,25 @@ namespace MeidoPhotoStudio.Plugin
     public class SceneWindow : BaseWindow
     {
         private const float resizeHandleSize = 15f;
+
         private readonly SceneManager sceneManager;
         private readonly SceneManagerTitleBarPane titleBar;
         private readonly SceneManagerDirectoryPane directoryList;
         private readonly SceneManagerScenePane sceneGrid;
+
         private Rect resizeHandleRect;
         private bool resizing;
         private bool visible;
+
         public override bool Visible
         {
             get => visible;
             set
             {
                 visible = value;
-                if (visible && !sceneManager.Initialized) sceneManager.Initialize();
+
+                if (visible && !sceneManager.Initialized)
+                    sceneManager.Initialize();
             }
         }
 
@@ -26,13 +31,13 @@ namespace MeidoPhotoStudio.Plugin
         {
             windowRect.width = Screen.width * 0.65f;
             windowRect.height = Screen.height * 0.75f;
-            windowRect.x = (Screen.width * 0.5f) - (windowRect.width * 0.5f);
-            windowRect.y = (Screen.height * 0.5f) - (windowRect.height * 0.5f);
+            windowRect.x = Screen.width * 0.5f - windowRect.width * 0.5f;
+            windowRect.y = Screen.height * 0.5f - windowRect.height * 0.5f;
 
-            resizeHandleRect = new Rect(0f, 0f, resizeHandleSize, resizeHandleSize);
+            resizeHandleRect = new(0f, 0f, resizeHandleSize, resizeHandleSize);
 
             this.sceneManager = sceneManager;
-            SceneModalWindow sceneModalWindow = new SceneModalWindow(this.sceneManager);
+            var sceneModalWindow = new SceneModalWindow(this.sceneManager);
 
             titleBar = AddPane(new SceneManagerTitleBarPane(sceneManager));
             titleBar.CloseChange += (s, a) => Visible = false;
@@ -46,25 +51,27 @@ namespace MeidoPhotoStudio.Plugin
         {
             HandleResize();
             Draw();
-            if (!resizing) GUI.DragWindow();
+
+            if (!resizing)
+                GUI.DragWindow();
         }
 
         public override void Update()
         {
             base.Update();
-            if (InputManager.GetKeyDown(MpsKey.OpenSceneManager)) Visible = !Visible;
+
+            if (InputManager.GetKeyDown(MpsKey.OpenSceneManager))
+                Visible = !Visible;
         }
 
-        public override void Deactivate()
-        {
+        public override void Deactivate() =>
             Visible = false;
-        }
 
         public override void Draw()
         {
             GUI.enabled = !SceneManager.Busy && !Modal.Visible;
 
-            GUILayout.BeginArea(new Rect(10f, 10f, windowRect.width - 20f, windowRect.height - 20f));
+            GUILayout.BeginArea(new(10f, 10f, windowRect.width - 20f, windowRect.height - 20f));
 
             titleBar.Draw();
 
@@ -84,16 +91,14 @@ namespace MeidoPhotoStudio.Plugin
             resizeHandleRect.y = windowRect.height - resizeHandleSize;
 
             if (!resizing && Input.GetMouseButton(0) && resizeHandleRect.Contains(Event.current.mousePosition))
-            {
                 resizing = true;
-            }
 
             if (resizing)
             {
-                float rectWidth = Event.current.mousePosition.x;
-                float rectHeight = Event.current.mousePosition.y;
+                var rectWidth = Event.current.mousePosition.x;
+                var rectHeight = Event.current.mousePosition.y;
 
-                float minWidth = Utility.GetPix(
+                var minWidth = Utility.GetPix(
                     SceneManagerDirectoryPane.listWidth
                     + (int)(SceneManager.sceneDimensions.x * SceneManagerScenePane.thumbnailScale)
                 );
@@ -101,7 +106,8 @@ namespace MeidoPhotoStudio.Plugin
                 windowRect.width = Mathf.Max(minWidth, rectWidth);
                 windowRect.height = Mathf.Max(300, rectHeight);
 
-                if (!Input.GetMouseButton(0)) resizing = false;
+                if (!Input.GetMouseButton(0))
+                    resizing = false;
             }
         }
     }

+ 15 - 8
src/MeidoPhotoStudio.Plugin/MPSScene.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 using System.Text;
 using UnityEngine;
 
@@ -11,25 +11,27 @@ namespace MeidoPhotoStudio.Plugin
         public bool Environment { get; private set; }
         public int NumberOfMaids { get; private set; }
 
-        private byte[] data;
-
         public byte[] Data
         {
             get
             {
-                if (data == null) Preload();
+                if (data is null)
+                    Preload();
+
                 return data;
             }
             private set => data = value;
         }
 
+        private byte[] data;
+
         public MPSScene(string path, Texture2D thumbnail = null)
         {
-            FileInfo = new FileInfo(path);
+            FileInfo = new(path);
 
             if (!thumbnail)
             {
-                thumbnail = new Texture2D(1, 1, TextureFormat.ARGB32, false);
+                thumbnail = new(1, 1, TextureFormat.ARGB32, false);
                 thumbnail.LoadImage(File.ReadAllBytes(FileInfo.FullName));
             }
 
@@ -38,9 +40,11 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Preload()
         {
-            if (data != null) return;
+            if (data is not null)
+                return;
 
             using var fileStream = FileInfo.OpenRead();
+
             Utility.SeekPngEnd(fileStream);
 
             using var memoryStream = new MemoryStream();
@@ -51,9 +55,11 @@ namespace MeidoPhotoStudio.Plugin
             using var binaryReader = new BinaryReader(memoryStream, Encoding.UTF8);
 
             var sceneHeader = MeidoPhotoStudio.SceneHeader;
+
             if (!Utility.BytesEqual(binaryReader.ReadBytes(sceneHeader.Length), sceneHeader))
             {
                 Utility.LogWarning($"'{FileInfo.FullName}' is not a MPS Scene");
+
                 return;
             }
 
@@ -64,7 +70,8 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Destroy()
         {
-            if (Thumbnail) Object.DestroyImmediate(Thumbnail);
+            if (Thumbnail)
+                Object.DestroyImmediate(Thumbnail);
         }
     }
 }

+ 51 - 43
src/MeidoPhotoStudio.Plugin/MaidPlacementUtility.cs

@@ -7,12 +7,14 @@ namespace MeidoPhotoStudio.Plugin
     {
         private const float pi = Mathf.PI;
         private const float tau = Mathf.PI * 2f;
+
         public static readonly string[] placementTypes = {
             "horizontalRow", "verticalRow", "diagonalRow", "diagonalRowInverse", "wave", "waveInverse",
             "v", "vInverse", "circleInner", "circleOuter", "fanInner", "fanOuter"
         };
 
-        public static int AlternatingSequence(int x) => (int)((x % 2 == 0 ? 1 : -1) * Mathf.Ceil(x / 2f));
+        public static int AlternatingSequence(int x) =>
+            (int)((x % 2 == 0 ? 1 : -1) * Mathf.Ceil(x / 2f));
 
         public static void ApplyPlacement(string placementType, IList<Meido> list)
         {
@@ -36,16 +38,18 @@ namespace MeidoPhotoStudio.Plugin
 
         public static void PlacementRow(IList<Meido> list, bool vertical = false)
         {
-            for (int i = 0; i < list.Count; i++)
+            for (var i = 0; i < list.Count; i++)
             {
-                Vector3 position = Vector3.zero;
+                var position = Vector3.zero;
 
-                Maid maid = list[i].Maid;
+                var maid = list[i].Maid;
 
-                float a = AlternatingSequence(i) * 0.6f;
+                var a = AlternatingSequence(i) * 0.6f;
 
-                if (vertical) position.z = a;
-                else position.x = a;
+                if (vertical)
+                    position.z = a;
+                else
+                    position.x = a;
 
                 maid.SetPos(position);
                 maid.SetRot(Vector3.zero);
@@ -54,91 +58,95 @@ namespace MeidoPhotoStudio.Plugin
 
         public static void PlacementDiagonal(IList<Meido> list, bool inverse = false)
         {
-            for (int i = 0; i < list.Count; i++)
+            for (var i = 0; i < list.Count; i++)
             {
-                Maid maid = list[i].Maid;
+                var maid = list[i].Maid;
 
-                float z = AlternatingSequence(i) * 0.5f;
+                var z = AlternatingSequence(i) * 0.5f;
 
-                maid.SetPos(inverse ? new Vector3(z, 0, -z) : new Vector3(z, 0, z));
+                maid.SetPos(inverse ? new(z, 0, -z) : new(z, 0, z));
                 maid.SetRot(Vector3.zero);
             }
         }
 
         public static void PlacementWave(IList<Meido> list, bool inverse = false)
         {
-            for (int i = 0; i < list.Count; i++)
+            for (var i = 0; i < list.Count; i++)
             {
-                Maid maid = list[i].Maid;
+                var maid = list[i].Maid;
 
-                float x = AlternatingSequence(i) * 0.4f;
-                float z = (inverse ? -1 : 1) * Mathf.Cos(AlternatingSequence(i) * pi) * 0.35f;
+                var x = AlternatingSequence(i) * 0.4f;
+                var z = (inverse ? -1 : 1) * Mathf.Cos(AlternatingSequence(i) * pi) * 0.35f;
 
-                maid.SetPos(new Vector3(x, 0, z));
+                maid.SetPos(new(x, 0, z));
                 maid.SetRot(Vector3.zero);
             }
         }
 
         public static void PlacementV(IList<Meido> list, bool inverse = false)
         {
-            for (int i = 0; i < list.Count; i++)
+            for (var i = 0; i < list.Count; i++)
             {
-                Maid maid = list[i].Maid;
+                var maid = list[i].Maid;
 
-                float x = AlternatingSequence(i) * 0.4f;
-                float z = (inverse ? 1 : -1) * Mathf.Abs(AlternatingSequence(i)) * 0.4f;
+                var x = AlternatingSequence(i) * 0.4f;
+                var z = (inverse ? 1 : -1) * Mathf.Abs(AlternatingSequence(i)) * 0.4f;
 
-                maid.SetPos(new Vector3(x, 0, z));
+                maid.SetPos(new(x, 0, z));
                 maid.SetRot(Vector3.zero);
             }
         }
 
         public static void PlacementCircle(IList<Meido> list, bool inner = false)
         {
-            int maidCount = list.Count;
+            var maidCount = list.Count;
 
-            float radius = 0.3f + (0.1f * maidCount);
+            var radius = 0.3f + 0.1f * maidCount;
 
-            for (int i = 0; i < maidCount; i++)
+            for (var i = 0; i < maidCount; i++)
             {
-                Maid maid = list[i].Maid;
+                var maid = list[i].Maid;
+
+                var angle = pi / 2f + tau * AlternatingSequence(i) / maidCount;
 
-                float angle = (pi / 2f) + (tau * AlternatingSequence(i) / maidCount);
+                var x = Mathf.Cos(angle) * radius;
+                var z = Mathf.Sin(angle) * radius;
 
-                float x = Mathf.Cos(angle) * radius;
-                float z = Mathf.Sin(angle) * radius;
+                var rotation = Mathf.Atan2(x, z);
 
-                float rotation = Mathf.Atan2(x, z);
-                if (inner) rotation += pi;
+                if (inner)
+                    rotation += pi;
 
-                maid.SetPos(new Vector3(x, 0, z));
-                maid.SetRot(new Vector3(0, rotation * Mathf.Rad2Deg, 0));
+                maid.SetPos(new(x, 0, z));
+                maid.SetRot(new(0, rotation * Mathf.Rad2Deg, 0));
             }
         }
 
         public static void PlacementFan(IList<Meido> list, bool outer = false)
         {
-            int maidCount = list.Count;
+            var maidCount = list.Count;
 
-            float radius = 0.2f + (0.2f * maidCount);
+            var radius = 0.2f + 0.2f * maidCount;
 
             list[0].Maid.SetPos(Vector3.zero);
             list[0].Maid.SetRot(Vector3.zero);
 
-            for (int i = 1; i < maidCount; i++)
+            for (var i = 1; i < maidCount; i++)
             {
-                Maid maid = list[i].Maid;
+                var maid = list[i].Maid;
+
+                var angle = pi * AlternatingSequence(i - 1) / maidCount;
 
-                float angle = pi * AlternatingSequence(i - 1) / maidCount;
+                var x = Mathf.Sin(angle) * radius;
+                var z = Mathf.Cos(angle) * radius;
 
-                float x = Mathf.Sin(angle) * radius;
-                float z = Mathf.Cos(angle) * radius;
+                var rotation = Mathf.Atan2(x, z);
 
-                float rotation = Mathf.Atan2(x, z);
-                if (outer) rotation += pi;
+                if (outer)
+                    rotation += pi;
 
-                maid.SetPos(new Vector3(-x, 0, -z));
-                maid.SetRot(new Vector3(0, rotation * Mathf.Rad2Deg, 0));
+                maid.SetPos(new(-x, 0, -z));
+                maid.SetRot(new(0, rotation * Mathf.Rad2Deg, 0));
             }
         }
     }

+ 46 - 28
src/MeidoPhotoStudio.Plugin/Managers/CameraManager.cs

@@ -1,28 +1,37 @@
 using System;
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+using UInput = UnityEngine.Input;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
-    using UInput = Input;
     public class CameraManager : IManager
     {
         public const string header = "CAMERA";
-        private static readonly CameraMain mainCamera = CameraUtility.MainCamera;
-        private static readonly UltimateOrbitCamera ultimateOrbitCamera = CameraUtility.UOCamera;
-        private float defaultCameraMoveSpeed;
-        private float defaultCameraZoomSpeed;
+
         private const float cameraFastMoveSpeed = 0.1f;
         private const float cameraFastZoomSpeed = 3f;
         private const float cameraSlowMoveSpeed = 0.004f;
         private const float cameraSlowZoomSpeed = 0.1f;
-        private Camera subCamera;
-        private CameraInfo tempCameraInfo = new CameraInfo();
         private const KeyCode AlphaOne = KeyCode.Alpha1;
-        public int CameraCount => cameraInfos.Length;
+
+        private static readonly CameraMain mainCamera = CameraUtility.MainCamera;
+        private static readonly UltimateOrbitCamera ultimateOrbitCamera = CameraUtility.UOCamera;
+
+        private readonly CameraInfo tempCameraInfo = new();
+        private readonly CameraInfo[] cameraInfos;
+
         public EventHandler CameraChange;
 
+        private float defaultCameraMoveSpeed;
+        private float defaultCameraZoomSpeed;
+        private Camera subCamera;
         private int currentCameraIndex;
+
+        public int CameraCount =>
+            cameraInfos.Length;
+
         public int CurrentCameraIndex
         {
             get => currentCameraIndex;
@@ -33,7 +42,6 @@ namespace MeidoPhotoStudio.Plugin
                 LoadCameraInfo(cameraInfos[currentCameraIndex]);
             }
         }
-        private CameraInfo[] cameraInfos;
 
         static CameraManager()
         {
@@ -46,7 +54,10 @@ namespace MeidoPhotoStudio.Plugin
         public CameraManager()
         {
             cameraInfos = new CameraInfo[5];
-            for (var i = 0; i < cameraInfos.Length; i++) cameraInfos[i] = new CameraInfo();
+
+            for (var i = 0; i < cameraInfos.Length; i++)
+                cameraInfos[i] = new();
+
             Activate();
         }
 
@@ -57,17 +68,20 @@ namespace MeidoPhotoStudio.Plugin
             defaultCameraMoveSpeed = ultimateOrbitCamera.moveSpeed;
             defaultCameraZoomSpeed = ultimateOrbitCamera.zoomSpeed;
 
-            if (!MeidoPhotoStudio.EditMode) ResetCamera();
+            if (!MeidoPhotoStudio.EditMode)
+                ResetCamera();
 
             currentCameraIndex = 0;
 
             tempCameraInfo.Reset();
 
-            for (var i = 0; i < CameraCount; i++) cameraInfos[i].Reset();
+            for (var i = 0; i < CameraCount; i++)
+                cameraInfos[i].Reset();
 
             mainCamera.ForceCalcNearClip();
 
             var subCamGo = new GameObject("subcam");
+
             subCamera = subCamGo.AddComponent<Camera>();
             subCamera.CopyFrom(mainCamera.camera);
             subCamera.clearFlags = CameraClearFlags.Depth;
@@ -84,7 +98,8 @@ namespace MeidoPhotoStudio.Plugin
             ultimateOrbitCamera.moveSpeed = defaultCameraMoveSpeed;
             ultimateOrbitCamera.zoomSpeed = defaultCameraZoomSpeed;
 
-            if (MeidoPhotoStudio.EditMode) return;
+            if (MeidoPhotoStudio.EditMode)
+                return;
 
             mainCamera.Reset(CameraMain.CameraType.Target, true);
             mainCamera.SetTargetPos(new Vector3(0.5609447f, 1.380762f, -1.382336f));
@@ -98,14 +113,16 @@ namespace MeidoPhotoStudio.Plugin
         {
             if (Input.GetKey(MpsKey.CameraLayer))
             {
-                if (Input.GetKeyDown(MpsKey.CameraSave)) SaveTempCamera();
-                else if (Input.GetKeyDown(MpsKey.CameraLoad)) LoadCameraInfo(tempCameraInfo);
-                else if (Input.GetKeyDown(MpsKey.CameraReset)) ResetCamera();
+                if (Input.GetKeyDown(MpsKey.CameraSave))
+                    SaveTempCamera();
+                else if (Input.GetKeyDown(MpsKey.CameraLoad))
+                    LoadCameraInfo(tempCameraInfo);
+                else if (Input.GetKeyDown(MpsKey.CameraReset))
+                    ResetCamera();
 
                 for (var i = 0; i < CameraCount; i++)
-                {
-                    if (i != CurrentCameraIndex && UInput.GetKeyDown(AlphaOne + i)) CurrentCameraIndex = i;
-                }
+                    if (i != CurrentCameraIndex && UInput.GetKeyDown(AlphaOne + i))
+                        CurrentCameraIndex = i;
             }
 
             subCamera.fieldOfView = mainCamera.camera.fieldOfView;
@@ -127,17 +144,17 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private void SaveTempCamera()
+        public void LoadCameraInfo(CameraInfo info)
         {
-            tempCameraInfo.UpdateInfo(mainCamera);
+            info.Apply(mainCamera);
             CameraUtility.StopAll();
+            CameraChange?.Invoke(this, EventArgs.Empty);
         }
 
-        public void LoadCameraInfo(CameraInfo info)
+        private void SaveTempCamera()
         {
-            info.Apply(mainCamera);
+            tempCameraInfo.UpdateInfo(mainCamera);
             CameraUtility.StopAll();
-            CameraChange?.Invoke(this, EventArgs.Empty);
         }
 
         private void ResetCamera()
@@ -156,8 +173,6 @@ namespace MeidoPhotoStudio.Plugin
         public float Distance { get; set; }
         public float FOV { get; set; }
 
-        public CameraInfo() => Reset();
-
         public static CameraInfo FromCamera(CameraMain mainCamera)
         {
             var info = new CameraInfo();
@@ -165,9 +180,12 @@ namespace MeidoPhotoStudio.Plugin
             return info;
         }
 
+        public CameraInfo() =>
+            Reset();
+
         public void Reset()
         {
-            TargetPos = new Vector3(0f, 0.9f, 0f);
+            TargetPos = new(0f, 0.9f, 0f);
             Angle = Quaternion.Euler(10f, 180f, 0f);
             Distance = 3f;
             FOV = 35f;

+ 11 - 6
src/MeidoPhotoStudio.Plugin/Managers/EffectManager.cs

@@ -7,27 +7,32 @@ namespace MeidoPhotoStudio.Plugin
     {
         public const string header = "EFFECT";
         public const string footer = "END_EFFECT";
-        private readonly Dictionary<Type, IEffectManager> EffectManagers = new Dictionary<Type, IEffectManager>();
 
-        public T Get<T>() where T : IEffectManager
-            => EffectManagers.ContainsKey(typeof(T)) ? (T)EffectManagers[typeof(T)] : default;
+        private readonly Dictionary<Type, IEffectManager> EffectManagers = new();
+
+        public T Get<T>() where T : IEffectManager =>
+            EffectManagers.ContainsKey(typeof(T)) ? (T)EffectManagers[typeof(T)] : default;
 
         public T AddManager<T>() where T : IEffectManager, new()
         {
-            T manager = new T();
+            var manager = new T();
+
             EffectManagers[typeof(T)] = manager;
             manager.Activate();
+
             return manager;
         }
 
         public void Activate()
         {
-            foreach (IEffectManager effectManager in EffectManagers.Values) effectManager.Activate();
+            foreach (var effectManager in EffectManagers.Values)
+                effectManager.Activate();
         }
 
         public void Deactivate()
         {
-            foreach (IEffectManager effectManager in EffectManagers.Values) effectManager.Deactivate();
+            foreach (var effectManager in EffectManagers.Values)
+                effectManager.Deactivate();
         }
 
         public void Update() { }

+ 38 - 18
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/BloomEffectManager.cs

@@ -5,72 +5,89 @@ namespace MeidoPhotoStudio.Plugin
 {
     public class BloomEffectManager : IEffectManager
     {
-        public const string header = "EFFECT_BLOOM";
         private const float bloomDefIntensity = 5.7f;
+
+        public const string header = "EFFECT_BLOOM";
+
         private static readonly CameraMain camera = GameMain.Instance.MainCamera;
-        private Bloom Bloom { get; set; }
-        // CMSystem's bloomValue;
-        private static int backupBloomValue;
         private static readonly float backup_m_fBloomDefIntensity;
         private static readonly FieldInfo m_fBloomDefIntensity
             = Utility.GetFieldInfo<CameraMain>("m_fBloomDefIntensity");
-        private static float BloomDefIntensity
-        {
-            set => m_fBloomDefIntensity.SetValue(camera, value);
-            get => (float)m_fBloomDefIntensity.GetValue(camera);
-        }
+
+        // CMSystem's bloomValue;
+        private static int backupBloomValue;
+
         private float initialIntensity;
         private int initialBlurIterations;
         private Color initialThresholdColour;
         private Bloom.HDRBloomMode initialHDRBloomMode;
+        private int blurIterations;
+        private Color bloomThresholdColour;
+        private bool bloomHdr;
+
+        private Bloom Bloom { get; set; }
+        private float bloomValue;
+
         public bool Ready { get; private set; }
         public bool Active { get; private set; }
-        private float bloomValue;
+
+        private static float BloomDefIntensity
+        {
+            set => m_fBloomDefIntensity.SetValue(camera, value);
+            get => (float)m_fBloomDefIntensity.GetValue(camera);
+        }
+
         public float BloomValue
         {
             get => bloomValue;
             set => GameMain.Instance.CMSystem.BloomValue = (int)(bloomValue = value);
         }
-        private int blurIterations;
+
         public int BlurIterations
         {
             get => blurIterations;
             set => blurIterations = Bloom.bloomBlurIterations = value;
         }
+
         public float BloomThresholdColorRed
         {
             get => BloomThresholdColour.r;
             set
             {
-                Color colour = Bloom.bloomThreshholdColor;
+                var colour = Bloom.bloomThreshholdColor;
+
                 BloomThresholdColour = new Color(value, colour.g, colour.b);
             }
         }
+
         public float BloomThresholdColorGreen
         {
             get => BloomThresholdColour.g;
             set
             {
-                Color colour = Bloom.bloomThreshholdColor;
+                var colour = Bloom.bloomThreshholdColor;
+
                 BloomThresholdColour = new Color(colour.r, value, colour.b);
             }
         }
+
         public float BloomThresholdColorBlue
         {
             get => BloomThresholdColour.b;
             set
             {
-                Color colour = Bloom.bloomThreshholdColor;
+                var colour = Bloom.bloomThreshholdColor;
+
                 BloomThresholdColour = new Color(colour.r, colour.g, value);
             }
         }
-        private Color bloomThresholdColour;
+
         public Color BloomThresholdColour
         {
             get => bloomThresholdColour;
             set => bloomThresholdColour = Bloom.bloomThreshholdColor = value;
         }
-        private bool bloomHdr;
+
         public bool BloomHDR
         {
             get => bloomHdr;
@@ -81,7 +98,8 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        static BloomEffectManager() => backup_m_fBloomDefIntensity = BloomDefIntensity;
+        static BloomEffectManager() =>
+            backup_m_fBloomDefIntensity = BloomDefIntensity;
 
         public void Activate()
         {
@@ -97,6 +115,7 @@ namespace MeidoPhotoStudio.Plugin
 
                 backupBloomValue = GameMain.Instance.CMSystem.BloomValue;
             }
+
             SetEffectActive(false);
         }
 
@@ -135,7 +154,8 @@ namespace MeidoPhotoStudio.Plugin
 
                 BloomDefIntensity = bloomDefIntensity;
             }
-            else Reset();
+            else
+                Reset();
         }
 
         public void Update() { }

+ 13 - 5
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/BlurEffectManager.cs

@@ -3,13 +3,15 @@ namespace MeidoPhotoStudio.Plugin
     public class BlurEffectManager : IEffectManager
     {
         public const string header = "EFFECT_BLUR";
-        private Blur Blur { get; set; }
-        public bool Ready { get; private set; }
-        public bool Active { get; private set; }
+
         private float initialBlurSize;
         private int initialBlurIterations;
         private int initialDownsample;
         private float blurSize;
+
+        public bool Ready { get; private set; }
+        public bool Active { get; private set; }
+
         public float BlurSize
         {
             get => blurSize;
@@ -17,6 +19,7 @@ namespace MeidoPhotoStudio.Plugin
             {
                 blurSize = value;
                 Blur.blurSize = blurSize / 10f;
+
                 if (blurSize >= 3f)
                 {
                     Blur.blurSize -= 0.3f;
@@ -31,6 +34,8 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
+        private Blur Blur { get; set; }
+
         public void Activate()
         {
             if (Blur == null)
@@ -41,6 +46,7 @@ namespace MeidoPhotoStudio.Plugin
                 initialBlurIterations = Blur.blurIterations;
                 initialDownsample = Blur.downsample;
             }
+
             SetEffectActive(false);
         }
 
@@ -54,8 +60,10 @@ namespace MeidoPhotoStudio.Plugin
 
         public void SetEffectActive(bool active)
         {
-            if (Blur.enabled = Active = active) BlurSize = BlurSize;
-            else Reset();
+            if (Blur.enabled = Active = active)
+                BlurSize = BlurSize;
+            else
+                Reset();
         }
 
         public void Reset()

+ 22 - 14
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/DepthOfFieldManager.cs

@@ -5,61 +5,67 @@ namespace MeidoPhotoStudio.Plugin
     public class DepthOfFieldEffectManager : IEffectManager
     {
         public const string header = "EFFECT_DOF";
-        private DepthOfFieldScatter DepthOfField { get; set; }
-        public bool Ready { get; private set; }
-        public bool Active { get; private set; }
+
         private readonly float initialValue = 0f;
+
         private float focalLength;
+        private float focalSize;
+        private float aperture;
+        private float maxBlurSize;
+        private bool visualizeFocus;
+
+        public bool Ready { get; private set; }
+        public bool Active { get; private set; }
+
         public float FocalLength
         {
             get => focalLength;
             set => focalLength = DepthOfField.focalLength = value;
         }
 
-        private float focalSize;
         public float FocalSize
         {
             get => focalSize;
             set => focalSize = DepthOfField.focalSize = value;
         }
-        private float aperture;
+
         public float Aperture
         {
             get => aperture;
             set => aperture = DepthOfField.aperture = value;
         }
-        private float maxBlurSize;
+
         public float MaxBlurSize
         {
             get => maxBlurSize;
             set => maxBlurSize = DepthOfField.maxBlurSize = value;
         }
-        private bool visualizeFocus;
+
         public bool VisualizeFocus
         {
             get => visualizeFocus;
             set => visualizeFocus = DepthOfField.visualizeFocus = value;
         }
 
+        private DepthOfFieldScatter DepthOfField { get; set; }
+
         public void Activate()
         {
             if (DepthOfField == null)
             {
                 Ready = true;
                 DepthOfField = GameMain.Instance.MainCamera.GetOrAddComponent<DepthOfFieldScatter>();
+
                 if (DepthOfField.dofHdrShader == null)
-                {
                     DepthOfField.dofHdrShader = Shader.Find("Hidden/Dof/DepthOfFieldHdr");
-                }
+
                 if (DepthOfField.dx11BokehShader == null)
-                {
                     DepthOfField.dx11BokehShader = Shader.Find("Hidden/Dof/DX11Dof");
-                }
+
                 if (DepthOfField.dx11BokehTexture == null)
-                {
                     DepthOfField.dx11BokehTexture = Resources.Load("Textures/hexShape") as Texture2D;
-                }
             }
+
             SetEffectActive(false);
         }
 
@@ -85,6 +91,7 @@ namespace MeidoPhotoStudio.Plugin
         public void SetEffectActive(bool active)
         {
             DepthOfField.enabled = active;
+
             if (Active = active)
             {
                 DepthOfField.focalLength = FocalLength;
@@ -92,7 +99,8 @@ namespace MeidoPhotoStudio.Plugin
                 DepthOfField.aperture = Aperture;
                 DepthOfField.maxBlurSize = MaxBlurSize;
             }
-            else Reset();
+            else
+                Reset();
         }
 
         public void Update() { }

+ 33 - 12
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/FogEffectManager.cs

@@ -5,85 +5,104 @@ namespace MeidoPhotoStudio.Plugin
     public class FogEffectManager : IEffectManager
     {
         public const string header = "EFFECT_FOG";
-        private GlobalFog Fog { get; set; }
-        public bool Ready { get; private set; }
-        public bool Active { get; private set; }
+
         private readonly float initialDistance = 4f;
         private readonly float initialDensity = 1f;
         private readonly float initialHeightScale = 1f;
         private readonly float initialHeight = 0f;
         private readonly Color initialColour = Color.white;
+
         private float distance;
+        private float density;
+        private float heightScale;
+        private float height;
+        private Color fogColour;
+
+        public bool Ready { get; private set; }
+        public bool Active { get; private set; }
+
         public float Distance
         {
             get => distance;
             set => distance = Fog.startDistance = value;
         }
-        private float density;
+
         public float Density
         {
             get => density;
             set => density = Fog.globalDensity = value;
         }
-        private float heightScale;
+
         public float HeightScale
         {
             get => heightScale;
             set => heightScale = Fog.heightScale = value;
         }
-        private float height;
+
         public float Height
         {
             get => height;
             set => height = Fog.height = value;
         }
+
         public float FogColourRed
         {
             get => FogColour.r;
             set
             {
-                Color fogColour = FogColour;
+                var fogColour = FogColour;
+
                 FogColour = new Color(value, fogColour.g, fogColour.b);
             }
         }
+
         public float FogColourGreen
         {
             get => FogColour.g;
             set
             {
-                Color fogColour = FogColour;
+                var fogColour = FogColour;
+
                 FogColour = new Color(fogColour.r, value, fogColour.b);
             }
         }
+
         public float FogColourBlue
         {
             get => FogColour.b;
             set
             {
-                Color fogColour = FogColour;
+                var fogColour = FogColour;
+
                 FogColour = new Color(fogColour.r, fogColour.g, value);
             }
         }
-        private Color fogColour;
+
         public Color FogColour
         {
             get => fogColour;
             set => fogColour = Fog.globalFogColor = value;
         }
 
+        private GlobalFog Fog { get; set; }
+
         public void Activate()
         {
             if (Fog == null)
             {
                 Ready = true;
                 Fog = GameMain.Instance.MainCamera.GetOrAddComponent<GlobalFog>();
-                if (Fog.fogShader == null) Fog.fogShader = Shader.Find("Hidden/GlobalFog");
+
+                if (Fog.fogShader == null)
+                    Fog.fogShader = Shader.Find("Hidden/GlobalFog");
+
                 Distance = initialDistance;
                 Density = initialDensity;
                 HeightScale = initialHeightScale;
                 Height = initialHeight;
                 FogColour = initialColour;
             }
+
             SetEffectActive(false);
         }
 
@@ -110,6 +129,7 @@ namespace MeidoPhotoStudio.Plugin
         public void SetEffectActive(bool active)
         {
             Fog.enabled = active;
+
             if (Active = active)
             {
                 Fog.startDistance = Distance;
@@ -118,7 +138,8 @@ namespace MeidoPhotoStudio.Plugin
                 Fog.height = Height;
                 Fog.globalFogColor = FogColour;
             }
-            else Reset();
+            else
+                Reset();
         }
 
         public void Update() { }

+ 1 - 0
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/IEffectManager.cs

@@ -4,6 +4,7 @@ namespace MeidoPhotoStudio.Plugin
     {
         bool Ready { get; }
         bool Active { get; }
+
         void SetEffectActive(bool active);
         void Reset();
     }

+ 10 - 4
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/SepiaToneEffectManager.cs

@@ -5,10 +5,12 @@ namespace MeidoPhotoStudio.Plugin
     public class SepiaToneEffectManger : IEffectManager
     {
         public const string header = "EFFECT_SEPIA";
-        private SepiaToneEffect SepiaTone { get; set; }
+
         public bool Ready { get; private set; }
         public bool Active { get; private set; }
 
+        private SepiaToneEffect SepiaTone { get; set; }
+
         public void Activate()
         {
             if (SepiaTone == null)
@@ -16,14 +18,18 @@ namespace MeidoPhotoStudio.Plugin
                 Ready = true;
                 SepiaTone = GameMain.Instance.MainCamera.GetOrAddComponent<SepiaToneEffect>();
 
-                if (SepiaTone.shader == null) SepiaTone.shader = Shader.Find("Hidden/Sepiatone Effect");
+                if (SepiaTone.shader == null)
+                    SepiaTone.shader = Shader.Find("Hidden/Sepiatone Effect");
             }
+
             SetEffectActive(false);
         }
 
-        public void Deactivate() => SetEffectActive(false);
+        public void Deactivate() =>
+            SetEffectActive(false);
 
-        public void SetEffectActive(bool active) => SepiaTone.enabled = Active = active;
+        public void SetEffectActive(bool active) =>
+            SepiaTone.enabled = Active = active;
 
         public void Reset() { }
 

+ 16 - 6
src/MeidoPhotoStudio.Plugin/Managers/EffectManagers/VignetteEffectManager.cs

@@ -3,38 +3,45 @@ namespace MeidoPhotoStudio.Plugin
     public class VignetteEffectManager : IEffectManager
     {
         public const string header = "EFFECT_VIGNETTE";
-        private Vignetting Vignette { get; set; }
+
         private float initialIntensity;
         private float initialBlur;
         private float initialBlurSpread;
         private float initialChromaticAberration;
+        private float blur;
+        private float blurSpread;
+        private float chromaticAberration;
+        private float intensity;
+
         public bool Ready { get; private set; }
         public bool Active { get; private set; }
-        private float intensity;
+
         public float Intensity
         {
             get => intensity;
             set => intensity = Vignette.intensity = value;
         }
-        private float blur;
+
         public float Blur
         {
             get => blur;
             set => blur = Vignette.blur = value;
         }
-        private float blurSpread;
+
         public float BlurSpread
         {
             get => blurSpread;
             set => blurSpread = Vignette.blurSpread = value;
         }
-        private float chromaticAberration;
+
         public float ChromaticAberration
         {
             get => chromaticAberration;
             set => chromaticAberration = Vignette.chromaticAberration = value;
         }
 
+        private Vignetting Vignette { get; set; }
+
         public void Activate()
         {
             if (Vignette == null)
@@ -48,6 +55,7 @@ namespace MeidoPhotoStudio.Plugin
                 initialBlurSpread = Vignette.blurSpread;
                 initialChromaticAberration = Vignette.chromaticAberration;
             }
+
             SetEffectActive(false);
         }
 
@@ -72,6 +80,7 @@ namespace MeidoPhotoStudio.Plugin
         public void SetEffectActive(bool active)
         {
             Vignette.enabled = active;
+
             if (Active = active)
             {
                 Vignette.intensity = Intensity;
@@ -79,7 +88,8 @@ namespace MeidoPhotoStudio.Plugin
                 Vignette.blurSpread = BlurSpread;
                 Vignette.chromaticAberration = ChromaticAberration;
             }
-            else Reset();
+            else
+                Reset();
         }
 
         public void Update() { }

+ 44 - 24
src/MeidoPhotoStudio.Plugin/Managers/EnvironmentManager.cs

@@ -1,45 +1,57 @@
-using System;
+using System;
 using UnityEngine;
+
 using Object = UnityEngine.Object;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class EnvironmentManager : IManager
     {
-        private static readonly BgMgr bgMgr = GameMain.Instance.BgMgr;
         public const string header = "ENVIRONMENT";
         public const string defaultBg = "Theater";
+
         private const string myRoomPrefix = "マイルーム:";
+
+        private static readonly BgMgr bgMgr = GameMain.Instance.BgMgr;
+
         private static bool cubeActive;
+        private static bool cubeSmall;
+        private static event EventHandler CubeActiveChange;
+        private static event EventHandler CubeSmallChange;
+
         public static bool CubeActive
         {
             get => cubeActive;
             set
             {
-                if (value == cubeActive) return;
+                if (value == cubeActive)
+                    return;
+
                 cubeActive = value;
                 CubeActiveChange?.Invoke(null, EventArgs.Empty);
             }
         }
-        private static bool cubeSmall;
+
         public static bool CubeSmall
         {
             get => cubeSmall;
             set
             {
-                if (value == cubeSmall) return;
+                if (value == cubeSmall)
+                    return;
+
                 cubeSmall = value;
                 CubeSmallChange?.Invoke(null, EventArgs.Empty);
             }
         }
-        private static event EventHandler CubeActiveChange;
-        private static event EventHandler CubeSmallChange;
+
         private Transform bg;
         private GameObject bgObject;
         private DragPointBG bgDragPoint;
-        public string CurrentBgAsset { get; private set; } = defaultBg;
         private bool bgVisible = true;
+
+        public string CurrentBgAsset { get; private set; } = defaultBg;
+
         public bool BGVisible
         {
             get => bgVisible;
@@ -66,9 +78,11 @@ namespace MeidoPhotoStudio.Plugin
             bgObject = bgMgr.Parent;
 
             bgObject.SetActive(true);
-            
-            if (MeidoPhotoStudio.EditMode) UpdateBG();
-            else ChangeBackground(defaultBg);
+
+            if (MeidoPhotoStudio.EditMode)
+                UpdateBG();
+            else
+                ChangeBackground(defaultBg);
 
             CubeSmallChange += OnCubeSmall;
             CubeActiveChange += OnCubeActive;
@@ -82,14 +96,17 @@ namespace MeidoPhotoStudio.Plugin
             DestroyDragPoint();
             BGVisible = true;
 
-            if (MeidoPhotoStudio.EditMode) bgMgr.ChangeBg(defaultBg);
+            if (MeidoPhotoStudio.EditMode)
+                bgMgr.ChangeBg(defaultBg);
             else
             {
                 var isNight = GameMain.Instance.CharacterMgr.status.GetFlag("時間帯") == 3;
+
                 bgMgr.ChangeBg(isNight ? "ShinShitsumu_ChairRot_Night" : "ShinShitsumu_ChairRot");
             }
 
-            if (bgMgr.BgObject) bgMgr.BgObject.transform.localScale = Vector3.one;
+            if (bgMgr.BgObject)
+                bgMgr.BgObject.transform.localScale = Vector3.one;
 
             CubeSmallChange -= OnCubeSmall;
             CubeActiveChange -= OnCubeActive;
@@ -97,8 +114,10 @@ namespace MeidoPhotoStudio.Plugin
 
         public void ChangeBackground(string assetName, bool creative = false)
         {
-            if (creative) bgMgr.ChangeBgMyRoom(assetName);
-            else bgMgr.ChangeBg(assetName);
+            if (creative)
+                bgMgr.ChangeBgMyRoom(assetName);
+            else
+                bgMgr.ChangeBg(assetName);
         }
 
         private void AttachDragPoint(Transform bgTransform)
@@ -117,28 +136,29 @@ namespace MeidoPhotoStudio.Plugin
 
         private void UpdateBG()
         {
-            if (!bgMgr.BgObject) return;
+            if (!bgMgr.BgObject)
+                return;
 
             CurrentBgAsset = bgMgr.GetBGName();
+
             if (CurrentBgAsset.StartsWith(myRoomPrefix))
                 CurrentBgAsset = CurrentBgAsset.Replace(myRoomPrefix, string.Empty);
+
             bg = bgMgr.BgObject.transform;
+
             AttachDragPoint(bg);
         }
 
         private void DestroyDragPoint()
         {
-            if (bgDragPoint) Object.Destroy(bgDragPoint.gameObject);
+            if (bgDragPoint)
+                Object.Destroy(bgDragPoint.gameObject);
         }
 
-        private void OnCubeSmall(object sender, EventArgs args)
-        {
+        private void OnCubeSmall(object sender, EventArgs args) =>
             bgDragPoint.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
-        }
 
-        private void OnCubeActive(object sender, EventArgs args)
-        {
+        private void OnCubeActive(object sender, EventArgs args) =>
             bgDragPoint.gameObject.SetActive(CubeActive);
-        }
     }
 }

+ 69 - 42
src/MeidoPhotoStudio.Plugin/Managers/InputManager.cs

@@ -1,39 +1,54 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using UnityEngine;
 using BepInEx.Configuration;
+using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public static class InputManager
     {
-        private static InputListener inputListener;
-        private static readonly Dictionary<MpsKey, KeyCode> ActionKeys = new Dictionary<MpsKey, KeyCode>();
-        private static readonly Dictionary<MpsKey, ConfigEntry<KeyCode>> ConfigEntries
-            = new Dictionary<MpsKey, ConfigEntry<KeyCode>>();
-        public static KeyCode CurrentKeyCode { get; private set; }
-        public static bool Listening { get; private set; }
-        public static event EventHandler KeyChange;
-        public static bool Control => Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
-        public static bool Alt => Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
-        public static bool Shift => Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
-        public static readonly AcceptableValueBase controlRange;
         public const KeyCode upperKeyCode = KeyCode.F15;
         public const string configHeader = "Controls";
 
-        static InputManager() => controlRange = new AcceptableValueRange<KeyCode>(default, upperKeyCode);
+        public static readonly AcceptableValueBase controlRange;
+
+        private static readonly Dictionary<MpsKey, KeyCode> ActionKeys = new();
+        private static readonly Dictionary<MpsKey, ConfigEntry<KeyCode>> ConfigEntries = new();
+
+        public static event EventHandler KeyChange;
+
+        public static KeyCode CurrentKeyCode { get; private set; }
+        public static bool Listening { get; private set; }
+
+        public static bool Control =>
+            Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
+
+        public static bool Alt =>
+            Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
+
+        public static bool Shift =>
+            Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
+
+        private static InputListener inputListener;
+
+        static InputManager() =>
+            controlRange = new AcceptableValueRange<KeyCode>(default, upperKeyCode);
 
         public static void Register(MpsKey action, KeyCode key, string description)
         {
             key = Clamp(key, default, upperKeyCode);
-            if (ConfigEntries.ContainsKey(action)) Rebind(action, key);
+
+            if (ConfigEntries.ContainsKey(action))
+                Rebind(action, key);
             else
             {
-                ConfigDescription configDescription = new ConfigDescription(description, controlRange);
+                var configDescription = new ConfigDescription(description, controlRange);
+
                 ConfigEntries[action] = Configuration.Config.Bind(
                     configHeader, action.ToString(), key, configDescription
                 );
+
                 key = ConfigEntries[action].Value;
                 ActionKeys[action] = key;
             }
@@ -42,20 +57,25 @@ namespace MeidoPhotoStudio.Plugin
         public static void Rebind(MpsKey action, KeyCode key)
         {
             key = Clamp(key, default, upperKeyCode);
-            if (ConfigEntries.ContainsKey(action)) ConfigEntries[action].Value = key;
+
+            if (ConfigEntries.ContainsKey(action))
+                ConfigEntries[action].Value = key;
+
             ActionKeys[action] = key;
         }
 
-        public static KeyCode Clamp(KeyCode value, KeyCode min, KeyCode max)
-            => value < min ? min : value > max ? max : value;
+        public static KeyCode Clamp(KeyCode value, KeyCode min, KeyCode max) =>
+            value < min ? min : value > max ? max : value;
 
-        public static KeyCode GetActionKey(MpsKey action)
-            => ActionKeys.TryGetValue(action, out KeyCode keyCode) ? keyCode : default;
+        public static KeyCode GetActionKey(MpsKey action) =>
+            ActionKeys.TryGetValue(action, out var keyCode) ? keyCode : default;
 
         public static void StartListening()
         {
-            if (inputListener == null) inputListener = new GameObject().AddComponent<InputListener>();
-            else if (inputListener.gameObject.activeSelf) StopListening();
+            if (inputListener == null)
+                inputListener = new GameObject().AddComponent<InputListener>();
+            else if (inputListener.gameObject.activeSelf)
+                StopListening();
 
             inputListener.gameObject.SetActive(true);
             inputListener.KeyChange += OnKeyChange;
@@ -65,7 +85,9 @@ namespace MeidoPhotoStudio.Plugin
 
         public static void StopListening()
         {
-            if (!inputListener || !inputListener.gameObject.activeSelf) return;
+            if (!inputListener || !inputListener.gameObject.activeSelf)
+                return;
+
             inputListener.gameObject.SetActive(false);
             inputListener.KeyChange -= OnKeyChange;
             CurrentKeyCode = KeyCode.None;
@@ -73,16 +95,18 @@ namespace MeidoPhotoStudio.Plugin
             Input.ResetInputAxes();
         }
 
-        public static bool GetKey(MpsKey action)
-            => !Listening && ActionKeys.ContainsKey(action) && Input.GetKey(ActionKeys[action]);
+        public static bool GetKey(MpsKey action) =>
+            !Listening && ActionKeys.ContainsKey(action) && Input.GetKey(ActionKeys[action]);
 
-        public static bool GetKeyDown(MpsKey action)
-            => !Listening && ActionKeys.ContainsKey(action) && Input.GetKeyDown(ActionKeys[action]);
+        public static bool GetKeyDown(MpsKey action) =>
+            !Listening && ActionKeys.ContainsKey(action) && Input.GetKeyDown(ActionKeys[action]);
 
         public static void Deactivate()
         {
             StopListening();
-            GameObject.Destroy(inputListener?.gameObject);
+
+            // TODO: Null propagation does not work with UnityEngine.Object
+            UnityEngine.Object.Destroy(inputListener?.gameObject);
             inputListener = null;
         }
 
@@ -97,30 +121,31 @@ namespace MeidoPhotoStudio.Plugin
         private class InputListener : MonoBehaviour
         {
             private static readonly KeyCode[] keyCodes;
+
             public event EventHandler<KeyChangeEventArgs> KeyChange;
 
-            static InputListener()
-            {
+            static InputListener() =>
                 keyCodes = Enum.GetValues(typeof(KeyCode))
                     .Cast<KeyCode>()
                     .Where(keyCode => keyCode <= upperKeyCode)
                     .ToArray();
-            }
 
-            private void Awake() => DontDestroyOnLoad(this);
+            private void Awake() =>
+                DontDestroyOnLoad(this);
 
             private void Update()
             {
-                if (Input.anyKeyDown)
+                if (!Input.anyKeyDown)
+                    return;
+
+                foreach (var key in keyCodes)
                 {
-                    foreach (KeyCode key in keyCodes)
-                    {
-                        if (Input.GetKeyDown(key))
-                        {
-                            KeyChange?.Invoke(this, new KeyChangeEventArgs(key));
-                            break;
-                        }
-                    }
+                    if (!Input.GetKeyDown(key))
+                        continue;
+
+                    KeyChange?.Invoke(this, new KeyChangeEventArgs(key));
+
+                    break;
                 }
             }
         }
@@ -128,7 +153,9 @@ namespace MeidoPhotoStudio.Plugin
         private class KeyChangeEventArgs : EventArgs
         {
             public KeyCode Key { get; }
-            public KeyChangeEventArgs(KeyCode key) => Key = key;
+
+            public KeyChangeEventArgs(KeyCode key) =>
+                Key = key;
         }
     }
 

+ 71 - 35
src/MeidoPhotoStudio.Plugin/Managers/LightManager.cs

@@ -8,7 +8,10 @@ namespace MeidoPhotoStudio.Plugin
     public class LightManager : IManager
     {
         public const string header = "LIGHT";
+
         private static bool cubeActive = true;
+        private static event EventHandler CubeActiveChange;
+
         public static bool CubeActive
         {
             get => cubeActive;
@@ -21,9 +24,16 @@ namespace MeidoPhotoStudio.Plugin
                 }
             }
         }
-        private static event EventHandler CubeActiveChange;
-        private readonly List<DragPointLight> lightList = new List<DragPointLight>();
+
+        private readonly List<DragPointLight> lightList = new();
+
+        public event EventHandler Rotate;
+        public event EventHandler Scale;
+        public event EventHandler ListModified;
+        public event EventHandler Select;
+
         private int selectedLightIndex;
+
         public int SelectedLightIndex
         {
             get => selectedLightIndex;
@@ -33,15 +43,18 @@ namespace MeidoPhotoStudio.Plugin
                 lightList[SelectedLightIndex].IsActiveLight = true;
             }
         }
-        public string[] LightNameList => lightList.Select(light => LightName(light.Name)).ToArray();
-        public string ActiveLightName => LightName(lightList[SelectedLightIndex].Name);
-        public DragPointLight CurrentLight => lightList[SelectedLightIndex];
-        public event EventHandler Rotate;
-        public event EventHandler Scale;
-        public event EventHandler ListModified;
-        public event EventHandler Select;
 
-        public LightManager() => Activate();
+        public string[] LightNameList =>
+            lightList.Select(light => LightName(light.Name)).ToArray();
+
+        public string ActiveLightName =>
+            LightName(lightList[SelectedLightIndex].Name);
+
+        public DragPointLight CurrentLight =>
+            lightList[SelectedLightIndex];
+
+        public LightManager() =>
+            Activate();
 
         public void Activate()
         {
@@ -52,16 +65,16 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Deactivate()
         {
-            for (int i = 0; i < lightList.Count; i++)
-            {
+            for (var i = 0; i < lightList.Count; i++)
                 DestroyLight(lightList[i]);
-            }
+
             selectedLightIndex = 0;
             lightList.Clear();
 
             GameMain.Instance.MainLight.Reset();
 
-            Light mainLight = GameMain.Instance.MainLight.GetComponent<Light>();
+            var mainLight = GameMain.Instance.MainLight.GetComponent<Light>();
+
             mainLight.type = LightType.Directional;
             DragPointLight.SetLightProperties(mainLight, new LightProperty());
             CubeActiveChange -= OnCubeActive;
@@ -71,8 +84,10 @@ namespace MeidoPhotoStudio.Plugin
 
         public void AddLight(GameObject lightGo = null, bool isMain = false)
         {
-            GameObject go = lightGo ?? new GameObject("MPS Light");
-            DragPointLight light = DragPoint.Make<DragPointLight>(PrimitiveType.Cube, Vector3.one * 0.12f);
+            // TODO: null propagation does not work with UntiyEngine.Object
+            var go = lightGo ?? new GameObject("MPS Light");
+            var light = DragPoint.Make<DragPointLight>(PrimitiveType.Cube, Vector3.one * 0.12f);
+
             light.Initialize(() => go.transform.position, () => go.transform.eulerAngles);
             light.Set(go.transform);
             light.IsMain = isMain;
@@ -91,71 +106,90 @@ namespace MeidoPhotoStudio.Plugin
 
         public void DeleteActiveLight()
         {
-            if (selectedLightIndex == 0) return;
+            if (selectedLightIndex == 0)
+                return;
 
             DeleteLight(SelectedLightIndex);
         }
 
         public void DeleteLight(int lightIndex, bool noUpdate = false)
         {
-            if (lightIndex == 0) return;
+            if (lightIndex == 0)
+                return;
 
             DestroyLight(lightList[lightIndex]);
             lightList.RemoveAt(lightIndex);
 
-            if (lightIndex <= SelectedLightIndex) SelectedLightIndex--;
+            if (lightIndex <= SelectedLightIndex)
+                SelectedLightIndex--;
+
+            if (noUpdate)
+                return;
 
-            if (noUpdate) return;
             OnListModified();
         }
 
-        public void SetColourModeActive(bool isColourMode) => lightList[0].IsColourMode = isColourMode;
+        public void SetColourModeActive(bool isColourMode) =>
+            lightList[0].IsColourMode = isColourMode;
 
         public void ClearLights()
         {
-            for (int i = lightList.Count - 1; i > 0; i--) DeleteLight(i);
+            for (var i = lightList.Count - 1; i > 0; i--)
+                DeleteLight(i);
+
             selectedLightIndex = 0;
         }
 
         private void DestroyLight(DragPointLight light)
         {
-            if (light == null) return;
+            if (light == null)
+                return;
+
             light.Rotate -= OnRotate;
             light.Scale -= OnScale;
             light.Delete -= OnDelete;
             light.Select -= OnSelect;
-            GameObject.Destroy(light.gameObject);
+
+            UnityEngine.Object.Destroy(light.gameObject);
         }
 
-        private string LightName(string name) => Translation.Get("lightType", name);
+        private string LightName(string name) =>
+            Translation.Get("lightType", name);
 
         private void OnDelete(object sender, EventArgs args)
         {
-            DragPointLight theLight = (DragPointLight)sender;
-            for (int i = 1; i < lightList.Count; i++)
+            var theLight = (DragPointLight)sender;
+
+            for (var i = 1; i < lightList.Count; i++)
             {
-                DragPointLight light = lightList[i];
+                var light = lightList[i];
+
                 if (light == theLight)
                 {
                     DeleteLight(i);
+
                     return;
                 }
             }
         }
 
-        private void OnRotate(object sender, EventArgs args) => OnTransformEvent((DragPointLight)sender, Rotate);
+        private void OnRotate(object sender, EventArgs args) =>
+            OnTransformEvent((DragPointLight)sender, Rotate);
 
-        private void OnScale(object sender, EventArgs args) => OnTransformEvent((DragPointLight)sender, Scale);
+        private void OnScale(object sender, EventArgs args) =>
+            OnTransformEvent((DragPointLight)sender, Scale);
 
         private void OnTransformEvent(DragPointLight light, EventHandler handler)
         {
-            if (light.IsActiveLight) handler?.Invoke(this, EventArgs.Empty);
+            if (light.IsActiveLight)
+                handler?.Invoke(this, EventArgs.Empty);
         }
 
         private void OnSelect(object sender, EventArgs args)
         {
-            DragPointLight theLight = (DragPointLight)sender;
-            int select = lightList.FindIndex(light => light == theLight);
+            var theLight = (DragPointLight)sender;
+            var select = lightList.FindIndex(light => light == theLight);
+
             if (select >= 0)
             {
                 SelectedLightIndex = select;
@@ -163,11 +197,13 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private void OnListModified() => ListModified?.Invoke(this, EventArgs.Empty);
+        private void OnListModified() =>
+            ListModified?.Invoke(this, EventArgs.Empty);
 
         private void OnCubeActive(object sender, EventArgs args)
         {
-            foreach (DragPointLight dragPoint in lightList) dragPoint.gameObject.SetActive(CubeActive);
+            foreach (var dragPoint in lightList)
+                dragPoint.gameObject.SetActive(CubeActive);
         }
     }
 }

+ 228 - 195
src/MeidoPhotoStudio.Plugin/Managers/MeidoManager.cs

@@ -9,29 +9,45 @@ namespace MeidoPhotoStudio.Plugin
     public class MeidoManager : IManager
     {
         public const string header = "MEIDO";
+
         private static readonly CharacterMgr characterMgr = GameMain.Instance.CharacterMgr;
+
         private static bool active;
+
         private static int EditMaidIndex { get; set; }
-        private int undress;
-        private int tempEditMaidIndex = -1;
-        public Meido[] Meidos { get; private set; }
-        public HashSet<int> SelectedMeidoSet { get; } = new HashSet<int>();
-        public List<int> SelectMeidoList { get; } = new List<int>();
-        public List<Meido> ActiveMeidoList { get; } = new List<Meido>();
-        public Meido ActiveMeido => ActiveMeidoList.Count > 0 ? ActiveMeidoList[SelectedMeido] : null;
-        public Meido EditMeido => tempEditMaidIndex >= 0 ? Meidos[tempEditMaidIndex] : Meidos[EditMaidIndex];
-        public bool HasActiveMeido => ActiveMeido != null;
+
         public event EventHandler<MeidoUpdateEventArgs> UpdateMeido;
         public event EventHandler EndCallMeidos;
         public event EventHandler BeginCallMeidos;
+
         private int selectedMeido;
+        private bool globalGravity;
+        private int undress;
+        private int tempEditMaidIndex = -1;
+
+        public Meido[] Meidos { get; private set; }
+        public HashSet<int> SelectedMeidoSet { get; } = new();
+        public List<int> SelectMeidoList { get; } = new();
+        public List<Meido> ActiveMeidoList { get; } = new();
+
         public int SelectedMeido
         {
             get => selectedMeido;
             private set => selectedMeido = Utility.Bound(value, 0, ActiveMeidoList.Count - 1);
         }
-        public bool Busy => ActiveMeidoList.Any(meido => meido.Busy);
-        private bool globalGravity;
+
+        public bool Busy =>
+            ActiveMeidoList.Any(meido => meido.Busy);
+
+        public Meido ActiveMeido =>
+            ActiveMeidoList.Count > 0 ? ActiveMeidoList[SelectedMeido] : null;
+
+        public Meido EditMeido =>
+            tempEditMaidIndex >= 0 ? Meidos[tempEditMaidIndex] : Meidos[EditMaidIndex];
+
+        public bool HasActiveMeido =>
+            ActiveMeido != null;
+
         public bool GlobalGravity
         {
             get => globalGravity;
@@ -39,27 +55,144 @@ namespace MeidoPhotoStudio.Plugin
             {
                 globalGravity = value;
 
-                if (!HasActiveMeido) return;
+                if (!HasActiveMeido)
+                    return;
 
-                Meido activeMeido = ActiveMeido;
-                int activeMeidoSlot = activeMeido.Slot;
+                var activeMeido = ActiveMeido;
+                var activeMeidoSlot = activeMeido.Slot;
 
-                foreach (Meido meido in ActiveMeidoList)
+                foreach (var meido in ActiveMeidoList)
                 {
-                    if (meido.Slot != activeMeidoSlot)
-                    {
-                        meido.HairGravityActive = value && activeMeido.HairGravityActive;
-                        meido.SkirtGravityActive = value && activeMeido.SkirtGravityActive;
-                    }
+                    if (meido.Slot == activeMeidoSlot)
+                        continue;
+
+                    meido.HairGravityActive = value && activeMeido.HairGravityActive;
+                    meido.SkirtGravityActive = value && activeMeido.SkirtGravityActive;
                 }
             }
         }
 
-        static MeidoManager() => InputManager.Register(MpsKey.MeidoUndressing, KeyCode.H, "All maid undressing");
+        static MeidoManager() =>
+            InputManager.Register(MpsKey.MeidoUndressing, KeyCode.H, "All maid undressing");
+
+        private static void SetEditorMaid(Maid maid)
+        {
+            if (maid == null)
+            {
+                Utility.LogWarning("Refusing to change editing maid because the new maid is null!");
+
+                return;
+            }
+
+            if (SceneEdit.Instance.maid.status.guid == maid.status.guid)
+            {
+                Utility.LogDebug("Editing maid is the same as new maid");
+
+                return;
+            }
+
+            var uiRoot = GameObject.Find("UI Root");
+
+            if (!TryGetUIControl<PresetCtrl>(uiRoot, "PresetPanel", out var presetCtrl))
+                return;
+
+            if (!TryGetUIControl<PresetButtonCtrl>(uiRoot, "PresetButtonPanel", out var presetButtonCtrl))
+                return;
+
+            if (!TryGetUIControl<ProfileCtrl>(uiRoot, "ProfilePanel", out var profileCtrl))
+                return;
+
+            if (!TryGetUIControl<SceneEditWindow.CustomPartsWindow>(
+                uiRoot, "Window/CustomPartsWindow", out var sceneEditWindow
+            ))
+                return;
+
+            // Preset application
+            presetCtrl.m_maid = maid;
+
+            // Preset saving
+            presetButtonCtrl.m_maid = maid;
+
+            // Maid profile (name, description, experience etc)
+            profileCtrl.m_maidStatus = maid.status;
+
+            // Accessory/Parts placement
+            sceneEditWindow.maid = maid;
+
+            // Stopping maid animation and head movement when customizing parts placement
+            sceneEditWindow.animation = maid.GetAnimation();
+
+            // Clothing/body in general and maybe other things
+            SceneEdit.Instance.m_maid = maid;
+
+            // Body status, parts colours and maybe more
+            GameMain.Instance.CharacterMgr.m_gcActiveMaid[0] = maid;
+
+            static bool TryGetUIControl<T>(GameObject root, string hierarchy, out T uiControl) where T : MonoBehaviour
+            {
+                uiControl = null;
+
+                var uiElement = UTY.GetChildObjectNoError(root, hierarchy);
+
+                if (!uiElement)
+                    return false;
+
+                uiControl = uiElement.GetComponent<T>();
+
+                return uiControl;
+            }
+        }
+
+        [HarmonyPostfix]
+        [HarmonyPatch(typeof(SceneEdit), nameof(SceneEdit.Start))]
+        private static void SceneEditStartPostfix()
+        {
+            EditMaidIndex = -1;
+
+            if (SceneEdit.Instance.maid == null)
+                return;
+
+            var originalEditingMaid = SceneEdit.Instance.maid;
+
+            EditMaidIndex = GameMain.Instance.CharacterMgr.GetStockMaidList()
+                .FindIndex(maid => maid.status.guid == originalEditingMaid.status.guid);
+
+            try
+            {
+                var editOkCancelButton = UTY.GetChildObject(GameObject.Find("UI Root"), "OkCancel")
+                    .GetComponent<EditOkCancel>();
+
+                EditOkCancel.OnClick newEditOkCancelDelegate = RestoreOriginalEditingMaid;
+
+                newEditOkCancelDelegate += editOkCancelButton.m_dgOnClickOk;
+
+                editOkCancelButton.m_dgOnClickOk = newEditOkCancelDelegate;
+
+                void RestoreOriginalEditingMaid()
+                {
+                    // Only restore original editing maid when active.
+                    if (!active)
+                        return;
+
+                    Utility.LogDebug($"Setting Editing maid back to '{originalEditingMaid.status.fullNameJpStyle}'");
+
+                    SetEditorMaid(originalEditingMaid);
+
+                    // Set SceneEdit's maid regardless of UI integration failing
+                    SceneEdit.Instance.m_maid = originalEditingMaid;
+                }
+            }
+            catch (Exception e)
+            {
+                Utility.LogWarning($"Failed to hook onto Edit Mode OK button: {e}");
+            }
+        }
 
-        public MeidoManager() => Activate();
+        public MeidoManager() =>
+            Activate();
 
-        public void ChangeMaid(int index) => OnUpdateMeido(null, new MeidoUpdateEventArgs(index));
+        public void ChangeMaid(int index) =>
+            OnUpdateMeido(null, new MeidoUpdateEventArgs(index));
 
         public void Activate()
         {
@@ -82,7 +215,7 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Deactivate()
         {
-            foreach (Meido meido in Meidos)
+            foreach (var meido in Meidos)
             {
                 meido.UpdateMeido -= OnUpdateMeido;
                 meido.GravityMove -= OnGravityMove;
@@ -93,7 +226,8 @@ namespace MeidoPhotoStudio.Plugin
 
             if (MeidoPhotoStudio.EditMode && !GameMain.Instance.MainCamera.IsFadeOut())
             {
-                Meido meido = Meidos[EditMaidIndex];
+                var meido = Meidos[EditMaidIndex];
+
                 meido.Maid.Visible = true;
                 meido.Stop = false;
                 meido.EyeToCam = true;
@@ -106,60 +240,32 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Update()
         {
-            if (InputManager.GetKeyDown(MpsKey.MeidoUndressing)) UndressAll();
-        }
-
-        private void UnloadMeidos()
-        {
-            SelectedMeido = 0;
-
-            var commonMeidoIDs = new HashSet<int>(
-                ActiveMeidoList.Where(meido => SelectedMeidoSet.Contains(meido.StockNo)).Select(meido => meido.StockNo)
-            );
-
-            foreach (Meido meido in ActiveMeidoList)
-            {
-                meido.UpdateMeido -= OnUpdateMeido;
-                meido.GravityMove -= OnGravityMove;
-                
-                if (!commonMeidoIDs.Contains(meido.StockNo))
-                    meido.Unload();
-            }
-
-            ActiveMeidoList.Clear();
+            if (InputManager.GetKeyDown(MpsKey.MeidoUndressing))
+                UndressAll();
         }
 
         public void CallMeidos()
         {
             BeginCallMeidos?.Invoke(this, EventArgs.Empty);
 
-            bool moreThanEditMaid = ActiveMeidoList.Count > 1;
+            var moreThanEditMaid = ActiveMeidoList.Count > 1;
 
             UnloadMeidos();
 
             if (SelectMeidoList.Count == 0)
             {
                 OnEndCallMeidos(this, EventArgs.Empty);
+
                 return;
             }
 
-            void callMeidos() => GameMain.Instance.StartCoroutine(LoadMeidos());
-
-            if (MeidoPhotoStudio.EditMode && !moreThanEditMaid && SelectMeidoList.Count == 1) callMeidos();
-            else GameMain.Instance.MainCamera.FadeOut(0.01f, f_bSkipable: false, f_dg: callMeidos);
-        }
-
-        private System.Collections.IEnumerator LoadMeidos()
-        {
-            foreach (int slot in SelectMeidoList) ActiveMeidoList.Add(Meidos[slot]);
-
-            for (int i = 0; i < ActiveMeidoList.Count; i++) ActiveMeidoList[i].Load(i);
+            void callMeidos() =>
+                GameMain.Instance.StartCoroutine(LoadMeidos());
 
-            while (Busy) yield return null;
-
-            yield return new WaitForEndOfFrame();
-
-            OnEndCallMeidos(this, EventArgs.Empty);
+            if (MeidoPhotoStudio.EditMode && !moreThanEditMaid && SelectMeidoList.Count == 1)
+                callMeidos();
+            else
+                GameMain.Instance.MainCamera.FadeOut(0.01f, f_bSkipable: false, f_dg: callMeidos);
         }
 
         public void SelectMeido(int index)
@@ -183,6 +289,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             SelectedMeidoSet.Clear();
             SelectMeidoList.Clear();
+
             if (MeidoPhotoStudio.EditMode)
             {
                 SelectedMeidoSet.Add(EditMaidIndex);
@@ -192,7 +299,8 @@ namespace MeidoPhotoStudio.Plugin
 
         public void SetEditMaid(Meido meido)
         {
-            if (!MeidoPhotoStudio.EditMode) return;
+            if (!MeidoPhotoStudio.EditMode)
+                return;
 
             EditMeido.IsEditMaid = false;
 
@@ -203,35 +311,69 @@ namespace MeidoPhotoStudio.Plugin
             SetEditorMaid(EditMeido.Maid);
         }
 
-        public Meido GetMeido(string guid)
-        {
-            return string.IsNullOrEmpty(guid) ? null : ActiveMeidoList.Find(meido => meido.Maid.status.guid == guid);
-        }
+        public Meido GetMeido(string guid) =>
+            string.IsNullOrEmpty(guid) ? null : ActiveMeidoList.Find(meido => meido.Maid.status.guid == guid);
 
-        public Meido GetMeido(int activeIndex)
+        public Meido GetMeido(int activeIndex) =>
+            activeIndex >= 0 && activeIndex < ActiveMeidoList.Count ? ActiveMeidoList[activeIndex] : null;
+
+        public void PlaceMeidos(string placementType) =>
+            MaidPlacementUtility.ApplyPlacement(placementType, ActiveMeidoList);
+
+        private void UnloadMeidos()
         {
-            return activeIndex >= 0 && activeIndex < ActiveMeidoList.Count ? ActiveMeidoList[activeIndex] : null;
+            SelectedMeido = 0;
+
+            var commonMeidoIDs = new HashSet<int>(
+                ActiveMeidoList.Where(meido => SelectedMeidoSet.Contains(meido.StockNo)).Select(meido => meido.StockNo)
+            );
+
+            foreach (var meido in ActiveMeidoList)
+            {
+                meido.UpdateMeido -= OnUpdateMeido;
+                meido.GravityMove -= OnGravityMove;
+
+                if (!commonMeidoIDs.Contains(meido.StockNo))
+                    meido.Unload();
+            }
+
+            ActiveMeidoList.Clear();
         }
 
-        public void PlaceMeidos(string placementType)
+        private System.Collections.IEnumerator LoadMeidos()
         {
-            MaidPlacementUtility.ApplyPlacement(placementType, ActiveMeidoList);
+            foreach (var slot in SelectMeidoList)
+                ActiveMeidoList.Add(Meidos[slot]);
+
+            for (var i = 0; i < ActiveMeidoList.Count; i++)
+                ActiveMeidoList[i].Load(i);
+
+            while (Busy)
+                yield return null;
+
+            yield return new WaitForEndOfFrame();
+
+            OnEndCallMeidos(this, EventArgs.Empty);
         }
 
         private void UndressAll()
         {
-            if (!HasActiveMeido) return;
+            if (!HasActiveMeido)
+                return;
 
             undress = ++undress % Enum.GetNames(typeof(Meido.Mask)).Length;
 
-            foreach (Meido activeMeido in ActiveMeidoList) activeMeido.SetMaskMode((Meido.Mask)undress);
+            foreach (var activeMeido in ActiveMeidoList)
+                activeMeido.SetMaskMode((Meido.Mask)undress);
 
             UpdateMeido?.Invoke(ActiveMeido, new MeidoUpdateEventArgs(SelectedMeido));
         }
 
         private void OnUpdateMeido(object sender, MeidoUpdateEventArgs args)
         {
-            if (!args.IsEmpty) SelectedMeido = args.SelectedMeido;
+            if (!args.IsEmpty)
+                SelectedMeido = args.SelectedMeido;
+
             UpdateMeido?.Invoke(ActiveMeido, args);
         }
 
@@ -239,147 +381,38 @@ namespace MeidoPhotoStudio.Plugin
         {
             GameMain.Instance.MainCamera.FadeIn(1f);
             EndCallMeidos?.Invoke(this, EventArgs.Empty);
-            foreach (Meido meido in ActiveMeidoList)
+
+            foreach (var meido in ActiveMeidoList)
             {
                 meido.UpdateMeido += OnUpdateMeido;
                 meido.GravityMove += OnGravityMove;
             }
 
             if (MeidoPhotoStudio.EditMode && tempEditMaidIndex >= 0 && !SelectedMeidoSet.Contains(tempEditMaidIndex))
-            {
                 SetEditMaid(Meidos[EditMaidIndex]);
-            }
         }
 
         private void OnGravityMove(object sender, GravityEventArgs args)
         {
-            if (!GlobalGravity) return;
-
-            foreach (Meido meido in ActiveMeidoList)
-            {
-                meido.ApplyGravity(args.LocalPosition, args.IsSkirt);
-            }
-        }
-
-        private static void SetEditorMaid(Maid maid)
-        {
-            if (maid == null)
-            {
-                Utility.LogWarning("Refusing to change editing maid because the new maid is null!");
-                return;
-            }
-
-            if (SceneEdit.Instance.maid.status.guid == maid.status.guid)
-            {
-                Utility.LogDebug("Editing maid is the same as new maid");
-                return;
-            }
-
-            var uiRoot = GameObject.Find("UI Root");
-
-            if (!TryGetUIControl<PresetCtrl>(uiRoot, "PresetPanel", out var presetCtrl))
-                return;
-
-            if (!TryGetUIControl<PresetButtonCtrl>(uiRoot, "PresetButtonPanel", out var presetButtonCtrl))
-                return;
-
-            if (!TryGetUIControl<ProfileCtrl>(uiRoot, "ProfilePanel", out var profileCtrl))
-                return;
-
-            if (!TryGetUIControl<SceneEditWindow.CustomPartsWindow>(
-                uiRoot, "Window/CustomPartsWindow", out var sceneEditWindow
-            ))
+            if (!GlobalGravity)
                 return;
 
-            // Preset application
-            presetCtrl.m_maid = maid;
-
-            // Preset saving
-            presetButtonCtrl.m_maid = maid;
-
-            // Maid profile (name, description, experience etc)
-            profileCtrl.m_maidStatus = maid.status;
-
-            // Accessory/Parts placement
-            sceneEditWindow.maid = maid;
-
-            // Stopping maid animation and head movement when customizing parts placement
-            sceneEditWindow.animation = maid.GetAnimation();
-
-            // Clothing/body in general and maybe other things
-            SceneEdit.Instance.m_maid = maid;
-
-            // Body status, parts colours and maybe more
-            GameMain.Instance.CharacterMgr.m_gcActiveMaid[0] = maid;
-
-            static bool TryGetUIControl<T>(GameObject root, string hierarchy, out T uiControl) where T : MonoBehaviour
-            {
-                uiControl = null;
-
-                var uiElement = UTY.GetChildObjectNoError(root, hierarchy);
-
-                if (!uiElement)
-                    return false;
-
-                uiControl = uiElement.GetComponent<T>();
-
-                return uiControl;
-            }
-        }
-
-        [HarmonyPostfix]
-        [HarmonyPatch(typeof(SceneEdit), nameof(SceneEdit.Start))]
-        private static void SceneEditStartPostfix()
-        {
-            EditMaidIndex = -1;
-
-            if (SceneEdit.Instance.maid == null)
-                return;
-
-            var originalEditingMaid = SceneEdit.Instance.maid;
-
-            EditMaidIndex = GameMain.Instance.CharacterMgr.GetStockMaidList()
-                .FindIndex(maid => maid.status.guid == originalEditingMaid.status.guid);
-
-            try
-            {
-                var editOkCancelButton = UTY.GetChildObject(GameObject.Find("UI Root"), "OkCancel")
-                    .GetComponent<EditOkCancel>();
-
-                EditOkCancel.OnClick newEditOkCancelDelegate = RestoreOriginalEditingMaid;
-
-                newEditOkCancelDelegate += editOkCancelButton.m_dgOnClickOk;
-
-                editOkCancelButton.m_dgOnClickOk = newEditOkCancelDelegate;
-
-                void RestoreOriginalEditingMaid()
-                {
-                    // Only restore original editing maid when active.
-                    if (!active)
-                        return;
-
-                    Utility.LogDebug($"Setting Editing maid back to '{originalEditingMaid.status.fullNameJpStyle}'");
-
-                    SetEditorMaid(originalEditingMaid);
-
-                    // Set SceneEdit's maid regardless of UI integration failing
-                    SceneEdit.Instance.m_maid = originalEditingMaid;
-                }
-            }
-            catch (Exception e)
-            {
-                Utility.LogWarning($"Failed to hook onto Edit Mode OK button: {e}");
-            }
+            foreach (var meido in ActiveMeidoList)
+                meido.ApplyGravity(args.LocalPosition, args.IsSkirt);
         }
     }
 
     public class MeidoUpdateEventArgs : EventArgs
     {
-        public static new MeidoUpdateEventArgs Empty { get; } = new MeidoUpdateEventArgs(-1);
-        public bool IsEmpty => (this == Empty) || (SelectedMeido == -1 && !FromMeido && IsBody);
+        public static new MeidoUpdateEventArgs Empty { get; } = new(-1);
+
         public int SelectedMeido { get; }
         public bool IsBody { get; }
         public bool FromMeido { get; }
+
+        public bool IsEmpty =>
+            this == Empty || SelectedMeido == -1 && !FromMeido && IsBody;
+
         public MeidoUpdateEventArgs(int meidoIndex = -1, bool fromMaid = false, bool isBody = true)
         {
             SelectedMeido = meidoIndex;

+ 3 - 5
src/MeidoPhotoStudio.Plugin/Managers/MessageWindowManager.cs

@@ -1,4 +1,3 @@
-using System.Collections.Generic;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
@@ -6,7 +5,8 @@ namespace MeidoPhotoStudio.Plugin
     public class MessageWindowManager : IManager
     {
         public const string header = "TEXTBOX";
-        public static readonly SliderProp FontBounds = new SliderProp(25f, 60f);
+
+        public static readonly SliderProp FontBounds = new(25f, 60f);
 
         private readonly MessageWindowMgr messageWindowMgr;
         private readonly GameObject subtitlesDisplayPanel;
@@ -46,10 +46,8 @@ namespace MeidoPhotoStudio.Plugin
             set => messageLabel.fontSize = (int)Mathf.Clamp(value, FontBounds.Left, FontBounds.Right);
         }
 
-        static MessageWindowManager()
-        {
+        static MessageWindowManager() =>
             InputManager.Register(MpsKey.ToggleMessage, KeyCode.M, "Show/hide message box");
-        }
 
         public MessageWindowManager()
         {

+ 118 - 72
src/MeidoPhotoStudio.Plugin/Managers/PropManager.cs

@@ -1,40 +1,27 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using BepInEx.Configuration;
 using UnityEngine;
+
+using static MeidoPhotoStudio.Plugin.ModelUtility;
+
 using Object = UnityEngine.Object;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using static ModelUtility;
-
     public class PropManager : IManager
     {
         public const string header = "PROP";
+
         private static readonly ConfigEntry<bool> modItemsOnly;
+
         private static bool cubeActive = true;
         private static Dictionary<string, string> modFileToFullPath;
-
-        private static Dictionary<string, string> ModFileToFullPath
-        {
-            get
-            {
-                if (modFileToFullPath != null) return modFileToFullPath;
-
-                string[] modFiles = Menu.GetModFiles();
-                modFileToFullPath = new Dictionary<string, string>(modFiles.Length, StringComparer.OrdinalIgnoreCase);
-
-                foreach (var mod in modFiles)
-                {
-                    var key = Path.GetFileName(mod);
-                    if (!modFileToFullPath.ContainsKey(key)) modFileToFullPath[key] = mod;
-                }
-
-                return modFileToFullPath;
-            }
-        }
+        private static bool cubeSmall;
+        private static event EventHandler CubeActiveChange;
+        private static event EventHandler CubeSmallChange;
 
         public static bool CubeActive
         {
@@ -49,8 +36,6 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private static bool cubeSmall;
-
         public static bool CubeSmall
         {
             get => cubeSmall;
@@ -64,18 +49,51 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private static event EventHandler CubeActiveChange;
-        private static event EventHandler CubeSmallChange;
-        public static bool ModItemsOnly => modItemsOnly.Value;
-        private readonly List<DragPointProp> propList = new List<DragPointProp>();
+        private static Dictionary<string, string> ModFileToFullPath
+        {
+            get
+            {
+                if (modFileToFullPath != null)
+                    return modFileToFullPath;
+
+                var modFiles = Menu.GetModFiles();
+
+                modFileToFullPath = new Dictionary<string, string>(modFiles.Length, StringComparer.OrdinalIgnoreCase);
+
+                foreach (var mod in modFiles)
+                {
+                    var key = Path.GetFileName(mod);
+
+                    if (!modFileToFullPath.ContainsKey(key))
+                        modFileToFullPath[key] = mod;
+                }
+
+                return modFileToFullPath;
+            }
+        }
+
+        public static bool ModItemsOnly =>
+            modItemsOnly.Value;
+
+        public DragPointProp CurrentProp =>
+            PropCount == 0 ? null : propList[CurrentPropIndex];
+
+        private readonly List<DragPointProp> propList = new();
+        private readonly MeidoManager meidoManager;
+
+        public event EventHandler PropSelectionChange;
+        public event EventHandler FromPropSelect;
+        public event EventHandler PropListChange;
+
+        private int currentPropIndex;
 
-        public string[] PropNameList => propList.Count == 0
+        public string[] PropNameList =>
+            propList.Count == 0
             ? new[] { Translation.Get("systemMessage", "noProps") }
             : propList.Select(prop => prop.Name).ToArray();
 
-        public int PropCount => propList.Count;
-        private int currentPropIndex;
-        private MeidoManager meidoManager;
+        public int PropCount =>
+            propList.Count;
 
         public int CurrentPropIndex
         {
@@ -88,21 +106,19 @@ namespace MeidoPhotoStudio.Plugin
                     return;
                 }
 
-                if ((uint) value >= (uint) PropCount) throw new ArgumentOutOfRangeException(nameof(value));
+                if ((uint)value >= (uint)PropCount)
+                    throw new ArgumentOutOfRangeException(nameof(value));
 
-                if (currentPropIndex == value) return;
+                if (currentPropIndex == value)
+                    return;
 
                 currentPropIndex = value;
                 PropSelectionChange?.Invoke(this, EventArgs.Empty);
             }
         }
 
-        public DragPointProp CurrentProp => PropCount == 0 ? null : propList[CurrentPropIndex];
-        public event EventHandler PropSelectionChange;
-        public event EventHandler FromPropSelect;
-        public event EventHandler PropListChange;
-
-        static PropManager() => modItemsOnly = Configuration.Config.Bind(
+        static PropManager() =>
+            modItemsOnly = Configuration.Config.Bind(
             "Prop", "ModItemsOnly",
             false,
             "Disable waiting for and loading base game clothing"
@@ -122,12 +138,14 @@ namespace MeidoPhotoStudio.Plugin
             {
                 case PropInfo.PropType.Mod:
                     ModItem modItem;
+
                     if (!string.IsNullOrEmpty(propInfo.SubFilename))
                     {
                         modItem = ModItem.OfficialMod(ModFileToFullPath[propInfo.Filename]);
                         modItem.BaseMenuFile = propInfo.SubFilename;
                     }
-                    else modItem = ModItem.Mod(propInfo.Filename);
+                    else
+                        modItem = ModItem.Mod(propInfo.Filename);
 
                     return AddModProp(modItem);
                 case PropInfo.PropType.MyRoom:
@@ -143,13 +161,19 @@ namespace MeidoPhotoStudio.Plugin
         public bool AddModProp(ModItem modItem)
         {
             var model = LoadMenuModel(modItem);
-            if (!model) return false;
+
+            if (!model)
+                return false;
 
             var name = modItem.MenuFile;
-            if (modItem.IsOfficialMod) name = Path.GetFileName(name) + ".menu"; // add '.menu' for partsedit support
+
+            if (modItem.IsOfficialMod)
+                name = Path.GetFileName(name) + ".menu"; // add '.menu' for partsedit support
+
             model.name = name;
 
             var dragPoint = AttachDragPoint(model);
+
             dragPoint.Info = PropInfo.FromModItem(modItem);
 
             AddProp(dragPoint);
@@ -160,11 +184,14 @@ namespace MeidoPhotoStudio.Plugin
         public bool AddMyRoomProp(MyRoomItem myRoomItem)
         {
             var model = LoadMyRoomModel(myRoomItem);
-            if (!model) return false;
+
+            if (!model)
+                return false;
 
             model.name = Translation.Get("myRoomPropNames", myRoomItem.PrefabName);
 
             var dragPoint = AttachDragPoint(model);
+
             dragPoint.Info = PropInfo.FromMyRoom(myRoomItem);
 
             AddProp(dragPoint);
@@ -175,11 +202,14 @@ namespace MeidoPhotoStudio.Plugin
         public bool AddBgProp(string assetName)
         {
             var model = LoadBgModel(assetName);
-            if (!model) return false;
+
+            if (!model)
+                return false;
 
             model.name = Translation.Get("bgNames", assetName);
 
             var dragPoint = AttachDragPoint(model);
+
             dragPoint.Info = PropInfo.FromBg(assetName);
 
             AddProp(dragPoint);
@@ -191,11 +221,14 @@ namespace MeidoPhotoStudio.Plugin
         {
             var isMenu = assetName.EndsWith(".menu");
             var model = isMenu ? LoadMenuModel(assetName) : LoadGameModel(assetName);
-            if (!model) return false;
+
+            if (!model)
+                return false;
 
             model.name = Translation.Get("propNames", isMenu ? Utility.HandItemToOdogu(assetName) : assetName, !isMenu);
 
             var dragPoint = AttachDragPoint(model);
+
             dragPoint.Info = PropInfo.FromGameProp(assetName);
 
             AddProp(dragPoint);
@@ -205,22 +238,27 @@ namespace MeidoPhotoStudio.Plugin
 
         public void CopyProp(int propIndex)
         {
-            if ((uint) propIndex >= (uint) PropCount) throw new ArgumentOutOfRangeException(nameof(propIndex));
+            if ((uint)propIndex >= (uint)PropCount)
+                throw new ArgumentOutOfRangeException(nameof(propIndex));
 
             AddFromPropInfo(propList[propIndex].Info);
         }
 
         public void DeleteAllProps()
         {
-            foreach (var prop in propList) DestroyProp(prop);
+            foreach (var prop in propList)
+                DestroyProp(prop);
+
             propList.Clear();
             CurrentPropIndex = 0;
+
             EmitPropListChange();
         }
 
         public void RemoveProp(int index)
         {
-            if ((uint) index >= (uint) PropCount) throw new ArgumentOutOfRangeException(nameof(index));
+            if ((uint)index >= (uint)PropCount)
+                throw new ArgumentOutOfRangeException(nameof(index));
 
             DestroyProp(propList[index]);
             propList.RemoveAt(index);
@@ -230,16 +268,33 @@ namespace MeidoPhotoStudio.Plugin
 
         public void AttachProp(DragPointProp prop, AttachPoint point, int index)
         {
-            if ((uint) index >= (uint) meidoManager.ActiveMeidoList.Count) return;
+            if ((uint)index >= (uint)meidoManager.ActiveMeidoList.Count)
+                return;
 
             var meido = meidoManager.ActiveMeidoList[index];
 
             prop.AttachTo(meido, point);
         }
 
+        public void Update() { }
+
+        public void Activate()
+        {
+            CubeSmallChange += OnCubeSmall;
+            CubeActiveChange += OnCubeActive;
+        }
+
+        public void Deactivate()
+        {
+            DeleteAllProps();
+            CubeSmallChange -= OnCubeSmall;
+            CubeActiveChange -= OnCubeActive;
+        }
+
         private DragPointProp AttachDragPoint(GameObject model)
         {
             var dragPoint = DragPoint.Make<DragPointProp>(PrimitiveType.Cube, Vector3.one * 0.12f);
+
             dragPoint.Initialize(() => model.transform.position, () => Vector3.zero);
             dragPoint.Set(model.transform);
             dragPoint.AddGizmo(0.45f, CustomGizmo.GizmoMode.World);
@@ -247,6 +302,7 @@ namespace MeidoPhotoStudio.Plugin
             dragPoint.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
             dragPoint.Delete += OnDeleteProp;
             dragPoint.Select += OnSelectProp;
+
             return dragPoint;
         }
 
@@ -258,14 +314,16 @@ namespace MeidoPhotoStudio.Plugin
 
         private void DestroyProp(DragPointProp prop)
         {
-            if (!prop) return;
+            if (!prop)
+                return;
 
             prop.Delete -= OnDeleteProp;
             prop.Select -= OnSelectProp;
             Object.Destroy(prop.gameObject);
         }
 
-        private void EmitPropListChange() => PropListChange?.Invoke(this, EventArgs.Empty);
+        private void EmitPropListChange() =>
+            PropListChange?.Invoke(this, EventArgs.Empty);
 
         private void OnBeginCallMeidos(object sender, EventArgs args)
         {
@@ -279,42 +337,30 @@ namespace MeidoPhotoStudio.Plugin
             {
                 var info = prop.AttachPointInfo;
                 var meido = meidoManager.GetMeido(info.MaidGuid);
+
                 prop.AttachTo(meido, info.AttachPoint, meido == null);
             }
         }
 
-        private void OnDeleteProp(object sender, EventArgs args)
-            => RemoveProp(propList.IndexOf((DragPointProp) sender));
+        private void OnDeleteProp(object sender, EventArgs args) =>
+            RemoveProp(propList.IndexOf((DragPointProp)sender));
 
         private void OnSelectProp(object sender, EventArgs args)
         {
-            CurrentPropIndex = propList.IndexOf((DragPointProp) sender);
+            CurrentPropIndex = propList.IndexOf((DragPointProp)sender);
             FromPropSelect?.Invoke(this, EventArgs.Empty);
         }
 
         private void OnCubeSmall(object sender, EventArgs args)
         {
-            foreach (var dragPoint in propList) dragPoint.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
+            foreach (var dragPoint in propList)
+                dragPoint.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
         }
 
         private void OnCubeActive(object sender, EventArgs args)
         {
-            foreach (var dragPoint in propList) dragPoint.gameObject.SetActive(CubeActive);
-        }
-
-        public void Update() { }
-
-        public void Activate()
-        {
-            CubeSmallChange += OnCubeSmall;
-            CubeActiveChange += OnCubeActive;
-        }
-
-        public void Deactivate()
-        {
-            DeleteAllProps();
-            CubeSmallChange -= OnCubeSmall;
-            CubeActiveChange -= OnCubeActive;
+            foreach (var dragPoint in propList)
+                dragPoint.gameObject.SetActive(CubeActive);
         }
     }
 }

+ 132 - 94
src/MeidoPhotoStudio.Plugin/Managers/SceneManager.cs

@@ -1,51 +1,67 @@
 using System;
-using System.IO;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
-using UnityEngine;
 using BepInEx.Configuration;
+using UnityEngine;
+using Input = MeidoPhotoStudio.Plugin.InputManager;
 using Object = UnityEngine.Object;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class SceneManager : IManager
     {
+        public enum SortMode { Name, DateCreated, DateModified }
+
+        public static readonly Vector2 sceneDimensions = new(480, 270);
 
-        private static byte[] tempSceneData;
-        private static string TempScenePath => Path.Combine(Constants.configPath, "mpstempscene");
-        public static bool Busy { get; private set; }
-        public static readonly Vector2 sceneDimensions = new Vector2(480, 270);
         private static readonly ConfigEntry<bool> sortDescending;
         private static readonly ConfigEntry<SortMode> currentSortMode;
+
+        private static byte[] tempSceneData;
+
+        public static bool Busy { get; private set; }
+
+        private static string TempScenePath =>
+            Path.Combine(Constants.configPath, "mpstempscene");
+
         private readonly MeidoPhotoStudio meidoPhotoStudio;
-        private int SortDirection => SortDescending ? -1 : 1;
+
         public bool Initialized { get; private set; }
         public bool KankyoMode { get; set; }
+        public int CurrentSceneIndex { get; private set; } = -1;
+        public List<MPSScene> SceneList { get; } = new();
+        public int CurrentDirectoryIndex { get; private set; } = -1;
+
         public bool SortDescending
         {
             get => sortDescending.Value;
             set => sortDescending.Value = value;
         }
-        public List<MPSScene> SceneList { get; } = new();
-        public int CurrentDirectoryIndex { get; private set; } = -1;
-        public string CurrentDirectoryName => CurrentDirectoryList[CurrentDirectoryIndex];
-        public List<string> CurrentDirectoryList
-            => KankyoMode ? Constants.KankyoDirectoryList : Constants.SceneDirectoryList;
-        public string CurrentBasePath => KankyoMode ? Constants.kankyoPath : Constants.scenesPath;
-        public string CurrentScenesDirectory
-            => CurrentDirectoryIndex == 0 ? CurrentBasePath : Path.Combine(CurrentBasePath, CurrentDirectoryName);
+
+        public string CurrentDirectoryName =>
+            CurrentDirectoryList[CurrentDirectoryIndex];
+
+        public List<string> CurrentDirectoryList =>
+            KankyoMode ? Constants.KankyoDirectoryList : Constants.SceneDirectoryList;
+
+        public string CurrentBasePath =>
+            KankyoMode ? Constants.kankyoPath : Constants.scenesPath;
+
+        public string CurrentScenesDirectory =>
+            CurrentDirectoryIndex == 0 ? CurrentBasePath : Path.Combine(CurrentBasePath, CurrentDirectoryName);
+
         public SortMode CurrentSortMode
         {
             get => currentSortMode.Value;
             private set => currentSortMode.Value = value;
         }
-        public int CurrentSceneIndex { get; private set; } = -1;
-        public MPSScene CurrentScene => SceneList.Count == 0 ? null : SceneList[CurrentSceneIndex];
-        public enum SortMode
-        {
-            Name, DateCreated, DateModified
-        }
+
+        public MPSScene CurrentScene =>
+            SceneList.Count == 0 ? null : SceneList[CurrentSceneIndex];
+
+        private int SortDirection =>
+            SortDescending ? -1 : 1;
 
         static SceneManager()
         {
@@ -87,23 +103,27 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Update()
         {
-            if (Input.Control)
-            {
-                if (Input.GetKeyDown(MpsKey.SaveScene)) QuickSaveScene();
-                else if (Input.GetKeyDown(MpsKey.LoadScene)) QuickLoadScene();
-            }
+            if (!Input.Control)
+                return;
+
+            if (Input.GetKeyDown(MpsKey.SaveScene))
+                QuickSaveScene();
+            else if (Input.GetKeyDown(MpsKey.LoadScene))
+                QuickLoadScene();
         }
 
         public void DeleteDirectory()
         {
-            if (Directory.Exists(CurrentScenesDirectory)) Directory.Delete(CurrentScenesDirectory, true);
+            if (Directory.Exists(CurrentScenesDirectory))
+                Directory.Delete(CurrentScenesDirectory, true);
 
             CurrentDirectoryList.RemoveAt(CurrentDirectoryIndex);
             CurrentDirectoryIndex = Mathf.Clamp(CurrentDirectoryIndex, 0, CurrentDirectoryList.Count - 1);
             UpdateSceneList();
         }
 
-        public void OverwriteScene() => SaveScene(overwrite: true);
+        public void OverwriteScene() =>
+            SaveScene(overwrite: true);
 
         public void ToggleKankyoMode()
         {
@@ -114,10 +134,13 @@ namespace MeidoPhotoStudio.Plugin
 
         public void SaveScene(bool overwrite = false)
         {
-            if (Busy) return;
+            if (Busy)
+                return;
+
             Busy = true;
 
-            if (!Directory.Exists(CurrentScenesDirectory)) Directory.CreateDirectory(CurrentScenesDirectory);
+            if (!Directory.Exists(CurrentScenesDirectory))
+                Directory.CreateDirectory(CurrentScenesDirectory);
 
             MeidoPhotoStudio.NotifyRawScreenshot += SaveScene;
 
@@ -134,7 +157,8 @@ namespace MeidoPhotoStudio.Plugin
         {
             directoryIndex = Mathf.Clamp(directoryIndex, 0, CurrentDirectoryList.Count - 1);
 
-            if (directoryIndex == CurrentDirectoryIndex) return;
+            if (directoryIndex == CurrentDirectoryIndex)
+                return;
 
             CurrentDirectoryIndex = directoryIndex;
 
@@ -151,34 +175,39 @@ namespace MeidoPhotoStudio.Plugin
         {
             directoryName = Utility.SanitizePathPortion(directoryName);
 
-            if (!CurrentDirectoryList.Contains(directoryName, StringComparer.InvariantCultureIgnoreCase))
-            {
-                string finalPath = Path.Combine(CurrentBasePath, directoryName);
-                string fullPath = Path.GetFullPath(finalPath);
+            if (CurrentDirectoryList.Contains(directoryName, StringComparer.InvariantCultureIgnoreCase))
+                return;
 
-                if (!fullPath.StartsWith(CurrentBasePath))
-                {
-                    string baseDirectoryName = KankyoMode ? Constants.kankyoDirectory : Constants.sceneDirectory;
-                    Utility.LogError($"Could not add directory to {baseDirectoryName}. Path is invalid: '{fullPath}'");
-                    return;
-                }
+            var finalPath = Path.Combine(CurrentBasePath, directoryName);
+            var fullPath = Path.GetFullPath(finalPath);
 
-                CurrentDirectoryList.Add(directoryName);
-                Directory.CreateDirectory(finalPath);
+            if (!fullPath.StartsWith(CurrentBasePath))
+            {
+                var baseDirectoryName = KankyoMode ? Constants.kankyoDirectory : Constants.sceneDirectory;
 
-                UpdateDirectoryList();
-                CurrentDirectoryIndex = CurrentDirectoryList.IndexOf(directoryName);
+                Utility.LogError($"Could not add directory to {baseDirectoryName}. Path is invalid: '{fullPath}'");
 
-                UpdateSceneList();
+                return;
             }
+
+            CurrentDirectoryList.Add(directoryName);
+            Directory.CreateDirectory(finalPath);
+
+            UpdateDirectoryList();
+            CurrentDirectoryIndex = CurrentDirectoryList.IndexOf(directoryName);
+
+            UpdateSceneList();
         }
 
         public void Refresh()
         {
-            if (!Directory.Exists(CurrentScenesDirectory)) CurrentDirectoryIndex = 0;
+            if (!Directory.Exists(CurrentScenesDirectory))
+                CurrentDirectoryIndex = 0;
 
-            if (KankyoMode) Constants.InitializeKankyoDirectories();
-            else Constants.InitializeSceneDirectories();
+            if (KankyoMode)
+                Constants.InitializeKankyoDirectories();
+            else
+                Constants.InitializeSceneDirectories();
 
             UpdateSceneList();
         }
@@ -186,55 +215,49 @@ namespace MeidoPhotoStudio.Plugin
         public void SortScenes(SortMode sortMode)
         {
             CurrentSortMode = sortMode;
+
             Comparison<MPSScene> comparator = CurrentSortMode switch
             {
                 SortMode.DateModified => SortByDateModified,
                 SortMode.DateCreated => SortByDateCreated,
+                SortMode.Name => SortByName,
                 _ => SortByName,
             };
+
             SceneList.Sort(comparator);
         }
 
         public void DeleteScene()
         {
             if (CurrentScene.FileInfo.Exists)
-            {
                 CurrentScene.FileInfo.Delete();
-            }
+
             SceneList.RemoveAt(CurrentSceneIndex);
             CurrentSceneIndex = Mathf.Clamp(CurrentSceneIndex, 0, SceneList.Count - 1);
         }
 
-        public void LoadScene(MPSScene scene) => meidoPhotoStudio.LoadScene(scene.Data);
+        public void LoadScene(MPSScene scene) =>
+            meidoPhotoStudio.LoadScene(scene.Data);
 
-        private int SortByName(MPSScene a, MPSScene b)
-        {
-            return SortDirection * WindowsLogicalComparer.StrCmpLogicalW(a.FileInfo.Name, b.FileInfo.Name);
-        }
+        private int SortByName(MPSScene a, MPSScene b) =>
+            SortDirection * WindowsLogicalComparer.StrCmpLogicalW(a.FileInfo.Name, b.FileInfo.Name);
 
-        private int SortByDateCreated(MPSScene a, MPSScene b)
-        {
-            return SortDirection * DateTime.Compare(a.FileInfo.CreationTime, b.FileInfo.CreationTime);
-        }
+        private int SortByDateCreated(MPSScene a, MPSScene b) =>
+            SortDirection * DateTime.Compare(a.FileInfo.CreationTime, b.FileInfo.CreationTime);
 
-        private int SortByDateModified(MPSScene a, MPSScene b)
-        {
-            return SortDirection * DateTime.Compare(a.FileInfo.LastWriteTime, b.FileInfo.LastWriteTime);
-        }
+        private int SortByDateModified(MPSScene a, MPSScene b) =>
+            SortDirection * DateTime.Compare(a.FileInfo.LastWriteTime, b.FileInfo.LastWriteTime);
 
         private void UpdateSceneList()
         {
             ClearSceneList();
 
             if (!Directory.Exists(CurrentScenesDirectory))
-            {
                 Directory.CreateDirectory(CurrentScenesDirectory);
-            }
 
-            foreach (string filename in Directory.GetFiles(CurrentScenesDirectory))
-            {
-                if (Path.GetExtension(filename) == ".png") SceneList.Add(new MPSScene(filename));
-            }
+            foreach (var filename in Directory.GetFiles(CurrentScenesDirectory))
+                if (Path.GetExtension(filename) == ".png")
+                    SceneList.Add(new(filename));
 
             SortScenes(CurrentSortMode);
 
@@ -243,38 +266,48 @@ namespace MeidoPhotoStudio.Plugin
 
         private void UpdateDirectoryList()
         {
-            string baseDirectoryName = KankyoMode ? Constants.kankyoDirectory : Constants.sceneDirectory;
-            CurrentDirectoryList.Sort((a, b)
-                => a.Equals(baseDirectoryName, StringComparison.InvariantCultureIgnoreCase) 
-                    ? -1 : WindowsLogicalComparer.StrCmpLogicalW(a, b));
+            var baseDirectoryName = KankyoMode ? Constants.kankyoDirectory : Constants.sceneDirectory;
+
+            CurrentDirectoryList.Sort((a, b) =>
+                a.Equals(baseDirectoryName, StringComparison.InvariantCultureIgnoreCase)
+                    ? -1
+                    : WindowsLogicalComparer.StrCmpLogicalW(a, b));
         }
 
         private void ClearSceneList()
         {
-            foreach (MPSScene scene in SceneList) scene.Destroy();
+            foreach (var scene in SceneList)
+                scene.Destroy();
+
             SceneList.Clear();
         }
 
         private void QuickSaveScene()
         {
-            if (Busy) return;
-            
+            if (Busy)
+                return;
+
             var data = meidoPhotoStudio.SaveScene();
-            if (data == null) return;
+
+            if (data == null)
+                return;
 
             tempSceneData = data;
-            
+
             File.WriteAllBytes(TempScenePath, data);
         }
 
         private void QuickLoadScene()
         {
-            if (Busy) return;
+            if (Busy)
+                return;
 
             if (tempSceneData == null)
             {
-                if (File.Exists(TempScenePath)) tempSceneData = File.ReadAllBytes(TempScenePath);
-                else return;
+                if (File.Exists(TempScenePath))
+                    tempSceneData = File.ReadAllBytes(TempScenePath);
+                else
+                    return;
             }
 
             meidoPhotoStudio.LoadScene(tempSceneData);
@@ -284,24 +317,27 @@ namespace MeidoPhotoStudio.Plugin
         {
             Busy = true;
 
-            byte[] sceneData = meidoPhotoStudio.SaveScene(KankyoMode);
+            var sceneData = meidoPhotoStudio.SaveScene(KankyoMode);
 
             if (sceneData != null)
             {
-                string scenePrefix = KankyoMode ? "mpskankyo" : "mpsscene";
-                string fileName = $"{scenePrefix}{Utility.Timestamp}.png";
-                string savePath = Path.Combine(CurrentScenesDirectory, fileName);
+                var scenePrefix = KankyoMode ? "mpskankyo" : "mpsscene";
+                var fileName = $"{scenePrefix}{Utility.Timestamp}.png";
+                var savePath = Path.Combine(CurrentScenesDirectory, fileName);
 
-                Utility.ResizeToFit(screenshot, (int) sceneDimensions.x, (int) sceneDimensions.y);
+                Utility.ResizeToFit(screenshot, (int)sceneDimensions.x, (int)sceneDimensions.y);
 
                 try
                 {
-                    if (overwrite && CurrentScene?.FileInfo != null) savePath = CurrentScene.FileInfo.FullName;
-                    else overwrite = false;
+                    if (overwrite && CurrentScene?.FileInfo != null)
+                        savePath = CurrentScene.FileInfo.FullName;
+                    else
+                        overwrite = false;
 
-                    using (FileStream fileStream = File.Create(savePath))
+                    using (var fileStream = File.Create(savePath))
                     {
-                        byte[] encodedPng = screenshot.EncodeToPNG();
+                        var encodedPng = screenshot.EncodeToPNG();
+
                         fileStream.Write(encodedPng, 0, encodedPng.Length);
                         fileStream.Write(sceneData, 0, sceneData.Length);
                     }
@@ -318,13 +354,15 @@ namespace MeidoPhotoStudio.Plugin
                     Utility.LogError($"Failed to save scene to disk because {e.Message}\n{e.StackTrace}");
                     Object.DestroyImmediate(screenshot);
                     Busy = false;
+
                     return;
                 }
 
-                SceneList.Add(new MPSScene(savePath, screenshot));
+                SceneList.Add(new(savePath, screenshot));
                 SortScenes(CurrentSortMode);
             }
-            else Object.DestroyImmediate(screenshot);
+            else
+                Object.DestroyImmediate(screenshot);
 
             Busy = false;
         }

+ 20 - 12
src/MeidoPhotoStudio.Plugin/Managers/WindowManager.cs

@@ -1,12 +1,14 @@
 using System.Collections.Generic;
 using UnityEngine;
 
+using static MeidoPhotoStudio.Plugin.Constants;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using static Constants;
     public class WindowManager : IManager
     {
-        private readonly Dictionary<Window, BaseWindow> Windows = new Dictionary<Window, BaseWindow>();
+        private readonly Dictionary<Window, BaseWindow> Windows = new();
+
         public BaseWindow this[Window id]
         {
             get => Windows[id];
@@ -17,35 +19,41 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        public WindowManager() => InputManager.Register(MpsKey.ToggleUI, KeyCode.Tab, "Show/hide all UI");
+        public WindowManager() =>
+            InputManager.Register(MpsKey.ToggleUI, KeyCode.Tab, "Show/hide all UI");
 
         public void DrawWindow(BaseWindow window)
         {
-            if (window.Visible)
-            {
-                GUIStyle windowStyle = new GUIStyle(GUI.skin.box);
-                window.WindowRect = GUI.Window(window.windowID, window.WindowRect, window.GUIFunc, "", windowStyle);
-            }
+            if (!window.Visible)
+                return;
+
+            var windowStyle = new GUIStyle(GUI.skin.box);
+
+            window.WindowRect = GUI.Window(window.windowID, window.WindowRect, window.GUIFunc, "", windowStyle);
         }
 
         public void DrawWindows()
         {
-            foreach (BaseWindow window in Windows.Values) DrawWindow(window);
+            foreach (var window in Windows.Values)
+                DrawWindow(window);
         }
 
         public void Update()
         {
-            foreach (BaseWindow window in Windows.Values) window.Update();
+            foreach (var window in Windows.Values)
+                window.Update();
         }
 
         public void Activate()
         {
-            foreach (BaseWindow window in Windows.Values) window.Activate();
+            foreach (var window in Windows.Values)
+                window.Activate();
         }
 
         public void Deactivate()
         {
-            foreach (BaseWindow window in Windows.Values) window.Deactivate();
+            foreach (var window in Windows.Values)
+                window.Deactivate();
         }
     }
 }

+ 32 - 20
src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointFinger.cs

@@ -1,13 +1,16 @@
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointFinger : DragPointMeido
     {
-        private static readonly Color dragpointColour = new Color(0.1f, 0.4f, 0.95f, defaultAlpha);
-        private readonly TBody.IKCMO IK = new TBody.IKCMO();
+        private static readonly Color dragpointColour = new(0.1f, 0.4f, 0.95f, defaultAlpha);
+
+        private readonly TBody.IKCMO IK = new();
         private readonly Quaternion[] jointRotation = new Quaternion[2];
+
         private IKCtrlData ikCtrlData;
         private Transform[] ikChain;
         private bool baseFinger;
@@ -15,43 +18,42 @@ namespace MeidoPhotoStudio.Plugin
         public override void Set(Transform myObject)
         {
             base.Set(myObject);
-            string parentName = myObject.parent.name.Split(' ')[2];
+
+            var parentName = myObject.parent.name.Split(' ')[2];
+
             // Base finger names have the form 'FingerN' or 'ToeN' where N is a natural number
-            baseFinger = (parentName.Length == 7) || (parentName.Length == 4);
+            baseFinger = parentName.Length is 7 or 4;
             ikChain = new Transform[2] {
                 myObject.parent,
                 myObject
             };
-            ikCtrlData = IkCtrlData;
-        }
 
-        private void SetRotation(int joint)
-        {
-            Vector3 rotation = jointRotation[joint].eulerAngles;
-            rotation.z = ikChain[joint].localEulerAngles.z;
-            ikChain[joint].localRotation = Quaternion.Euler(rotation);
+            ikCtrlData = IkCtrlData;
         }
 
         protected override void ApplyDragType()
         {
-            if (baseFinger && CurrentDragType == DragType.RotLocalY) ApplyProperties(true, true, false);
-            else if (CurrentDragType == DragType.MoveXZ) ApplyProperties(true, true, false);
-            else ApplyProperties(false, false, false);
+            if (baseFinger && CurrentDragType == DragType.RotLocalY)
+                ApplyProperties(true, true, false);
+            else if (CurrentDragType == DragType.MoveXZ)
+                ApplyProperties(true, true, false);
+            else
+                ApplyProperties(false, false, false);
+
             ApplyColour(dragpointColour);
         }
 
-        protected override void UpdateDragType()
-        {
+        protected override void UpdateDragType() =>
             CurrentDragType = Input.GetKey(MpsKey.DragFinger)
                 ? Input.Shift
                     ? DragType.RotLocalY
                     : DragType.MoveXZ
                 : DragType.None;
-        }
 
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
+
             jointRotation[jointUpper] = ikChain[jointUpper].localRotation;
             jointRotation[jointMiddle] = ikChain[jointMiddle].localRotation;
             InitializeIK(IK, ikChain[jointUpper], ikChain[jointUpper], ikChain[jointMiddle]);
@@ -59,11 +61,13 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void Drag()
         {
-            if (isPlaying) meido.Stop = true;
+            if (isPlaying)
+                meido.Stop = true;
 
             if (CurrentDragType == DragType.MoveXZ)
             {
                 Porc(IK, ikCtrlData, ikChain[jointUpper], ikChain[jointUpper], ikChain[jointMiddle]);
+
                 if (!baseFinger)
                 {
                     SetRotation(jointUpper);
@@ -77,11 +81,19 @@ namespace MeidoPhotoStudio.Plugin
             }
             else if (CurrentDragType == DragType.RotLocalY)
             {
-                Vector3 mouseDelta = MouseDelta();
+                var mouseDelta = MouseDelta();
 
                 ikChain[jointUpper].localRotation = jointRotation[jointUpper];
                 ikChain[jointUpper].Rotate(Vector3.right * (mouseDelta.x / 1.5f));
             }
         }
+
+        private void SetRotation(int joint)
+        {
+            var rotation = jointRotation[joint].eulerAngles;
+
+            rotation.z = ikChain[joint].localEulerAngles.z;
+            ikChain[joint].localRotation = Quaternion.Euler(rotation);
+        }
     }
 }

+ 26 - 30
src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointHead.cs

@@ -1,57 +1,56 @@
 using System;
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointHead : DragPointMeido
     {
+        public event EventHandler Select;
+
         private Quaternion headRotation;
         private Vector3 eyeRotationL;
         private Vector3 eyeRotationR;
-        public event EventHandler Select;
+
         public bool IsIK { get; set; }
 
         protected override void ApplyDragType()
         {
             if (IsBone)
             {
-                DragType current = CurrentDragType;
-                bool active = current == DragType.MoveY || current == DragType.MoveXZ || current == DragType.Select;
+                var current = CurrentDragType;
+                var active = current is DragType.MoveY or DragType.MoveXZ or DragType.Select;
+
                 ApplyProperties(active, false, false);
             }
-            else ApplyProperties(CurrentDragType != DragType.None, false, false);
+            else
+                ApplyProperties(CurrentDragType != DragType.None, false, false);
         }
 
         protected override void UpdateDragType()
         {
-            bool shift = Input.Shift;
-            bool alt = Input.Alt;
+            var shift = Input.Shift;
+            var alt = Input.Alt;
+
             if (alt && Input.Control)
-            {
                 // eyes
                 CurrentDragType = shift ? DragType.MoveY : DragType.MoveXZ;
-            }
             else if (alt)
-            {
                 // head
                 CurrentDragType = shift ? DragType.RotLocalY : DragType.RotLocalXZ;
-            }
             else if (Input.GetKey(MpsKey.DragSelect))
-            {
                 CurrentDragType = DragType.Select;
-            }
             else
-            {
                 CurrentDragType = DragType.None;
-            }
         }
 
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
 
-            if (CurrentDragType == DragType.Select) Select?.Invoke(this, EventArgs.Empty);
+            if (CurrentDragType == DragType.Select)
+                Select?.Invoke(this, EventArgs.Empty);
 
             headRotation = MyObject.rotation;
 
@@ -61,27 +60,24 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void OnDoubleClick()
         {
-            if (CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.MoveY)
+            if (CurrentDragType is DragType.MoveXZ or DragType.MoveY)
             {
                 meido.Body.quaDefEyeL = meido.DefaultEyeRotL;
                 meido.Body.quaDefEyeR = meido.DefaultEyeRotR;
             }
-            else if (CurrentDragType == DragType.RotLocalY || CurrentDragType == DragType.RotLocalXZ)
-            {
+            else if (CurrentDragType is DragType.RotLocalY or DragType.RotLocalXZ)
                 meido.FreeLook = !meido.FreeLook;
-            }
         }
 
         protected override void Drag()
         {
-            if (IsIK || CurrentDragType == DragType.Select) return;
+            if (IsIK || CurrentDragType == DragType.Select)
+                return;
 
             if (!(CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.MoveY) && isPlaying)
-            {
                 meido.Stop = true;
-            }
 
-            Vector3 mouseDelta = MouseDelta();
+            var mouseDelta = MouseDelta();
 
             if (CurrentDragType == DragType.RotLocalXZ)
             {
@@ -96,15 +92,15 @@ namespace MeidoPhotoStudio.Plugin
                 MyObject.Rotate(Vector3.right * mouseDelta.x / 3f);
             }
 
-            if (CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.MoveY)
+            if (CurrentDragType is DragType.MoveXZ or DragType.MoveY)
             {
-                int inv = CurrentDragType == DragType.MoveY ? -1 : 1;
+                var inv = CurrentDragType == DragType.MoveY ? -1 : 1;
 
-                meido.Body.quaDefEyeL.eulerAngles = new Vector3(
-                    eyeRotationL.x, eyeRotationL.y - (mouseDelta.x / 10f), eyeRotationL.z - (mouseDelta.y / 10f)
+                meido.Body.quaDefEyeL.eulerAngles = new(
+                    eyeRotationL.x, eyeRotationL.y - mouseDelta.x / 10f, eyeRotationL.z - mouseDelta.y / 10f
                 );
-                meido.Body.quaDefEyeR.eulerAngles = new Vector3(
-                    eyeRotationR.x, eyeRotationR.y + (inv * mouseDelta.x / 10f), eyeRotationR.z + (mouseDelta.y / 10f)
+                meido.Body.quaDefEyeR.eulerAngles = new(
+                    eyeRotationR.x, eyeRotationR.y + inv * mouseDelta.x / 10f, eyeRotationR.z + mouseDelta.y / 10f
                 );
             }
         }

+ 20 - 12
src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointPelvis.cs

@@ -1,25 +1,31 @@
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointPelvis : DragPointMeido
     {
         private Quaternion pelvisRotation;
 
         protected override void ApplyDragType()
         {
-            if (CurrentDragType == DragType.Ignore) ApplyProperties();
-            else if (IsBone) ApplyProperties(false, false, false);
-            else ApplyProperties(CurrentDragType != DragType.None, false, false);
+            if (CurrentDragType == DragType.Ignore)
+                ApplyProperties();
+            else if (IsBone)
+                ApplyProperties(false, false, false);
+            else
+                ApplyProperties(CurrentDragType != DragType.None, false, false);
         }
 
-        protected override void UpdateDragType()
-        {
+        protected override void UpdateDragType() =>
             CurrentDragType = Input.Alt && !Input.Control
-                ? Input.Shift ? DragType.RotLocalY : DragType.RotLocalXZ
-                : OtherDragType() ? DragType.Ignore : DragType.None;
-        }
+                ? Input.Shift
+                    ? DragType.RotLocalY
+                    : DragType.RotLocalXZ
+                : OtherDragType()
+                    ? DragType.Ignore
+                    : DragType.None;
 
         protected override void OnMouseDown()
         {
@@ -29,11 +35,13 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void Drag()
         {
-            if (CurrentDragType == DragType.None) return;
+            if (CurrentDragType == DragType.None)
+                return;
 
-            if (isPlaying) meido.Stop = true;
+            if (isPlaying)
+                meido.Stop = true;
 
-            Vector3 mouseDelta = MouseDelta();
+            var mouseDelta = MouseDelta();
 
             if (CurrentDragType == DragType.RotLocalXZ)
             {

+ 32 - 26
src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointSpine.cs

@@ -1,8 +1,9 @@
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointSpine : DragPointMeido
     {
         private Quaternion spineRotation;
@@ -13,12 +14,15 @@ namespace MeidoPhotoStudio.Plugin
         public override void AddGizmo(float scale = 0.25f, CustomGizmo.GizmoMode mode = CustomGizmo.GizmoMode.Local)
         {
             base.AddGizmo(scale, mode);
-            if (isHead) Gizmo.GizmoDrag += (s, a) => meido.HeadToCam = false;
+
+            if (isHead)
+                Gizmo.GizmoDrag += (s, a) => meido.HeadToCam = false;
         }
 
         public override void Set(Transform myObject)
         {
             base.Set(myObject);
+
             isHip = myObject.name == "Bip01";
             isThigh = myObject.name.EndsWith("Thigh");
             isHead = myObject.name.EndsWith("Head");
@@ -26,62 +30,62 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void ApplyDragType()
         {
-            DragType current = CurrentDragType;
+            var current = CurrentDragType;
+
             if (IsBone && current != DragType.Ignore)
             {
-                if (!isHead && current == DragType.RotLocalXZ) ApplyProperties(false, false, isThigh);
-                else if (!isThigh && (current == DragType.MoveY)) ApplyProperties(isHip, isHip, !isHip);
-                else if (!isThigh && !isHead && (current == DragType.RotLocalY)) ApplyProperties(!isHip, !isHip, isHip);
-                else ApplyProperties(!isThigh, !isThigh, false);
+                if (!isHead && current == DragType.RotLocalXZ)
+                    ApplyProperties(false, false, isThigh);
+                else if (!isThigh && current == DragType.MoveY)
+                    ApplyProperties(isHip, isHip, !isHip);
+                else if (!isThigh && !isHead && current == DragType.RotLocalY)
+                    ApplyProperties(!isHip, !isHip, isHip);
+                else
+                    ApplyProperties(!isThigh, !isThigh, false);
             }
-            else ApplyProperties(false, false, false);
+            else
+                ApplyProperties(false, false, false);
         }
 
         protected override void UpdateDragType()
         {
-            bool shift = Input.Shift;
-            bool alt = Input.Alt;
+            var shift = Input.Shift;
+            var alt = Input.Alt;
 
-            if (OtherDragType()) CurrentDragType = DragType.Ignore;
+            if (OtherDragType())
+                CurrentDragType = DragType.Ignore;
             else if (isThigh && !Input.Control && alt && shift)
-            {
                 // gizmo thigh rotation
                 CurrentDragType = DragType.RotLocalXZ;
-            }
             else if (alt)
-            {
                 CurrentDragType = DragType.Ignore;
-            }
             else if (shift)
-            {
                 CurrentDragType = DragType.RotLocalY;
-            }
             else if (Input.Control)
-            {
                 // hip y transform and spine gizmo rotation
                 CurrentDragType = DragType.MoveY;
-            }
             else
-            {
                 CurrentDragType = DragType.None;
-            }
         }
 
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
+
             spineRotation = MyObject.rotation;
         }
 
         protected override void Drag()
         {
-            if (isPlaying) meido.Stop = true;
+            if (isPlaying)
+                meido.Stop = true;
 
-            Vector3 mouseDelta = MouseDelta();
+            var mouseDelta = MouseDelta();
 
             if (CurrentDragType == DragType.None)
             {
-                if (isHead) meido.HeadToCam = false;
+                if (isHead)
+                    meido.HeadToCam = false;
 
                 MyObject.rotation = spineRotation;
                 MyObject.Rotate(camera.transform.forward, -mouseDelta.x / 4.5f, Space.World);
@@ -90,7 +94,8 @@ namespace MeidoPhotoStudio.Plugin
 
             if (CurrentDragType == DragType.RotLocalY)
             {
-                if (isHead) meido.HeadToCam = false;
+                if (isHead)
+                    meido.HeadToCam = false;
 
                 MyObject.rotation = spineRotation;
                 MyObject.Rotate(Vector3.right * mouseDelta.x / 4f);
@@ -98,7 +103,8 @@ namespace MeidoPhotoStudio.Plugin
 
             if (CurrentDragType == DragType.MoveY)
             {
-                Vector3 cursorPosition = CursorPosition();
+                var cursorPosition = CursorPosition();
+
                 MyObject.position = new Vector3(MyObject.position.x, cursorPosition.y, MyObject.position.z);
             }
         }

+ 30 - 23
src/MeidoPhotoStudio.Plugin/Meido/IK/DragPointTorso.cs

@@ -1,60 +1,70 @@
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointTorso : DragPointMeido
     {
         private static readonly float[] blah = new[] { 0.03f, 0.1f, 0.09f, 0.07f };
         private static readonly float[] something = new[] { 0.08f, 0.15f };
+
         private readonly Quaternion[] spineRotation = new Quaternion[4];
         private readonly Transform[] spine = new Transform[4];
 
         public override void Set(Transform myObject)
         {
             base.Set(myObject);
-            Transform spine = myObject;
-            for (int i = 0; i < this.spine.Length; i++)
+
+            var spine = myObject;
+
+            for (var i = 0; i < this.spine.Length; i++)
             {
                 this.spine[i] = spine;
+
                 spine = spine.parent;
             }
         }
 
         protected override void ApplyDragType()
         {
-            if (CurrentDragType == DragType.Ignore) ApplyProperties();
-            else if (IsBone) ApplyProperties(false, false, false);
-            else ApplyProperties(CurrentDragType != DragType.None, false, false);
+            if (CurrentDragType == DragType.Ignore)
+                ApplyProperties();
+            else if (IsBone)
+                ApplyProperties(false, false, false);
+            else
+                ApplyProperties(CurrentDragType != DragType.None, false, false);
         }
 
-        protected override void UpdateDragType()
-        {
+        protected override void UpdateDragType() =>
             CurrentDragType = Input.Alt && !Input.Control
-                ? Input.Shift ? DragType.RotLocalY : DragType.RotLocalXZ
-                : OtherDragType() ? DragType.Ignore : DragType.None;
-        }
+                ? Input.Shift
+                    ? DragType.RotLocalY
+                    : DragType.RotLocalXZ
+                : OtherDragType()
+                    ? DragType.Ignore
+                    : DragType.None;
 
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
-            for (int i = 0; i < spine.Length; i++)
-            {
+
+            for (var i = 0; i < spine.Length; i++)
                 spineRotation[i] = spine[i].localRotation;
-            }
         }
 
         protected override void Drag()
         {
-            if (CurrentDragType == DragType.None) return;
+            if (CurrentDragType == DragType.None)
+                return;
 
-            if (isPlaying) meido.Stop = true;
+            if (isPlaying)
+                meido.Stop = true;
 
-            Vector3 mouseDelta = MouseDelta();
+            var mouseDelta = MouseDelta();
 
             if (CurrentDragType == DragType.RotLocalXZ)
-            {
-                for (int i = 0; i < spine.Length; i++)
+                for (var i = 0; i < spine.Length; i++)
                 {
                     spine[i].localRotation = spineRotation[i];
                     spine[i].Rotate(
@@ -62,16 +72,13 @@ namespace MeidoPhotoStudio.Plugin
                     );
                     spine[i].Rotate(camera.transform.right, mouseDelta.y * blah[i], Space.World);
                 }
-            }
 
             if (CurrentDragType == DragType.RotLocalY)
-            {
-                for (int i = 0; i < spine.Length; i++)
+                for (var i = 0; i < spine.Length; i++)
                 {
                     spine[i].localRotation = spineRotation[i];
                     spine[i].Rotate(Vector3.right * (mouseDelta.x / 1.5f * something[i / 2]));
                 }
-            }
         }
     }
 }

+ 8 - 6
src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointChain.cs

@@ -4,8 +4,9 @@ namespace MeidoPhotoStudio.Plugin
 {
     public abstract class DragPointChain : DragPointMeido
     {
-        protected readonly TBody.IKCMO IK = new TBody.IKCMO();
+        protected readonly TBody.IKCMO IK = new();
         protected readonly Quaternion[] jointRotation = new Quaternion[3];
+
         protected IKCtrlData ikCtrlData;
         protected Transform[] ikChain;
 
@@ -22,11 +23,6 @@ namespace MeidoPhotoStudio.Plugin
             ikCtrlData = IkCtrlData;
         }
 
-        protected void InitializeRotation()
-        {
-            for (int i = 0; i < jointRotation.Length; i++) jointRotation[i] = ikChain[i].localRotation;
-        }
-
         protected override void OnMouseDown()
         {
             base.OnMouseDown();
@@ -35,5 +31,11 @@ namespace MeidoPhotoStudio.Plugin
 
             InitializeIK(IK, ikChain[jointUpper], ikChain[jointMiddle], ikChain[jointLower]);
         }
+
+        protected void InitializeRotation()
+        {
+            for (var i = 0; i < jointRotation.Length; i++)
+                jointRotation[i] = ikChain[i].localRotation;
+        }
     }
 }

+ 52 - 28
src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointLimb.cs

@@ -1,19 +1,22 @@
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointLimb : DragPointChain
     {
         private int foot = 1;
         private bool isLower;
         private bool isMiddle;
         private bool isUpper;
+
         public override bool IsBone
         {
             set
             {
                 base.IsBone = value;
+
                 BaseScale = isBone ? boneScale : OriginalScale;
             }
         }
@@ -22,80 +25,101 @@ namespace MeidoPhotoStudio.Plugin
         {
             base.Set(myObject);
 
-            string name = myObject.name;
+            var name = myObject.name;
 
             foot = name.EndsWith("Foot") ? -1 : 1;
             isLower = name.EndsWith("Hand") || foot == -1;
             isMiddle = name.EndsWith("Calf") || name.EndsWith("Forearm");
             isUpper = !isMiddle && !isLower;
 
-            if (isLower) ikChain[0] = ikChain[0].parent;
+            if (isLower)
+                ikChain[0] = ikChain[0].parent;
         }
 
         protected override void ApplyDragType()
         {
-            DragType current = CurrentDragType;
-            bool isBone = IsBone;
-            if (CurrentDragType == DragType.Ignore) ApplyProperties();
+            var current = CurrentDragType;
+            var isBone = IsBone;
+
+            if (CurrentDragType == DragType.Ignore)
+                ApplyProperties();
             else if (current == DragType.RotLocalXZ)
             {
-                if (isLower) ApplyProperties(!isBone, false, isBone);
-                else ApplyProperties();
+                if (isLower)
+                    ApplyProperties(!isBone, false, isBone);
+                else
+                    ApplyProperties();
             }
             else if (current == DragType.RotLocalY)
             {
-                if (isLower || isMiddle) ApplyProperties(!isBone, false, false);
-                else if (isUpper) ApplyProperties(false, false, isBone);
-                else ApplyProperties();
+                if (isLower || isMiddle)
+                    ApplyProperties(!isBone, false, false);
+                else if (isUpper)
+                    ApplyProperties(false, false, isBone);
+                else
+                    ApplyProperties();
             }
             else if (current == DragType.RotY)
             {
-                if (isMiddle) ApplyProperties(false, false, isBone);
-                else ApplyProperties();
+                if (isMiddle)
+                    ApplyProperties(false, false, isBone);
+                else
+                    ApplyProperties();
             }
             else if (current == DragType.MoveXZ)
             {
-                if (isLower) ApplyProperties(true, isBone, false);
-                else ApplyProperties();
+                if (isLower)
+                    ApplyProperties(true, isBone, false);
+                else
+                    ApplyProperties();
             }
-            else ApplyProperties(true, isBone, false);
+            else
+                ApplyProperties(true, isBone, false);
         }
 
         protected override void UpdateDragType()
         {
-            bool control = Input.Control;
-            bool alt = Input.Alt;
+            var control = Input.Control;
+            var alt = Input.Alt;
+
             // Check for DragMove so that hand dragpoint is not in the way
-            if (OtherDragType()) CurrentDragType = DragType.Ignore;
+            if (OtherDragType())
+                CurrentDragType = DragType.Ignore;
             else if (control && !Input.GetKey(MpsKey.DragMove))
             {
-                if (alt) CurrentDragType = DragType.RotY;
-                else CurrentDragType = DragType.MoveXZ;
+                if (alt)
+                    CurrentDragType = DragType.RotY;
+                else
+                    CurrentDragType = DragType.MoveXZ;
             }
-            else if (alt) CurrentDragType = Input.Shift ? DragType.RotLocalY : DragType.RotLocalXZ;
-            else CurrentDragType = Input.Shift ? DragType.Ignore : DragType.None;
+            else if (alt)
+                CurrentDragType = Input.Shift ? DragType.RotLocalY : DragType.RotLocalXZ;
+            else
+                CurrentDragType = Input.Shift ? DragType.Ignore : DragType.None;
         }
 
         protected override void Drag()
         {
-            if (isPlaying) meido.Stop = true;
+            if (isPlaying)
+                meido.Stop = true;
 
-            bool altRotation = CurrentDragType == DragType.MoveXZ || CurrentDragType == DragType.RotY;
+            var altRotation = CurrentDragType is DragType.MoveXZ or DragType.RotY;
 
             if (CurrentDragType == DragType.None || altRotation)
             {
-                int upperJoint = altRotation ? jointMiddle : jointUpper;
+                var upperJoint = altRotation ? jointMiddle : jointUpper;
 
                 Porc(IK, ikCtrlData, ikChain[upperJoint], ikChain[jointMiddle], ikChain[jointLower]);
 
                 InitializeRotation();
             }
 
-            Vector3 mouseDelta = MouseDelta();
+            var mouseDelta = MouseDelta();
 
             if (CurrentDragType == DragType.RotLocalY)
             {
-                int joint = isMiddle ? jointUpper : jointLower;
+                var joint = isMiddle ? jointUpper : jointLower;
+
                 ikChain[joint].localRotation = jointRotation[joint];
                 ikChain[joint].Rotate(Vector3.right * (-mouseDelta.x / 1.5f));
             }

+ 19 - 8
src/MeidoPhotoStudio.Plugin/Meido/IK/IK Chain/DragPointMune.cs

@@ -1,8 +1,9 @@
 using UnityEngine;
 
+using Input = MeidoPhotoStudio.Plugin.InputManager;
+
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     public class DragPointMune : DragPointChain
     {
         private bool isMuneL;
@@ -11,11 +12,15 @@ namespace MeidoPhotoStudio.Plugin
         public override void Set(Transform myObject)
         {
             base.Set(myObject);
+
             isMuneL = myObject.name[5] == 'L'; // Mune_L_Sub
-            if (isMuneL) inv *= -1;
+
+            if (isMuneL)
+                inv *= -1;
         }
 
-        protected override void ApplyDragType() => ApplyProperties(CurrentDragType != DragType.None, false, false);
+        protected override void ApplyDragType() =>
+            ApplyProperties(CurrentDragType != DragType.None, false, false);
 
         protected override void OnMouseDown()
         {
@@ -26,18 +31,22 @@ namespace MeidoPhotoStudio.Plugin
 
         protected override void OnDoubleClick()
         {
-            if (CurrentDragType != DragType.None) meido.SetMune(true, isMuneL);
+            if (CurrentDragType != DragType.None)
+                meido.SetMune(true, isMuneL);
         }
 
         protected override void UpdateDragType()
         {
-            if (Input.Control && Input.Alt) CurrentDragType = Input.Shift ? DragType.RotLocalY : DragType.RotLocalXZ;
-            else CurrentDragType = DragType.None;
+            if (Input.Control && Input.Alt)
+                CurrentDragType = Input.Shift ? DragType.RotLocalY : DragType.RotLocalXZ;
+            else
+                CurrentDragType = DragType.None;
         }
 
         protected override void Drag()
         {
-            if (isPlaying) meido.Stop = true;
+            if (isPlaying)
+                meido.Stop = true;
 
             if (CurrentDragType == DragType.RotLocalXZ)
             {
@@ -47,8 +56,10 @@ namespace MeidoPhotoStudio.Plugin
 
             if (CurrentDragType == DragType.RotLocalY)
             {
-                Vector3 mouseDelta = MouseDelta();
+                var mouseDelta = MouseDelta();
+
                 ikChain[jointLower].localRotation = jointRotation[jointLower];
+                // TODO: Reorder operands for better performance
                 ikChain[jointLower].Rotate(Vector3.up * (-mouseDelta.x / 1.5f) * inv);
                 ikChain[jointLower].Rotate(Vector3.forward * (mouseDelta.y / 1.5f) * inv);
             }

Fichier diff supprimé car celui-ci est trop grand
+ 376 - 248
src/MeidoPhotoStudio.Plugin/Meido/Meido.cs


+ 280 - 232
src/MeidoPhotoStudio.Plugin/Meido/MeidoDragPointManager.cs

@@ -1,6 +1,6 @@
 using System;
-using System.IO;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
 using UnityEngine;
 
@@ -44,7 +44,8 @@ namespace MeidoPhotoStudio.Plugin
             Toe1R, Toe11R, Toe1NubR,
             Toe2R, Toe21R, Toe2NubR
         }
-        private static readonly Dictionary<AttachPoint, Bone> PointToBone = new Dictionary<AttachPoint, Bone>()
+
+        private static readonly Dictionary<AttachPoint, Bone> PointToBone = new()
         {
             [AttachPoint.Head] = Bone.Head,
             [AttachPoint.Neck] = Bone.HeadNub,
@@ -68,11 +69,17 @@ namespace MeidoPhotoStudio.Plugin
             [AttachPoint.Spine0a] = Bone.Spine0a,
             [AttachPoint.Spine0] = Bone.Spine
         };
+
         private static readonly Bone[] SpineBones =
         {
             Bone.Neck, Bone.Spine, Bone.Spine0a, Bone.Spine1, Bone.Spine1a, Bone.Hip, Bone.ThighL, Bone.ThighR
         };
+
         private static bool cubeActive;
+        private static bool cubeSmall;
+        private static EventHandler CubeActiveChange;
+        private static EventHandler CubeSmallChange;
+
         public static bool CubeActive
         {
             get => cubeActive;
@@ -85,7 +92,7 @@ namespace MeidoPhotoStudio.Plugin
                 }
             }
         }
-        private static bool cubeSmall;
+
         public static bool CubeSmall
         {
             get => cubeSmall;
@@ -98,51 +105,119 @@ namespace MeidoPhotoStudio.Plugin
                 }
             }
         }
-        private static EventHandler CubeActiveChange;
-        private static EventHandler CubeSmallChange;
+
         private readonly Meido meido;
-        private readonly Dictionary<Bone, DragPointMeido> DragPoints = new Dictionary<Bone, DragPointMeido>();
-        private Dictionary<Bone, Transform> BoneTransform = new Dictionary<Bone, Transform>();
+        private readonly Dictionary<Bone, DragPointMeido> DragPoints = new();
+
+        public event EventHandler<MeidoUpdateEventArgs> SelectMaid;
+
+        private Dictionary<Bone, Transform> BoneTransform = new();
         private DragPointBody dragBody;
         private DragPointBody dragCube;
         private bool initialized;
-        public event EventHandler<MeidoUpdateEventArgs> SelectMaid;
         private bool isBone;
+        private bool active = true;
+
         public bool IsBone
         {
             get => isBone;
             set
             {
-                if (!initialized) return;
-                if (isBone != value)
-                {
-                    isBone = value;
-                    foreach (DragPointMeido dragPoint in DragPoints.Values) dragPoint.IsBone = isBone;
-                    foreach (Bone bone in SpineBones) DragPoints[bone].gameObject.SetActive(isBone);
-                }
+                if (!initialized)
+                    return;
+
+                if (isBone == value)
+                    return;
+
+                isBone = value;
+
+                foreach (var dragPoint in DragPoints.Values)
+                    dragPoint.IsBone = isBone;
+
+                foreach (var bone in SpineBones)
+                    DragPoints[bone].gameObject.SetActive(isBone);
             }
         }
-        private bool active = true;
+
         public bool Active
         {
             get => active;
             set
             {
-                if (!initialized) return;
-                if (active != value)
-                {
-                    active = value;
-                    foreach (DragPointMeido dragPoint in DragPoints.Values) dragPoint.gameObject.SetActive(active);
-                    foreach (Bone bone in SpineBones) DragPoints[bone].gameObject.SetActive(active && IsBone);
-                    DragPointHead head = (DragPointHead)DragPoints[Bone.Head];
-                    head.gameObject.SetActive(true);
-                    head.IsIK = !active;
-                    dragBody.IsIK = !active;
-                }
+                if (!initialized)
+                    return;
+
+                if (active == value)
+                    return;
+
+                active = value;
+
+                foreach (var dragPoint in DragPoints.Values)
+                    dragPoint.gameObject.SetActive(active);
+
+                foreach (var bone in SpineBones)
+                    DragPoints[bone].gameObject.SetActive(active && IsBone);
+
+                var head = (DragPointHead)DragPoints[Bone.Head];
+
+                head.gameObject.SetActive(true);
+                head.IsIK = !active;
+                dragBody.IsIK = !active;
+            }
+        }
+
+        private static DragPointLimb[] MakeArmChain(Transform lower, Meido meido)
+        {
+            var limbDragPointSize = Vector3.one * 0.12f;
+
+            var realLower = CMT.SearchObjName(meido.Body.goSlot[0].obj_tr, lower.name, false);
+
+            var dragPoints = new DragPointLimb[3];
+
+            for (var i = dragPoints.Length - 1; i >= 0; i--)
+            {
+                var joint = lower;
+                var positionJoint = realLower;
+
+                dragPoints[i] = DragPoint.Make<DragPointLimb>(PrimitiveType.Sphere, limbDragPointSize);
+                dragPoints[i].Initialize(meido, () => positionJoint.position, () => Vector3.zero);
+                dragPoints[i].Set(joint);
+                dragPoints[i].AddGizmo();
+                dragPoints[i].Gizmo.SetAlternateTarget(positionJoint);
+
+                lower = lower.parent;
+                realLower = realLower.parent;
             }
+
+            return dragPoints;
         }
 
-        public MeidoDragPointManager(Meido meido) => this.meido = meido;
+        private static DragPointFinger[] MakeFingerChain(Transform lower, Meido meido)
+        {
+            var fingerDragPointSize = Vector3.one * 0.01f;
+
+            var dragPoints = new DragPointFinger[3];
+
+            var realLower = CMT.SearchObjName(meido.Body.goSlot[0].obj_tr, lower.parent.name, false);
+
+            for (var i = dragPoints.Length - 1; i >= 0; i--)
+            {
+                var joint = lower;
+                var positionJoint = realLower;
+
+                dragPoints[i] = DragPoint.Make<DragPointFinger>(PrimitiveType.Sphere, fingerDragPointSize);
+                dragPoints[i].Initialize(meido, () => positionJoint.position, () => Vector3.zero);
+                dragPoints[i].Set(joint);
+
+                lower = lower.parent;
+                realLower = realLower.parent;
+            }
+
+            return dragPoints;
+        }
+
+        public MeidoDragPointManager(Meido meido) =>
+            this.meido = meido;
 
         public void Deserialize(BinaryReader reader)
         {
@@ -153,7 +228,8 @@ namespace MeidoPhotoStudio.Plugin
             for (var bone = Bone.Finger0L; bone <= upperBone; ++bone)
                 BoneTransform[bone].localRotation = reader.ReadQuaternion();
 
-            var bones = sixtyFourFlag ? new[]
+            var bones = sixtyFourFlag
+                ? new[]
                 {
                     Bone.Pelvis, Bone.Spine, Bone.Spine0a, Bone.Spine1, Bone.Spine1a, Bone.Neck, Bone.UpperArmL,
                     Bone.UpperArmR, Bone.ForearmL, Bone.ForearmR, Bone.ThighL, Bone.ThighR, Bone.CalfL, Bone.CalfR,
@@ -206,42 +282,27 @@ namespace MeidoPhotoStudio.Plugin
             GameMain.Instance.StartCoroutine(ApplyHipPosition(reader.ReadVector3()));
         }
 
-        /*
-            Somebody smarter than me please help me find a way to do this better T_T
-            inb4 for loop.
-         */
-        private System.Collections.IEnumerator ApplyHipPosition(Vector3 hipPosition)
-        {
-            BoneTransform[Bone.Hip].position = hipPosition;
-            yield return new WaitForEndOfFrame();
-            BoneTransform[Bone.Hip].position = hipPosition;
-            yield return new WaitForEndOfFrame();
-            BoneTransform[Bone.Hip].position = hipPosition;
-        }
-
-        public Transform GetAttachPointTransform(AttachPoint point)
-            => point == AttachPoint.None ? null : BoneTransform[PointToBone[point]];
-
         public void Flip()
         {
             meido.Stop = true;
-            Bone[] single = new[] { Bone.Pelvis, Bone.Spine, Bone.Spine0a, Bone.Spine1, Bone.Spine1a, Bone.Neck };
-            Bone[] pair = new[] {
+
+            var single = new[] { Bone.Pelvis, Bone.Spine, Bone.Spine0a, Bone.Spine1, Bone.Spine1a, Bone.Neck };
+            var pair = new[] {
                 Bone.ClavicleL, Bone.ClavicleR, Bone.UpperArmL, Bone.UpperArmR, Bone.ForearmL, Bone.ForearmR,
                 Bone.ThighL, Bone.ThighR, Bone.CalfL, Bone.CalfR, Bone.HandL, Bone.HandR, Bone.FootL, Bone.FootR
             };
 
-            List<Vector3> singleRotations = single.Select(bone => BoneTransform[bone].eulerAngles).ToList();
-            List<Vector3> pairRotations = pair.Select(bone => BoneTransform[bone].eulerAngles).ToList();
+            var singleRotations = single.Select(bone => BoneTransform[bone].eulerAngles).ToList();
+            var pairRotations = pair.Select(bone => BoneTransform[bone].eulerAngles).ToList();
 
-            Transform hip = BoneTransform[Bone.Hip];
-            Vector3 vecHip = hip.eulerAngles;
+            var hip = BoneTransform[Bone.Hip];
+            var vecHip = hip.eulerAngles;
 
-            Transform hipL = meido.Maid.body0.GetBone("Hip_L");
-            Vector3 vecHipL = hipL.eulerAngles;
+            var hipL = meido.Maid.body0.GetBone("Hip_L");
+            var vecHipL = hipL.eulerAngles;
 
-            Transform hipR = meido.Maid.body0.GetBone("Hip_R");
-            Vector3 vecHipR = hipR.eulerAngles;
+            var hipR = meido.Maid.body0.GetBone("Hip_R");
+            var vecHipR = hipR.eulerAngles;
 
             hip.rotation = Quaternion.Euler(
                 360f - (vecHip.x + 270f) - 270f, 360f - (vecHip.y + 90f) - 90f, 360f - vecHip.z
@@ -250,120 +311,82 @@ namespace MeidoPhotoStudio.Plugin
             hipL.rotation = FlipRotation(vecHipR);
             hipR.rotation = FlipRotation(vecHipL);
 
-            for (int i = 0; i < single.Length; i++)
+            for (var i = 0; i < single.Length; i++)
             {
-                Bone bone = single[i];
+                var bone = single[i];
+
                 BoneTransform[bone].rotation = FlipRotation(singleRotations[i]);
             }
 
-            for (int i = 0; i < pair.Length; i += 2)
+            for (var i = 0; i < pair.Length; i += 2)
             {
-                Bone boneA = pair[i];
-                Bone boneB = pair[i + 1];
+                var boneA = pair[i];
+                var boneB = pair[i + 1];
+
                 BoneTransform[boneA].rotation = FlipRotation(pairRotations[i + 1]);
                 BoneTransform[boneB].rotation = FlipRotation(pairRotations[i]);
             }
 
-            byte[] leftHand = SerializeHand(right: false);
-            byte[] rightHand = SerializeHand(right: true);
+            var leftHand = SerializeHand(right: false);
+            var rightHand = SerializeHand(right: true);
+
             DeserializeHand(leftHand, right: true, true);
             DeserializeHand(rightHand, right: false, true);
+
             leftHand = SerializeFoot(right: false);
             rightHand = SerializeFoot(right: true);
+
             DeserializeFoot(leftHand, right: true, true);
             DeserializeFoot(rightHand, right: false, true);
         }
 
-        private Quaternion FlipRotation(Vector3 rotation)
-        {
-            return Quaternion.Euler(360f - rotation.x, 360f - (rotation.y + 90f) - 90f, rotation.z);
-        }
+        public Transform GetAttachPointTransform(AttachPoint point) =>
+            point == AttachPoint.None ? null : BoneTransform[PointToBone[point]];
 
         public byte[] SerializeHand(bool right)
         {
-            Bone start = right ? Bone.Finger0R : Bone.Finger0L;
-            Bone end = right ? Bone.Finger4R : Bone.Finger4L;
+            var start = right ? Bone.Finger0R : Bone.Finger0L;
+            var end = right ? Bone.Finger4R : Bone.Finger4L;
+
             return SerializeFinger(start, end);
         }
 
         public void DeserializeHand(byte[] handBinary, bool right, bool mirroring = false)
         {
-            Bone start = right ? Bone.Finger0R : Bone.Finger0L;
-            Bone end = right ? Bone.Finger4R : Bone.Finger4L;
+            var start = right ? Bone.Finger0R : Bone.Finger0L;
+            var end = right ? Bone.Finger4R : Bone.Finger4L;
+
             DeserializeFinger(start, end, handBinary, mirroring);
         }
 
         public byte[] SerializeFoot(bool right)
         {
-            Bone start = right ? Bone.Toe0R : Bone.Toe0L;
-            Bone end = right ? Bone.Toe2R : Bone.Toe2L;
+            var start = right ? Bone.Toe0R : Bone.Toe0L;
+            var end = right ? Bone.Toe2R : Bone.Toe2L;
+
             return SerializeFinger(start, end);
         }
 
         public void DeserializeFoot(byte[] footBinary, bool right, bool mirroring = false)
         {
-            Bone start = right ? Bone.Toe0R : Bone.Toe0L;
-            Bone end = right ? Bone.Toe2R : Bone.Toe2L;
-            DeserializeFinger(start, end, footBinary, mirroring);
-        }
-
-        private byte[] SerializeFinger(Bone start, Bone end)
-        {
-            int joints = BoneTransform[start].name.Split(' ')[2].StartsWith("Finger") ? 4 : 3;
-
-            byte[] buf;
-
-            using (MemoryStream memoryStream = new MemoryStream())
-            using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
-            {
-                for (Bone bone = start; bone <= end; bone += joints)
-                {
-                    for (int i = 0; i < joints - 1; i++)
-                    {
-                        binaryWriter.WriteQuaternion(BoneTransform[bone + i].localRotation);
-                    }
-                }
-                buf = memoryStream.ToArray();
-            }
+            var start = right ? Bone.Toe0R : Bone.Toe0L;
+            var end = right ? Bone.Toe2R : Bone.Toe2L;
 
-            return buf;
+            DeserializeFinger(start, end, footBinary, mirroring);
         }
 
-        private void DeserializeFinger(Bone start, Bone end, byte[] fingerBinary, bool mirroring = false)
+        public void Destroy()
         {
-            int joints = BoneTransform[start].name.Split(' ')[2].StartsWith("Finger") ? 4 : 3;
-
-            int mirror = mirroring ? -1 : 1;
+            foreach (var dragPoint in DragPoints.Values)
+                if (dragPoint != null)
+                    UnityEngine.Object.Destroy(dragPoint.gameObject);
 
-            using MemoryStream memoryStream = new MemoryStream(fingerBinary);
-            using BinaryReader binaryReader = new BinaryReader(memoryStream);
+            if (dragCube != null)
+                UnityEngine.Object.Destroy(dragCube.gameObject);
 
-            for (Bone bone = start; bone <= end; bone += joints)
-            {
-                for (int i = 0; i < joints - 1; i++)
-                {
-                    BoneTransform[bone + i].localRotation = new Quaternion
-                    (
-                        binaryReader.ReadSingle() * mirror,
-                        binaryReader.ReadSingle() * mirror,
-                        binaryReader.ReadSingle(),
-                        binaryReader.ReadSingle()
-                    );
-                }
-            }
-        }
+            if (dragBody != null)
+                UnityEngine.Object.Destroy(dragBody.gameObject);
 
-        public void Destroy()
-        {
-            foreach (DragPointMeido dragPoint in DragPoints.Values)
-            {
-                if (dragPoint != null)
-                {
-                    GameObject.Destroy(dragPoint.gameObject);
-                }
-            }
-            if (dragCube != null) GameObject.Destroy(dragCube.gameObject);
-            if (dragBody != null) GameObject.Destroy(dragBody.gameObject);
             BoneTransform.Clear();
             DragPoints.Clear();
             CubeActiveChange -= OnCubeActive;
@@ -373,15 +396,81 @@ namespace MeidoPhotoStudio.Plugin
 
         public void Initialize()
         {
-            if (initialized) return;
+            if (initialized)
+                return;
+
             initialized = true;
             CubeActiveChange += OnCubeActive;
             CubeSmallChange += OnCubeSmall;
+
             InitializeBones();
             InitializeDragPoints();
             SetDragPointScale(meido.Maid.transform.localScale.x);
         }
 
+        public void SetDragPointScale(float scale)
+        {
+            foreach (var dragPoint in DragPoints.Values)
+                dragPoint.DragPointScale = scale;
+
+            dragBody.DragPointScale = scale;
+        }
+
+        /*
+            Somebody smarter than me please help me find a way to do this better T_T
+            inb4 for loop.
+         */
+        private System.Collections.IEnumerator ApplyHipPosition(Vector3 hipPosition)
+        {
+            BoneTransform[Bone.Hip].position = hipPosition;
+
+            yield return new WaitForEndOfFrame();
+
+            BoneTransform[Bone.Hip].position = hipPosition;
+
+            yield return new WaitForEndOfFrame();
+
+            BoneTransform[Bone.Hip].position = hipPosition;
+        }
+
+        private Quaternion FlipRotation(Vector3 rotation) =>
+            Quaternion.Euler(360f - rotation.x, 360f - (rotation.y + 90f) - 90f, rotation.z);
+
+        private byte[] SerializeFinger(Bone start, Bone end)
+        {
+            var joints = BoneTransform[start].name.Split(' ')[2].StartsWith("Finger") ? 4 : 3;
+
+            byte[] buf;
+
+            using var memoryStream = new MemoryStream();
+            using var binaryWriter = new BinaryWriter(memoryStream);
+
+            for (var bone = start; bone <= end; bone += joints)
+                for (var i = 0; i < joints - 1; i++)
+                    binaryWriter.WriteQuaternion(BoneTransform[bone + i].localRotation);
+
+            buf = memoryStream.ToArray();
+
+            return buf;
+        }
+
+        private void DeserializeFinger(Bone start, Bone end, byte[] fingerBinary, bool mirroring = false)
+        {
+            var joints = BoneTransform[start].name.Split(' ')[2].StartsWith("Finger") ? 4 : 3;
+            var mirror = mirroring ? -1 : 1;
+
+            using var memoryStream = new MemoryStream(fingerBinary);
+            using var binaryReader = new BinaryReader(memoryStream);
+
+            for (var bone = start; bone <= end; bone += joints)
+                for (var i = 0; i < joints - 1; i++)
+                    BoneTransform[bone + i].localRotation =
+                        new(
+                            binaryReader.ReadSingle() * mirror, binaryReader.ReadSingle() * mirror,
+                            binaryReader.ReadSingle(), binaryReader.ReadSingle()
+                        );
+        }
+
         private void InitializeDragPoints()
         {
             dragCube = DragPoint.Make<DragPointBody>(PrimitiveType.Cube, Vector3.one * 0.12f);
@@ -395,6 +484,7 @@ namespace MeidoPhotoStudio.Plugin
             dragCube.gameObject.SetActive(CubeActive);
 
             dragBody = DragPoint.Make<DragPointBody>(PrimitiveType.Capsule, new Vector3(0.2f, 0.3f, 0.24f));
+
             dragBody.Initialize(
                 () => new Vector3(
                     (BoneTransform[Bone.Hip].position.x + BoneTransform[Bone.Spine0a].position.x) / 2f,
@@ -407,18 +497,20 @@ namespace MeidoPhotoStudio.Plugin
                     BoneTransform[Bone.Spine0a].eulerAngles.z + 90f
                 )
             );
+
             dragBody.Set(meido.Maid.transform);
             dragBody.Select += OnSelectBody;
             dragBody.EndScale += OnSetDragPointScale;
 
             // Neck Dragpoint
-            DragPointHead dragNeck = DragPoint.Make<DragPointHead>(
+            var dragNeck = DragPoint.Make<DragPointHead>(
                 PrimitiveType.Sphere, new Vector3(0.2f, 0.24f, 0.2f)
             );
+
             dragNeck.Initialize(meido,
                 () => new Vector3(
                     BoneTransform[Bone.Head].position.x,
-                    ((BoneTransform[Bone.Head].position.y * 1.2f) + (BoneTransform[Bone.HeadNub].position.y * 0.8f)) / 2f,
+                    (BoneTransform[Bone.Head].position.y * 1.2f + BoneTransform[Bone.HeadNub].position.y * 0.8f) / 2f,
                     BoneTransform[Bone.Head].position.z
                 ),
                 () => new Vector3(
@@ -427,13 +519,15 @@ namespace MeidoPhotoStudio.Plugin
                     BoneTransform[Bone.Head].eulerAngles.z + 90f
                 )
             );
+
             dragNeck.Set(BoneTransform[Bone.Neck]);
             dragNeck.Select += OnSelectFace;
 
             DragPoints[Bone.Head] = dragNeck;
 
             // Head Dragpoint
-            DragPointSpine dragHead = DragPoint.Make<DragPointSpine>(PrimitiveType.Sphere, Vector3.one * 0.045f);
+            var dragHead = DragPoint.Make<DragPointSpine>(PrimitiveType.Sphere, Vector3.one * 0.045f);
+
             dragHead.Initialize(meido, () => BoneTransform[Bone.Head].position, () => Vector3.zero);
             dragHead.Set(BoneTransform[Bone.Head]);
             dragHead.AddGizmo();
@@ -441,12 +535,13 @@ namespace MeidoPhotoStudio.Plugin
             DragPoints[Bone.HeadNub] = dragHead;
 
             // Torso Dragpoint
-            Transform spineTrans1 = BoneTransform[Bone.Spine1];
-            Transform spineTrans2 = BoneTransform[Bone.Spine1a];
+            var spineTrans1 = BoneTransform[Bone.Spine1];
+            var spineTrans2 = BoneTransform[Bone.Spine1a];
 
-            DragPointTorso dragTorso = DragPoint.Make<DragPointTorso>(
+            var dragTorso = DragPoint.Make<DragPointTorso>(
                 PrimitiveType.Capsule, new Vector3(0.2f, 0.19f, 0.24f)
             );
+
             dragTorso.Initialize(meido,
                 () => new Vector3(
                     spineTrans1.position.x,
@@ -459,15 +554,16 @@ namespace MeidoPhotoStudio.Plugin
                     spineTrans1.eulerAngles.z + 90f
                 )
             );
+
             dragTorso.Set(BoneTransform[Bone.Spine1a]);
 
             DragPoints[Bone.Torso] = dragTorso;
 
             // Pelvis Dragpoint
-            Transform pelvisTrans = BoneTransform[Bone.Pelvis];
-            Transform spineTrans = BoneTransform[Bone.Spine];
+            var pelvisTrans = BoneTransform[Bone.Pelvis];
+            var spineTrans = BoneTransform[Bone.Spine];
 
-            DragPointPelvis dragPelvis = DragPoint.Make<DragPointPelvis>(
+            var dragPelvis = DragPoint.Make<DragPointPelvis>(
                 PrimitiveType.Capsule, new Vector3(0.2f, 0.15f, 0.24f)
             );
             dragPelvis.Initialize(meido,
@@ -491,20 +587,24 @@ namespace MeidoPhotoStudio.Plugin
             InitializeMuneDragPoint(left: false);
 
             var armDragPointL = MakeArmChain(BoneTransform[Bone.HandL], meido);
+
             DragPoints[Bone.UpperArmL] = armDragPointL[0];
             DragPoints[Bone.ForearmL] = armDragPointL[1];
             DragPoints[Bone.HandL] = armDragPointL[2];
 
             var armDragPointR = MakeArmChain(BoneTransform[Bone.HandR], meido);
+
             DragPoints[Bone.UpperArmR] = armDragPointR[0];
             DragPoints[Bone.ForearmR] = armDragPointR[1];
             DragPoints[Bone.HandR] = armDragPointR[2];
 
             var legDragPointL = MakeLegChain(BoneTransform[Bone.FootL]);
+
             DragPoints[Bone.CalfL] = legDragPointL[0];
             DragPoints[Bone.FootL] = legDragPointL[1];
 
             var legDragPointR = MakeLegChain(BoneTransform[Bone.FootR]);
+
             DragPoints[Bone.CalfR] = legDragPointR[0];
             DragPoints[Bone.FootR] = legDragPointR[1];
 
@@ -512,8 +612,8 @@ namespace MeidoPhotoStudio.Plugin
 
             for (var bone = Bone.Finger4NubR; bone >= Bone.Finger0L; bone -= 4)
             {
-                var i = 2;
                 var chain = MakeFingerChain(BoneTransform[bone], meido);
+                var i = 2;
 
                 for (var joint = bone - 1; joint > bone - 4; joint--)
                 {
@@ -521,59 +621,40 @@ namespace MeidoPhotoStudio.Plugin
                     i--;
                 }
             }
+
             MakeToeChain(Bone.Toe0L, Bone.Toe2R);
         }
 
         private void InitializeMuneDragPoint(bool left)
         {
-            Bone mune = left ? Bone.MuneL : Bone.MuneR;
-            Bone sub = left ? Bone.MuneSubL : Bone.MuneSubR;
-            DragPointMune muneDragPoint = DragPoint.Make<DragPointMune>(PrimitiveType.Sphere, Vector3.one * 0.12f);
+            var mune = left ? Bone.MuneL : Bone.MuneR;
+            var sub = left ? Bone.MuneSubL : Bone.MuneSubR;
+            var muneDragPoint = DragPoint.Make<DragPointMune>(PrimitiveType.Sphere, Vector3.one * 0.12f);
+
             muneDragPoint.Initialize(meido,
                 () => (BoneTransform[mune].position + BoneTransform[sub].position) / 2f,
                 () => Vector3.zero
             );
+
             muneDragPoint.Set(BoneTransform[sub]);
             DragPoints[mune] = muneDragPoint;
         }
 
         private DragPointLimb[] MakeLegChain(Transform lower)
         {
-            Vector3 limbDragPointSize = Vector3.one * 0.12f;
-            DragPointLimb[] dragPoints = new DragPointLimb[2];
-            for (var i = dragPoints.Length - 1; i >= 0; i--)
-            {
-                Transform joint = lower;
-                dragPoints[i] = DragPoint.Make<DragPointLimb>(PrimitiveType.Sphere, limbDragPointSize);
-                dragPoints[i].Initialize(meido, () => joint.position, () => Vector3.zero);
-                dragPoints[i].Set(joint);
-                dragPoints[i].AddGizmo();
-                lower = lower.parent;
-            }
-            return dragPoints;
-        }
-
-        private static DragPointLimb[] MakeArmChain(Transform lower, Meido meido)
-        {
             var limbDragPointSize = Vector3.one * 0.12f;
 
-            var realLower = CMT.SearchObjName(meido.Body.goSlot[0].obj_tr, lower.name, false);
-
-            var dragPoints = new DragPointLimb[3];
+            var dragPoints = new DragPointLimb[2];
 
             for (var i = dragPoints.Length - 1; i >= 0; i--)
             {
                 var joint = lower;
-                var positionJoint = realLower;
 
                 dragPoints[i] = DragPoint.Make<DragPointLimb>(PrimitiveType.Sphere, limbDragPointSize);
-                dragPoints[i].Initialize(meido, () => positionJoint.position, () => Vector3.zero);
+                dragPoints[i].Initialize(meido, () => joint.position, () => Vector3.zero);
                 dragPoints[i].Set(joint);
                 dragPoints[i].AddGizmo();
-                dragPoints[i].Gizmo.SetAlternateTarget(positionJoint);
-
                 lower = lower.parent;
-                realLower = realLower.parent;
             }
 
             return dragPoints;
@@ -581,14 +662,17 @@ namespace MeidoPhotoStudio.Plugin
 
         private void MakeToeChain(Bone start, Bone end)
         {
-            Vector3 fingerDragPointSize = Vector3.one * 0.01f;
             const int joints = 3;
-            for (Bone bone = start; bone <= end; bone += joints)
+
+            var fingerDragPointSize = Vector3.one * 0.01f;
+
+            for (var bone = start; bone <= end; bone += joints)
             {
-                for (int i = 1; i < joints; i++)
+                for (var i = 1; i < joints; i++)
                 {
-                    Transform trans = BoneTransform[bone + i];
-                    DragPointFinger chain = DragPoint.Make<DragPointFinger>(PrimitiveType.Sphere, fingerDragPointSize);
+                    var trans = BoneTransform[bone + i];
+                    var chain = DragPoint.Make<DragPointFinger>(PrimitiveType.Sphere, fingerDragPointSize);
+
                     chain.Initialize(meido, () => trans.position, () => Vector3.zero);
                     chain.Set(trans);
                     DragPoints[bone + i] = chain;
@@ -596,42 +680,21 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private static DragPointFinger[] MakeFingerChain(Transform lower, Meido meido)
+        private void InitializeSpineDragPoint(params Bone[] bones)
         {
-            var fingerDragPointSize = Vector3.one * 0.01f;
+            var spineDragPointSize = DragPointMeido.boneScale;
 
-            var dragPoints = new DragPointFinger[3];
-
-            var realLower = CMT.SearchObjName(meido.Body.goSlot[0].obj_tr, lower.parent.name, false);
-
-            for (var i = dragPoints.Length - 1; i >= 0; i--)
+            foreach (var bone in bones)
             {
-                var joint = lower;
-                var positionJoint = realLower;
-
-                dragPoints[i] = DragPoint.Make<DragPointFinger>(PrimitiveType.Sphere, fingerDragPointSize);
-                dragPoints[i].Initialize(meido, () => positionJoint.position, () => Vector3.zero);
-                dragPoints[i].Set(joint);
+                var spine = BoneTransform[bone];
+                var primitive = bone == Bone.Hip ? PrimitiveType.Cube : PrimitiveType.Sphere;
+                var dragPoint = DragPoint.Make<DragPointSpine>(primitive, spineDragPointSize);
 
-                lower = lower.parent;
-                realLower = realLower.parent;
-            }
-
-            return dragPoints;
-        }
-
-        private void InitializeSpineDragPoint(params Bone[] bones)
-        {
-            Vector3 spineDragPointSize = DragPointMeido.boneScale;
-            foreach (Bone bone in bones)
-            {
-                Transform spine = BoneTransform[bone];
-                PrimitiveType primitive = bone == Bone.Hip ? PrimitiveType.Cube : PrimitiveType.Sphere;
-                DragPointSpine dragPoint = DragPoint.Make<DragPointSpine>(primitive, spineDragPointSize);
                 dragPoint.Initialize(meido,
                     () => spine.position,
                     () => Vector3.zero
                 );
+
                 dragPoint.Set(spine);
                 dragPoint.AddGizmo();
                 DragPoints[bone] = dragPoint;
@@ -639,42 +702,27 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        private void OnCubeActive(object sender, EventArgs args)
-        {
+        private void OnCubeActive(object sender, EventArgs args) =>
             dragCube.gameObject.SetActive(CubeActive);
-        }
 
-        private void OnCubeSmall(object sender, EventArgs args)
-        {
+        private void OnCubeSmall(object sender, EventArgs args) =>
             dragCube.DragPointScale = CubeSmall ? DragPointGeneral.smallCube : 1f;
-        }
 
-        private void OnSetDragPointScale(object sender, EventArgs args)
-        {
+        private void OnSetDragPointScale(object sender, EventArgs args) =>
             SetDragPointScale(meido.Maid.transform.localScale.x);
-        }
 
-        private void OnSelectBody(object sender, EventArgs args)
-        {
+        private void OnSelectBody(object sender, EventArgs args) =>
             SelectMaid?.Invoke(this, new MeidoUpdateEventArgs(meido.Slot, fromMaid: true, isBody: true));
-        }
 
-        private void OnSelectFace(object sender, EventArgs args)
-        {
+        private void OnSelectFace(object sender, EventArgs args) =>
             SelectMaid?.Invoke(this, new MeidoUpdateEventArgs(meido.Slot, fromMaid: true, isBody: false));
-        }
-
-        public void SetDragPointScale(float scale)
-        {
-            foreach (DragPointMeido dragPoint in DragPoints.Values) dragPoint.DragPointScale = scale;
-            dragBody.DragPointScale = scale;
-        }
 
         private void InitializeBones()
         {
             // TODO: Move to external file somehow
-            Transform transform = meido.Body.m_Bones.transform;
-            BoneTransform = new Dictionary<Bone, Transform>()
+            var transform = meido.Body.m_Bones.transform;
+
+            BoneTransform = new()
             {
                 [Bone.Head] = CMT.SearchObjName(transform, "Bip01 Head"),
                 [Bone.Neck] = CMT.SearchObjName(transform, "Bip01 Neck"),
@@ -771,27 +819,27 @@ namespace MeidoPhotoStudio.Plugin
 
     public readonly struct AttachPointInfo
     {
-        private readonly AttachPoint attachPoint;
-        public AttachPoint AttachPoint => attachPoint;
-        public string MaidGuid { get; }
-        
-        private readonly int maidIndex;
-        public int MaidIndex => maidIndex;
         private static readonly AttachPointInfo empty = new(AttachPoint.None, string.Empty, -1);
-        public static ref readonly AttachPointInfo Empty => ref empty;
+
+        public AttachPoint AttachPoint { get; }
+        public string MaidGuid { get; }
+        public int MaidIndex { get; }
+
+        public static ref readonly AttachPointInfo Empty =>
+            ref empty;
 
         public AttachPointInfo(AttachPoint attachPoint, Meido meido)
         {
-            this.attachPoint = attachPoint;
+            AttachPoint = attachPoint;
             MaidGuid = meido.Maid.status.guid;
-            maidIndex = meido.Slot;
+            MaidIndex = meido.Slot;
         }
 
         public AttachPointInfo(AttachPoint attachPoint, string maidGuid, int maidIndex)
         {
-            this.attachPoint = attachPoint;
+            AttachPoint = attachPoint;
             MaidGuid = maidGuid;
-            this.maidIndex = maidIndex;
+            MaidIndex = maidIndex;
         }
     }
 }

+ 132 - 96
src/MeidoPhotoStudio.Plugin/MeidoPhotoStudio.cs

@@ -1,30 +1,37 @@
 using System;
-using System.IO;
 using System.Collections;
-using System.Collections.Generic;
+using System.IO;
 using System.Text;
+using BepInEx;
 using UnityEngine;
 using UnityEngine.SceneManagement;
-using BepInEx;
+using Input = MeidoPhotoStudio.Plugin.InputManager;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using Input = InputManager;
     [BepInPlugin(pluginGuid, pluginName, pluginVersion)]
     [BepInDependency("org.bepinex.plugins.unityinjectorloader", BepInDependency.DependencyFlags.SoftDependency)]
     public class MeidoPhotoStudio : BaseUnityPlugin
     {
-        public static readonly byte[] SceneHeader = Encoding.UTF8.GetBytes("MPSSCENE");
-        private static event EventHandler<ScreenshotEventArgs> ScreenshotEvent;
-        private const string pluginGuid = "com.habeebweeb.com3d2.meidophotostudio";
         public const string pluginName = "MeidoPhotoStudio";
         public const string pluginVersion = "1.0.0";
         public const string pluginSubVersion = "beta.4.1";
         public const short sceneVersion = 2;
         public const int kankyoMagic = -765;
+
+        private const string pluginGuid = "com.habeebweeb.com3d2.meidophotostudio";
+
+        public static readonly byte[] SceneHeader = Encoding.UTF8.GetBytes("MPSSCENE");
         public static readonly string pluginString = $"{pluginName} {pluginVersion}";
-        public static bool EditMode => currentScene == Constants.Scene.Edit;
+
+        public static bool EditMode =>
+            currentScene is Constants.Scene.Edit;
+
         public static event EventHandler<ScreenshotEventArgs> NotifyRawScreenshot;
+
+        private static event EventHandler<ScreenshotEventArgs> ScreenshotEvent;
+        private static Constants.Scene currentScene;
+
         private HarmonyLib.Harmony harmony;
         private WindowManager windowManager;
         private SceneManager sceneManager;
@@ -35,7 +42,6 @@ namespace MeidoPhotoStudio.Plugin
         private PropManager propManager;
         private EffectManager effectManager;
         private CameraManager cameraManager;
-        private static Constants.Scene currentScene;
         private bool initialized;
         private bool active;
         private bool uiActive;
@@ -45,40 +51,20 @@ namespace MeidoPhotoStudio.Plugin
             Input.Register(MpsKey.Screenshot, KeyCode.S, "Take screenshot");
             Input.Register(MpsKey.Activate, KeyCode.F6, "Activate/deactivate MeidoPhotoStudio");
 
-            if (!string.IsNullOrEmpty(pluginSubVersion)) pluginString += $"-{pluginSubVersion}";
+            if (!string.IsNullOrEmpty(pluginSubVersion))
+                pluginString += $"-{pluginSubVersion}";
         }
 
-        private void Awake()
-        {
-            harmony = HarmonyLib.Harmony.CreateAndPatchAll(typeof(AllProcPropSeqStartPatcher));
-            harmony.PatchAll(typeof(BgMgrPatcher));
-            harmony.PatchAll(typeof(MeidoManager));
-            ScreenshotEvent += OnScreenshotEvent;
-            DontDestroyOnLoad(this);
-            UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
-            UnityEngine.SceneManagement.SceneManager.activeSceneChanged += OnSceneChanged;
-        }
-
-        private void Start()
-        {
-            Constants.Initialize();
-            Translation.Initialize(Translation.CurrentLanguage);
-        }
+        public static void TakeScreenshot(ScreenshotEventArgs args) =>
+            ScreenshotEvent?.Invoke(null, args);
 
-        private void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode)
-        {
-            currentScene = (Constants.Scene)scene.buildIndex;
-        }
-
-        private void OnSceneChanged(Scene current, Scene next)
-        {
-            if (active) Deactivate(true);
-            CameraUtility.MainCamera.ResetCalcNearClip();
-        }
+        public static void TakeScreenshot(string path = "", int superSize = -1, bool hideMaids = false) =>
+            TakeScreenshot(new ScreenshotEventArgs() { Path = path, SuperSize = superSize, HideMaids = hideMaids });
 
         public byte[] SaveScene(bool environment = false)
         {
-            if (meidoManager.Busy) return null;
+            if (meidoManager.Busy)
+                return null;
 
             try
             {
@@ -91,7 +77,8 @@ namespace MeidoPhotoStudio.Plugin
                 {
                     Version = sceneVersion,
                     Environment = environment,
-                    MaidCount = environment ? kankyoMagic : meidoManager.ActiveMeidoList.Count
+                    MaidCount = environment ? kankyoMagic : meidoManager.ActiveMeidoList.Count,
+                    MMConverted = false,
                 }.WriteMetadata(headerWriter);
 
                 using var compressionStream = memoryStream.GetCompressionStream();
@@ -114,6 +101,7 @@ namespace MeidoPhotoStudio.Plugin
                 compressionStream.Close();
 
                 var data = memoryStream.ToArray();
+
                 return data;
             }
             catch (Exception e)
@@ -133,7 +121,7 @@ namespace MeidoPhotoStudio.Plugin
 
             using var memoryStream = new MemoryStream(buffer);
             using var headerReader = new BinaryReader(memoryStream, Encoding.UTF8);
-            
+
             if (!Utility.BytesEqual(headerReader.ReadBytes(SceneHeader.Length), SceneHeader))
             {
                 Utility.LogError("Not a MPS scene!");
@@ -154,13 +142,14 @@ namespace MeidoPhotoStudio.Plugin
 
             var header = string.Empty;
             var previousHeader = string.Empty;
+
             try
             {
-                while ((header = dataReader.ReadString()) != "END")
+                while ((header = dataReader.ReadString()) is not "END")
                 {
                     switch (header)
                     {
-                        case MeidoManager.header: 
+                        case MeidoManager.header:
                             Serialization.Get<MeidoManager>().Deserialize(meidoManager, dataReader, metadata);
                             break;
                         case MessageWindowManager.header:
@@ -197,34 +186,56 @@ namespace MeidoPhotoStudio.Plugin
             }
         }
 
-        public static void TakeScreenshot(ScreenshotEventArgs args) => ScreenshotEvent?.Invoke(null, args);
+        private void OnSceneLoaded(Scene scene, LoadSceneMode sceneMode) =>
+            currentScene = (Constants.Scene)scene.buildIndex;
 
-        public static void TakeScreenshot(string path = "", int superSize = -1, bool hideMaids = false)
+        private void OnSceneChanged(Scene current, Scene next)
         {
-            TakeScreenshot(new ScreenshotEventArgs() { Path = path, SuperSize = superSize, HideMaids = hideMaids });
+            if (active)
+                Deactivate(true);
+
+            CameraUtility.MainCamera.ResetCalcNearClip();
         }
 
-        private void OnScreenshotEvent(object sender, ScreenshotEventArgs args)
-        {
+        private void OnScreenshotEvent(object sender, ScreenshotEventArgs args) =>
             StartCoroutine(Screenshot(args));
+
+        private void Awake()
+        {
+            harmony = HarmonyLib.Harmony.CreateAndPatchAll(typeof(AllProcPropSeqStartPatcher));
+            harmony.PatchAll(typeof(BgMgrPatcher));
+            harmony.PatchAll(typeof(MeidoManager));
+
+            ScreenshotEvent += OnScreenshotEvent;
+
+            DontDestroyOnLoad(this);
+
+            UnityEngine.SceneManagement.SceneManager.sceneLoaded += OnSceneLoaded;
+            UnityEngine.SceneManagement.SceneManager.activeSceneChanged += OnSceneChanged;
+        }
+
+        private void Start()
+        {
+            Constants.Initialize();
+            Translation.Initialize(Translation.CurrentLanguage);
         }
 
         private void Update()
         {
-            if (currentScene == Constants.Scene.Daily || currentScene == Constants.Scene.Edit)
+            if (currentScene is Constants.Scene.Daily or Constants.Scene.Edit)
             {
                 if (Input.GetKeyDown(MpsKey.Activate))
                 {
-                    if (active) Deactivate();
-                    else Activate();
+                    if (active)
+                        Deactivate();
+                    else
+                        Activate();
                 }
 
                 if (active)
                 {
                     if (!Input.Control && !Input.GetKey(MpsKey.CameraLayer) && Input.GetKeyDown(MpsKey.Screenshot))
-                    {
                         TakeScreenshot();
-                    }
 
                     meidoManager.Update();
                     cameraManager.Update();
@@ -238,14 +249,14 @@ namespace MeidoPhotoStudio.Plugin
         private IEnumerator Screenshot(ScreenshotEventArgs args)
         {
             // Hide UI and dragpoints
-            GameObject gameMain = GameMain.Instance.gameObject;
-            GameObject editUI = UTY.GetChildObject(GameObject.Find("UI Root"), "Camera");
-            GameObject fpsViewer = UTY.GetChildObject(gameMain, "SystemUI Root/FpsCounter");
-            GameObject sysDialog = UTY.GetChildObject(gameMain, "SystemUI Root/SystemDialog");
-            GameObject sysShortcut = UTY.GetChildObject(gameMain, "SystemUI Root/SystemShortcut");
+            var gameMain = GameMain.Instance.gameObject;
+            var editUI = UTY.GetChildObject(GameObject.Find("UI Root"), "Camera");
+            var fpsViewer = UTY.GetChildObject(gameMain, "SystemUI Root/FpsCounter");
+            var sysDialog = UTY.GetChildObject(gameMain, "SystemUI Root/SystemDialog");
+            var sysShortcut = UTY.GetChildObject(gameMain, "SystemUI Root/SystemShortcut");
 
             // CameraUtility can hide the edit UI so keep its state for later
-            bool editUIWasActive = editUI.activeSelf;
+            var editUIWasActive = editUI.activeSelf;
 
             uiActive = false;
             editUI.SetActive(false);
@@ -254,14 +265,18 @@ namespace MeidoPhotoStudio.Plugin
             sysShortcut.SetActive(false);
 
             // Hide maid dragpoints and maids
-            List<Meido> activeMeidoList = meidoManager.ActiveMeidoList;
-            bool[] isIK = new bool[activeMeidoList.Count];
-            bool[] isVisible = new bool[activeMeidoList.Count];
-            for (int i = 0; i < activeMeidoList.Count; i++)
+            var activeMeidoList = meidoManager.ActiveMeidoList;
+            var isIK = new bool[activeMeidoList.Count];
+            var isVisible = new bool[activeMeidoList.Count];
+
+            for (var i = 0; i < activeMeidoList.Count; i++)
             {
-                Meido meido = activeMeidoList[i];
+                var meido = activeMeidoList[i];
+
                 isIK[i] = meido.IK;
-                if (meido.IK) meido.IK = false;
+
+                if (meido.IK)
+                    meido.IK = false;
 
                 // Hide the maid if needed
                 if (args.HideMaids)
@@ -272,7 +287,7 @@ namespace MeidoPhotoStudio.Plugin
             }
 
             // Hide other drag points
-            bool[] isCubeActive = {
+            var isCubeActive = new[] {
                 MeidoDragPointManager.CubeActive,
                 PropManager.CubeActive,
                 LightManager.CubeActive,
@@ -294,12 +309,13 @@ namespace MeidoPhotoStudio.Plugin
             if (args.InMemory)
             {
                 // Take a screenshot directly to a Texture2D for immediate processing
-                RenderTexture renderTexture = new RenderTexture(Screen.width, Screen.height, 24);
+                var renderTexture = new RenderTexture(Screen.width, Screen.height, 24);
+
                 RenderTexture.active = renderTexture;
                 CameraUtility.MainCamera.camera.targetTexture = renderTexture;
                 CameraUtility.MainCamera.camera.Render();
 
-                rawScreenshot = new Texture2D(Screen.width, Screen.height, TextureFormat.RGB24, false);
+                rawScreenshot = new(Screen.width, Screen.height, TextureFormat.RGB24, false);
                 rawScreenshot.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0, false);
                 rawScreenshot.Apply();
 
@@ -310,17 +326,18 @@ namespace MeidoPhotoStudio.Plugin
             else
             {
                 // Take Screenshot
-                int[] defaultSuperSize = new[] { 1, 2, 4 };
-                int selectedSuperSize = args.SuperSize < 1
+                var defaultSuperSize = new[] { 1, 2, 4 };
+                var selectedSuperSize = args.SuperSize < 1
                     ? defaultSuperSize[(int)GameMain.Instance.CMSystem.ScreenShotSuperSize]
                     : args.SuperSize;
 
-                string path = string.IsNullOrEmpty(args.Path)
+                var path = string.IsNullOrEmpty(args.Path)
                     ? Utility.ScreenshotFilename()
                     : args.Path;
 
                 Application.CaptureScreenshot(path, selectedSuperSize);
             }
+
             GameMain.Instance.SoundMgr.PlaySe("se022.ogg", false);
 
             yield return new WaitForEndOfFrame();
@@ -332,11 +349,14 @@ namespace MeidoPhotoStudio.Plugin
             sysDialog.SetActive(true);
             sysShortcut.SetActive(true);
 
-            for (int i = 0; i < activeMeidoList.Count; i++)
+            for (var i = 0; i < activeMeidoList.Count; i++)
             {
-                Meido meido = activeMeidoList[i];
-                if (isIK[i]) meido.IK = true;
-                if (args.HideMaids && isVisible[i]) meido.Maid.Visible = true;
+                var meido = activeMeidoList[i];
+
+                if (isIK[i])
+                    meido.IK = true;
+                if (args.HideMaids && isVisible[i])
+                    meido.Maid.Visible = true;
             }
 
             MeidoDragPointManager.CubeActive = isCubeActive[0];
@@ -347,7 +367,7 @@ namespace MeidoPhotoStudio.Plugin
             GizmoRender.UIVisible = true;
 
             if (args.InMemory && rawScreenshot)
-                NotifyRawScreenshot?.Invoke(null, new ScreenshotEventArgs() { Screenshot = rawScreenshot });
+                NotifyRawScreenshot?.Invoke(null, new() { Screenshot = rawScreenshot });
         }
 
         private void OnGUI()
@@ -356,26 +376,31 @@ namespace MeidoPhotoStudio.Plugin
             {
                 windowManager.DrawWindows();
 
-                if (DropdownHelper.Visible) DropdownHelper.HandleDropdown();
-                if (Modal.Visible) Modal.Draw();
+                if (DropdownHelper.Visible)
+                    DropdownHelper.HandleDropdown();
+
+                if (Modal.Visible)
+                    Modal.Draw();
             }
         }
 
         private void Initialize()
         {
-            if (initialized) return;
+            if (initialized)
+                return;
+
             initialized = true;
 
-            meidoManager = new MeidoManager();
-            environmentManager = new EnvironmentManager();
-            messageWindowManager = new MessageWindowManager();
+            meidoManager = new();
+            environmentManager = new();
+            messageWindowManager = new();
             messageWindowManager.Activate();
-            lightManager = new LightManager();
-            propManager = new PropManager(meidoManager);
-            sceneManager = new SceneManager(this);
-            cameraManager = new CameraManager();
+            lightManager = new();
+            propManager = new(meidoManager);
+            sceneManager = new(this);
+            cameraManager = new();
 
-            effectManager = new EffectManager();
+            effectManager = new();
             effectManager.AddManager<BloomEffectManager>();
             effectManager.AddManager<DepthOfFieldEffectManager>();
             effectManager.AddManager<FogEffectManager>();
@@ -386,11 +411,11 @@ namespace MeidoPhotoStudio.Plugin
             meidoManager.BeginCallMeidos += (s, a) => uiActive = false;
             meidoManager.EndCallMeidos += (s, a) => uiActive = true;
 
-            MaidSwitcherPane maidSwitcherPane = new MaidSwitcherPane(meidoManager);
+            var maidSwitcherPane = new MaidSwitcherPane(meidoManager);
 
-            SceneWindow sceneWindow = new SceneWindow(sceneManager);
+            var sceneWindow = new SceneWindow(sceneManager);
 
-            windowManager = new WindowManager()
+            windowManager = new()
             {
                 [Constants.Window.Main] = new MainWindow(meidoManager, propManager, lightManager)
                 {
@@ -410,9 +435,11 @@ namespace MeidoPhotoStudio.Plugin
 
         private void Activate()
         {
-            if (!GameMain.Instance.SysDlg.IsDecided) return;
+            if (!GameMain.Instance.SysDlg.IsDecided)
+                return;
 
-            if (!initialized) Initialize();
+            if (!initialized)
+                Initialize();
             else
             {
                 meidoManager.Activate();
@@ -430,19 +457,25 @@ namespace MeidoPhotoStudio.Plugin
 
             if (!EditMode)
             {
-                GameObject dailyPanel = GameObject.Find("UI Root")?.transform.Find("DailyPanel")?.gameObject;
-                if (dailyPanel) dailyPanel.SetActive(false);
+                // TODO: Rework this to not use null propagation (UNT008)
+                var dailyPanel = GameObject.Find("UI Root")?.transform.Find("DailyPanel")?.gameObject;
+
+                if (dailyPanel)
+                    dailyPanel.SetActive(false);
             }
-            else meidoManager.CallMeidos();
+            else
+                meidoManager.CallMeidos();
         }
 
         private void Deactivate(bool force = false)
         {
-            if (meidoManager.Busy || SceneManager.Busy) return;
+            if (meidoManager.Busy || SceneManager.Busy)
+                return;
 
             var sysDialog = GameMain.Instance.SysDlg;
 
-            if (!sysDialog.IsDecided && !force) return;
+            if (!sysDialog.IsDecided && !force)
+                return;
 
             uiActive = false;
             active = false;
@@ -483,10 +516,13 @@ namespace MeidoPhotoStudio.Plugin
 
                 Configuration.Config.Save();
 
-                if (EditMode) return;
+                if (EditMode)
+                    return;
 
+                // TODO: Rework this to not use null propagation (UNT008)
                 var dailyPanel = GameObject.Find("UI Root")?.transform.Find("DailyPanel")?.gameObject;
 
+                // NOTE: using is (not) for null checks on UnityEngine.Object does not work
                 if (dailyPanel != null)
                     dailyPanel.SetActive(true);
             }

+ 31 - 16
src/MeidoPhotoStudio.Plugin/MenuFileCache.cs

@@ -1,5 +1,5 @@
-using System.IO;
 using System.Collections.Generic;
+using System.IO;
 
 /*
     All of this is pretty much stolen from COM3D2.CacheEditMenu. Thanks Mr. Horsington.
@@ -7,14 +7,17 @@ using System.Collections.Generic;
 */
 namespace MeidoPhotoStudio.Plugin
 {
-    using static MenuFileUtility;
 
     public class MenuFileCache
     {
         private const int cacheVersion = 765;
+
         public static readonly string cachePath = Path.Combine(Constants.configPath, "cache.dat");
+
         private readonly Dictionary<string, ModItem> modItems;
+
         private bool rebuild;
+
         public ModItem this[string menu]
         {
             get => modItems[menu];
@@ -30,33 +33,45 @@ namespace MeidoPhotoStudio.Plugin
 
         public MenuFileCache()
         {
-            modItems = new Dictionary<string, ModItem>();
-            if (File.Exists(cachePath)) Deserialize();
+            modItems = new();
+
+            if (File.Exists(cachePath))
+                Deserialize();
         }
 
-        public bool Has(string menuFileName) => modItems.ContainsKey(menuFileName);
+        public bool Has(string menuFileName) =>
+            modItems.ContainsKey(menuFileName);
+
+        public void Serialize()
+        {
+            if (!rebuild)
+                return;
+
+            using var binaryWriter = new BinaryWriter(File.OpenWrite(cachePath));
+
+            binaryWriter.Write(cacheVersion);
+
+            foreach (var item in modItems.Values)
+                item.Serialize(binaryWriter);
+        }
 
         private void Deserialize()
         {
-            using BinaryReader binaryReader = new BinaryReader(File.OpenRead(cachePath));
-            if (binaryReader.ReadInt32() != cacheVersion)
+            using var binaryReader = new BinaryReader(File.OpenRead(cachePath));
+
+            if (binaryReader.ReadInt32() is not cacheVersion)
             {
                 Utility.LogInfo("Cache version out of date. Rebuilding");
+
                 return;
             }
+
             while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
             {
-                ModItem item = ModItem.Deserialize(binaryReader);
+                var item = ModItem.Deserialize(binaryReader);
+
                 modItems[item.MenuFile] = item;
             }
         }
-
-        public void Serialize()
-        {
-            if (!rebuild) return;
-            using BinaryWriter binaryWriter = new BinaryWriter(File.OpenWrite(cachePath));
-            binaryWriter.Write(cacheVersion);
-            foreach (ModItem item in modItems.Values) item.Serialize(binaryWriter);
-        }
     }
 }

+ 114 - 64
src/MeidoPhotoStudio.Plugin/MenuFileUtility.cs

@@ -1,16 +1,15 @@
 using System;
-using System.Text;
-using System.IO;
 using System.Collections;
 using System.Collections.Generic;
+using System.IO;
 using System.Linq;
+using System.Text;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public static class MenuFileUtility
     {
-        private static byte[] fileBuffer;
         public const string noCategory = "noCategory";
 
         public static readonly string[] MenuCategories =
@@ -20,100 +19,104 @@ namespace MeidoPhotoStudio.Plugin
             "accnip", "accude", "accheso", "accashi", "accsenaka", "accshippo", "accxxx"
         };
 
-        private static readonly HashSet<string> accMpn = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
+        private static readonly HashSet<string> accMpn = new(StringComparer.InvariantCultureIgnoreCase);
 
         public static event EventHandler MenuFilesReadyChange;
         public static bool MenuFilesReady { get; private set; }
 
+        private static byte[] fileBuffer;
+
         static MenuFileUtility()
         {
             accMpn.UnionWith(MenuCategories.Skip(1));
             GameMain.Instance.StartCoroutine(CheckMenuDataBaseJob());
         }
 
-        private static IEnumerator CheckMenuDataBaseJob()
-        {
-            if (MenuFilesReady) yield break;
-            while (!GameMain.Instance.MenuDataBase.JobFinished()) yield return null;
-            MenuFilesReady = true;
-            MenuFilesReadyChange?.Invoke(null, EventArgs.Empty);
-        }
-
-        private static ref byte[] GetFileBuffer(long size)
-        {
-            if (fileBuffer == null) fileBuffer = new byte[Math.Max(500000, size)];
-            else if (fileBuffer.Length < size) fileBuffer = new byte[size];
-
-            return ref fileBuffer;
-        }
-
         public static byte[] ReadAFileBase(string filename)
         {
-            using AFileBase aFileBase = GameUty.FileOpen(filename);
+            using var aFileBase = GameUty.FileOpen(filename);
 
-            if (aFileBase.IsValid() && aFileBase.GetSize() != 0)
+            if (!aFileBase.IsValid() || aFileBase.GetSize() is 0)
             {
-                ref byte[] buffer = ref GetFileBuffer(aFileBase.GetSize());
+                Utility.LogError($"AFileBase '{filename}' is invalid");
 
-                aFileBase.Read(ref buffer, aFileBase.GetSize());
-
-                return buffer;
+                return null;
             }
 
-            Utility.LogError($"AFileBase '{filename}' is invalid");
-            return null;
+            ref var buffer = ref GetFileBuffer(aFileBase.GetSize());
+
+            aFileBase.Read(ref buffer, aFileBase.GetSize());
+
+            return buffer;
         }
 
         public static byte[] ReadOfficialMod(string filename)
         {
             using var fileStream = new FileStream(filename, FileMode.Open);
 
-            if (fileStream.Length != 0)
+            if (fileStream.Length is 0)
             {
-                ref byte[] buffer = ref GetFileBuffer(fileStream.Length);
+                Utility.LogWarning($"Mod menu file '{filename}' is invalid");
+                return null;
+            }
 
-                fileStream.Read(buffer, 0, (int) fileStream.Length);
+            ref var buffer = ref GetFileBuffer(fileStream.Length);
 
-                return buffer;
-            }
+            fileStream.Read(buffer, 0, (int)fileStream.Length);
 
-            Utility.LogWarning($"Mod menu file '{filename}' is invalid");
-            return null;
+            return buffer;
         }
 
         public static bool ParseNativeMenuFile(int menuIndex, ModItem modItem)
         {
-            MenuDataBase menuDataBase = GameMain.Instance.MenuDataBase;
+            var menuDataBase = GameMain.Instance.MenuDataBase;
             menuDataBase.SetIndex(menuIndex);
-            if (menuDataBase.GetBoDelOnly()) return false;
+
+            if (menuDataBase.GetBoDelOnly())
+                return false;
+
             modItem.Category = menuDataBase.GetCategoryMpnText();
-            if (!accMpn.Contains(modItem.Category)) return false;
+
+            if (!accMpn.Contains(modItem.Category))
+                return false;
+
             modItem.MenuFile = menuDataBase.GetMenuFileName().ToLower();
-            if (!ValidBG2MenuFile(modItem.MenuFile)) return false;
+
+            if (!ValidBG2MenuFile(modItem.MenuFile))
+                return false;
+
             modItem.Name = menuDataBase.GetMenuName();
             modItem.IconFile = menuDataBase.GetIconS();
             modItem.Priority = menuDataBase.GetPriority();
+
             return true;
         }
 
         public static void ParseMenuFile(string menuFile, ModItem modItem)
         {
-            if (!ValidBG2MenuFile(menuFile)) return;
+            if (!ValidBG2MenuFile(menuFile))
+                return;
 
             byte[] buffer;
 
-            try { buffer = ReadAFileBase(menuFile); }
+            try
+            {
+                buffer = ReadAFileBase(menuFile);
+            }
             catch (Exception e)
             {
                 Utility.LogError($"Could not read menu file '{menuFile}' because {e.Message}");
-                return ;
+
+                return;
             }
 
             try
             {
                 using var binaryReader = new BinaryReader(new MemoryStream(buffer), Encoding.UTF8);
 
-                if (binaryReader.ReadString() != "CM3D2_MENU") return;
+                if (binaryReader.ReadString() is not "CM3D2_MENU")
+                    return;
+
                 binaryReader.ReadInt32(); // file version
                 binaryReader.ReadString(); // txt path
                 modItem.Name = binaryReader.ReadString(); // name
@@ -123,34 +126,39 @@ namespace MeidoPhotoStudio.Plugin
 
                 while (true)
                 {
-                    int numberOfProps = binaryReader.ReadByte();
+                    var numberOfProps = binaryReader.ReadByte();
                     var menuPropString = string.Empty;
 
-                    if (numberOfProps == 0) break;
+                    if (numberOfProps is 0)
+                        break;
 
                     for (var i = 0; i < numberOfProps; i++)
-                    {
                         menuPropString = $"{menuPropString}\"{binaryReader.ReadString()}\"";
-                    }
 
-                    if (string.IsNullOrEmpty(menuPropString)) continue;
+                    if (string.IsNullOrEmpty(menuPropString))
+                        continue;
 
                     var header = UTY.GetStringCom(menuPropString);
-                    string[] menuProps = UTY.GetStringList(menuPropString);
+                    var menuProps = UTY.GetStringList(menuPropString);
 
-                    if (header == "end") break;
+                    if (header is "end")
+                        break;
 
-                    if (header == "category")
+                    if (header is "category")
                     {
                         modItem.Category = menuProps[1];
-                        if (!accMpn.Contains(modItem.Category)) return;
+
+                        if (!accMpn.Contains(modItem.Category))
+                            return;
                     }
-                    else if (header == "icons" || header == "icon")
+                    else if (header is "icons" or "icon")
                     {
                         modItem.IconFile = menuProps[1];
+
                         break;
                     }
-                    else if (header == "priority") modItem.Priority = float.Parse(menuProps[1]);
+                    else if (header is "priority")
+                        modItem.Priority = float.Parse(menuProps[1]);
                 }
             }
             catch (Exception e)
@@ -161,11 +169,15 @@ namespace MeidoPhotoStudio.Plugin
 
         public static bool ParseModMenuFile(string modMenuFile, ModItem modItem)
         {
-            if (!ValidBG2MenuFile(modMenuFile)) return false;
+            if (!ValidBG2MenuFile(modMenuFile))
+                return false;
 
             byte[] modBuffer;
 
-            try { modBuffer = ReadOfficialMod(modMenuFile); }
+            try
+            {
+                modBuffer = ReadOfficialMod(modMenuFile);
+            }
             catch (Exception e)
             {
                 Utility.LogError($"Could not read mod menu file '{modMenuFile} because {e.Message}'");
@@ -176,38 +188,53 @@ namespace MeidoPhotoStudio.Plugin
             {
                 using var binaryReader = new BinaryReader(new MemoryStream(modBuffer), Encoding.UTF8);
 
-                if (binaryReader.ReadString() != "CM3D2_MOD") return false;
+                if (binaryReader.ReadString() is not "CM3D2_MOD")
+                    return false;
 
                 binaryReader.ReadInt32();
+
                 var iconName = binaryReader.ReadString();
                 var baseItemPath = binaryReader.ReadString().Replace(":", " ");
+
                 modItem.BaseMenuFile = Path.GetFileName(baseItemPath);
                 modItem.Name = binaryReader.ReadString();
                 modItem.Category = binaryReader.ReadString();
-                if (!accMpn.Contains(modItem.Category)) return false;
+
+                if (!accMpn.Contains(modItem.Category))
+                    return false;
+
                 binaryReader.ReadString();
 
                 var mpnValue = binaryReader.ReadString();
                 var mpn = MPN.null_mpn;
-                try { mpn = (MPN) Enum.Parse(typeof(MPN), mpnValue, true); }
+
+                try
+                {
+                    mpn = (MPN)Enum.Parse(typeof(MPN), mpnValue, true);
+                }
                 catch { /* ignored */ }
 
-                if (mpn != MPN.null_mpn) binaryReader.ReadString();
+                if (mpn is not MPN.null_mpn)
+                    binaryReader.ReadString();
 
                 binaryReader.ReadString();
 
                 var entryCount = binaryReader.ReadInt32();
+
                 for (var i = 0; i < entryCount; i++)
                 {
                     var key = binaryReader.ReadString();
                     var count = binaryReader.ReadInt32();
-                    byte[] data = binaryReader.ReadBytes(count);
+                    var data = binaryReader.ReadBytes(count);
 
-                    if (!string.Equals(key, iconName, StringComparison.InvariantCultureIgnoreCase)) continue;
+                    if (!string.Equals(key, iconName, StringComparison.InvariantCultureIgnoreCase))
+                        continue;
 
                     var tex = new Texture2D(1, 1, TextureFormat.RGBA32, false);
+
                     tex.LoadImage(data);
                     modItem.Icon = tex;
+
                     break;
                 }
             }
@@ -220,14 +247,37 @@ namespace MeidoPhotoStudio.Plugin
             return true;
         }
 
-        public static bool ValidBG2MenuFile(ModItem modItem)
-            => accMpn.Contains(modItem.Category) && ValidBG2MenuFile(modItem.MenuFile);
+        public static bool ValidBG2MenuFile(ModItem modItem) =>
+            accMpn.Contains(modItem.Category) && ValidBG2MenuFile(modItem.MenuFile);
 
         public static bool ValidBG2MenuFile(string menu)
         {
             menu = Path.GetFileNameWithoutExtension(menu).ToLower();
+
             return !(menu.EndsWith("_del") || menu.Contains("zurashi") || menu.Contains("mekure")
                 || menu.Contains("porori") || menu.Contains("moza") || menu.Contains("folder"));
         }
+
+        private static IEnumerator CheckMenuDataBaseJob()
+        {
+            if (MenuFilesReady)
+                yield break;
+
+            while (!GameMain.Instance.MenuDataBase.JobFinished())
+                yield return null;
+
+            MenuFilesReady = true;
+            MenuFilesReadyChange?.Invoke(null, EventArgs.Empty);
+        }
+
+        private static ref byte[] GetFileBuffer(long size)
+        {
+            if (fileBuffer is null)
+                fileBuffer = new byte[Math.Max(500000, size)];
+            else if (fileBuffer.Length < size)
+                fileBuffer = new byte[size];
+
+            return ref fileBuffer;
+        }
     }
 }

+ 37 - 22
src/MeidoPhotoStudio.Plugin/MenuItem.cs

@@ -1,4 +1,4 @@
-using System.Globalization;
+using System.Globalization;
 using System.IO;
 using UnityEngine;
 
@@ -20,34 +20,48 @@ namespace MeidoPhotoStudio.Plugin
         public bool IsMod { get; private set; }
         public bool IsOfficialMod { get; private set; }
 
-        public static ModItem OfficialMod(string menuFile) => new ModItem()
-        {
-            MenuFile = menuFile, IsMod = true, IsOfficialMod = true, Priority = 1000f
-        };
+        public static ModItem OfficialMod(string menuFile) =>
+            new()
+            {
+                MenuFile = menuFile,
+                IsMod = true,
+                IsOfficialMod = true,
+                Priority = 1000f
+            };
 
-        public static ModItem Mod(string menuFile) => new ModItem() { MenuFile = menuFile, IsMod = true };
+        public static ModItem Mod(string menuFile) =>
+            new()
+            {
+                MenuFile = menuFile,
+                IsMod = true
+            };
 
-        public ModItem() { }
+        public static ModItem Deserialize(BinaryReader binaryReader) =>
+            new()
+            {
+                MenuFile = binaryReader.ReadNullableString(),
+                BaseMenuFile = binaryReader.ReadNullableString(),
+                IconFile = binaryReader.ReadNullableString(),
+                Name = binaryReader.ReadNullableString(),
+                Category = binaryReader.ReadNullableString(),
+                Priority = float.Parse(binaryReader.ReadNullableString()),
+                IsMod = binaryReader.ReadBoolean(),
+                IsOfficialMod = binaryReader.ReadBoolean()
+            };
 
-        public ModItem(string menuFile) => MenuFile = menuFile;
 
-        public override string ToString() => IsOfficialMod ? $"{Path.GetFileName(MenuFile)}#{BaseMenuFile}" : MenuFile;
+        public ModItem() { }
 
-        public static ModItem Deserialize(BinaryReader binaryReader) => new ModItem()
-        {
-            MenuFile = binaryReader.ReadNullableString(),
-            BaseMenuFile = binaryReader.ReadNullableString(),
-            IconFile = binaryReader.ReadNullableString(),
-            Name = binaryReader.ReadNullableString(),
-            Category = binaryReader.ReadNullableString(),
-            Priority = float.Parse(binaryReader.ReadNullableString()),
-            IsMod = binaryReader.ReadBoolean(),
-            IsOfficialMod = binaryReader.ReadBoolean()
-        };
+        public ModItem(string menuFile) =>
+            MenuFile = menuFile;
+
+        public override string ToString() =>
+            IsOfficialMod ? $"{Path.GetFileName(MenuFile)}#{BaseMenuFile}" : MenuFile;
 
         public void Serialize(BinaryWriter binaryWriter)
         {
-            if (IsOfficialMod) return;
+            if (IsOfficialMod)
+                return;
 
             binaryWriter.WriteNullableString(MenuFile);
             binaryWriter.WriteNullableString(BaseMenuFile);
@@ -65,6 +79,7 @@ namespace MeidoPhotoStudio.Plugin
         public int ID { get; set; }
         public string PrefabName { get; set; }
 
-        public override string ToString() => $"MYR_{ID}#{PrefabName}";
+        public override string ToString() =>
+            $"MYR_{ID}#{PrefabName}";
     }
 }

+ 194 - 126
src/MeidoPhotoStudio.Plugin/ModelUtility.cs

@@ -1,106 +1,111 @@
+using System;
+using System.Collections.Generic;
 using System.IO;
+using System.Linq;
 using System.Text;
-using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.Rendering;
-using System;
-using System.Linq;
+using static MeidoPhotoStudio.Plugin.MenuFileUtility;
 using Object = UnityEngine.Object;
 
 namespace MeidoPhotoStudio.Plugin
 {
-    using static MenuFileUtility;
-
     public static class ModelUtility
     {
         private enum IMode { None, ItemChange, TexChange }
 
         private static GameObject deploymentObject;
 
-        private static GameObject GetDeploymentObject()
-        {
-            if (deploymentObject) return deploymentObject;
-
-            if (!(deploymentObject = GameObject.Find("Deployment Object Parent")))
-                deploymentObject = new GameObject("Deployment Object Parent");
-            return deploymentObject;
-        }
-
         public static GameObject LoadMyRoomModel(MyRoomItem item)
         {
             var data = MyRoomCustom.PlacementData.GetData(item.ID);
             var gameObject = Object.Instantiate(data.GetPrefab());
-            if (gameObject)
+
+            if (!gameObject)
             {
-                var final = new GameObject();
-                gameObject.transform.SetParent(final.transform, true);
-                final.transform.SetParent(GetDeploymentObject().transform, false);
-                return final;
+                Utility.LogMessage($"Could not load MyRoomCreative model '{item.PrefabName}'");
+
+                return null;
             }
 
-            Utility.LogMessage($"Could not load MyRoomCreative model '{item.PrefabName}'");
+            var final = new GameObject();
 
-            return null;
+            gameObject.transform.SetParent(final.transform, true);
+            final.transform.SetParent(GetDeploymentObject().transform, false);
+
+            return final;
         }
 
         public static GameObject LoadBgModel(string bgName)
         {
             var gameObject = GameMain.Instance.BgMgr.CreateAssetBundle(bgName);
-            if (!gameObject) gameObject = Resources.Load<GameObject>("BG/" + bgName);
-            if (!gameObject) gameObject = Resources.Load<GameObject>("BG/2_0/" + bgName);
 
-            if (gameObject)
+            if (!gameObject)
+                gameObject = Resources.Load<GameObject>("BG/" + bgName);
+
+            if (!gameObject)
+                gameObject = Resources.Load<GameObject>("BG/2_0/" + bgName);
+
+            if (!gameObject)
             {
-                var final = Object.Instantiate(gameObject);
-                final.transform.localScale = Vector3.one * 0.1f;
-                return final;
+                Utility.LogMessage($"Could not load BG model '{bgName}'");
+
+                return null;
             }
 
-            Utility.LogMessage($"Could not load BG model '{bgName}'");
+            var final = Object.Instantiate(gameObject);
 
-            return null;
+            final.transform.localScale = Vector3.one * 0.1f;
+
+            return final;
         }
 
         public static GameObject LoadGameModel(string assetName)
         {
             var gameObject = GameMain.Instance.BgMgr.CreateAssetBundle(assetName);
-            if (!gameObject) gameObject = Resources.Load<GameObject>("Prefab/" + assetName);
-            if (!gameObject) gameObject = Resources.Load<GameObject>("BG/" + assetName);
 
-            if (gameObject)
+            if (!gameObject)
+                gameObject = Resources.Load<GameObject>("Prefab/" + assetName);
+
+            if (!gameObject)
+                gameObject = Resources.Load<GameObject>("BG/" + assetName);
+
+            if (!gameObject)
             {
-                var final = Object.Instantiate(gameObject);
-                final.transform.localPosition = Vector3.zero;
+                Utility.LogMessage($"Could not load game model '{assetName}'");
 
-                Renderer[] renderers = final.GetComponentsInChildren<Renderer>();
-                foreach (var renderer in renderers)
-                {
-                    if (renderer && renderer.gameObject.name.Contains("castshadow"))
-                        renderer.shadowCastingMode = ShadowCastingMode.Off;
-                }
+                return null;
+            }
 
-                Collider[] colliders = final.GetComponentsInChildren<Collider>();
-                foreach (var collider in colliders)
-                {
-                    if (collider) collider.enabled = false;
-                }
+            var final = Object.Instantiate(gameObject);
+            final.transform.localPosition = Vector3.zero;
 
-                if (final.transform.localScale != Vector3.one)
-                {
-                    var parent = new GameObject();
-                    final.transform.SetParent(parent.transform, true);
-                    return parent;
-                }
+            var renderers = final.GetComponentsInChildren<Renderer>();
 
-                return final;
-            }
+            foreach (var renderer in renderers)
+                if (renderer && renderer.gameObject.name.Contains("castshadow"))
+                    renderer.shadowCastingMode = ShadowCastingMode.Off;
 
-            Utility.LogMessage($"Could not load game model '{assetName}'");
+            var colliders = final.GetComponentsInChildren<Collider>();
 
-            return null;
+            foreach (var collider in colliders)
+                if (collider)
+                    collider.enabled = false;
+
+            if (final.transform.localScale != Vector3.one)
+            {
+                var parent = new GameObject();
+
+                final.transform.SetParent(parent.transform, true);
+
+                final = parent;
+            }
+
+            return final;
         }
 
-        public static GameObject LoadMenuModel(string menuFile) => LoadMenuModel(new ModItem(menuFile));
+        public static GameObject LoadMenuModel(string menuFile) =>
+            LoadMenuModel(new ModItem(menuFile));
 
         public static GameObject LoadMenuModel(ModItem modItem)
         {
@@ -108,40 +113,43 @@ namespace MeidoPhotoStudio.Plugin
 
             byte[] modelBuffer;
 
-            try { modelBuffer = ReadAFileBase(menu); }
+            try
+            {
+                modelBuffer = ReadAFileBase(menu);
+            }
             catch (Exception e)
             {
                 Utility.LogError($"Could not read menu file '{menu}' because {e.Message}\n{e.StackTrace}");
+
                 return null;
             }
 
-            if (ProcScriptBin(modelBuffer, out ModelInfo modelInfo))
+            if (ProcScriptBin(modelBuffer, out var modelInfo))
             {
                 if (InstantiateModel(modelInfo.ModelFile, out var finalModel))
                 {
                     IEnumerable<Renderer> renderers = GetRenderers(finalModel).ToList();
 
-                    foreach (MaterialChange matChange in modelInfo.MaterialChanges)
-                    {
-                        foreach (Renderer renderer in renderers)
-                        {
+                    foreach (var matChange in modelInfo.MaterialChanges)
+                        foreach (var renderer in renderers)
                             if (matChange.MaterialIndex < renderer.materials.Length)
-                            {
                                 renderer.materials[matChange.MaterialIndex] = ImportCM.LoadMaterial(
                                     matChange.MaterialFile, null, renderer.materials[matChange.MaterialIndex]
                                 );
-                            }
-                        }
-                    }
 
-                    if (!modItem.IsOfficialMod) return finalModel;
+                    if (!modItem.IsOfficialMod)
+                        return finalModel;
 
-                    try { modelBuffer = ReadOfficialMod(modItem.MenuFile); }
+                    try
+                    {
+                        modelBuffer = ReadOfficialMod(modItem.MenuFile);
+                    }
                     catch (Exception e)
                     {
                         Utility.LogError(
                             $"Could not read mod menu file '{modItem.MenuFile}' because {e.Message}\n{e.StackTrace}"
                         );
+
                         return null;
                     }
 
@@ -156,12 +164,25 @@ namespace MeidoPhotoStudio.Plugin
             return null;
         }
 
-        private static IEnumerable<Renderer> GetRenderers(GameObject gameObject) => gameObject.transform
+        private static GameObject GetDeploymentObject()
+        {
+            if (deploymentObject)
+                return deploymentObject;
+
+            if (!(deploymentObject = GameObject.Find("Deployment Object Parent")))
+                deploymentObject = new("Deployment Object Parent");
+
+            return deploymentObject;
+        }
+
+        private static IEnumerable<Renderer> GetRenderers(GameObject gameObject) =>
+            gameObject.transform
             .GetComponentsInChildren<Transform>(true)
             .Select(transform => transform.GetComponent<Renderer>())
             .Where(renderer => renderer && renderer.material).ToList();
 
-        private static GameObject CreateSeed() => Object.Instantiate(Resources.Load<GameObject>("seed"));
+        private static GameObject CreateSeed() =>
+            Object.Instantiate(Resources.Load<GameObject>("seed"));
 
         private static bool InstantiateModel(string modelFilename, out GameObject modelParent)
         {
@@ -169,18 +190,23 @@ namespace MeidoPhotoStudio.Plugin
 
             modelParent = default;
 
-            try { buffer = ReadAFileBase(modelFilename); }
+            try
+            {
+                buffer = ReadAFileBase(modelFilename);
+            }
             catch
             {
                 Utility.LogError($"Could not load model file '{modelFilename}'");
+
                 return false;
             }
 
             using var binaryReader = new BinaryReader(new MemoryStream(buffer), Encoding.UTF8);
 
-            if (binaryReader.ReadString() != "CM3D2_MESH")
+            if (binaryReader.ReadString() is not "CM3D2_MESH")
             {
                 Utility.LogError($"{modelFilename} is not a model file");
+
                 return false;
             }
 
@@ -204,13 +230,14 @@ namespace MeidoPhotoStudio.Plugin
                 // read bone data
                 for (var i = 0; i < boneCount; i++)
                 {
-                    GameObject bone = CreateSeed();
+                    var bone = CreateSeed();
+
                     bone.layer = 1;
                     bone.name = binaryReader.ReadString();
 
-                    if (binaryReader.ReadByte() != 0)
+                    if (binaryReader.ReadByte() is not 0)
                     {
-                        GameObject otherBone = CreateSeed();
+                        var otherBone = CreateSeed();
                         otherBone.name = bone.name + "_SCL_";
                         otherBone.transform.parent = bone.transform;
                         boneDict[bone.name + "$_SCL_"] = otherBone;
@@ -219,12 +246,14 @@ namespace MeidoPhotoStudio.Plugin
                     boneList.Add(bone);
                     boneDict[bone.name] = bone;
 
-                    if (bone.name == rootName) rootBone = bone;
+                    if (bone.name == rootName)
+                        rootBone = bone;
                 }
 
                 for (var i = 0; i < boneCount; i++)
                 {
                     var parentIndex = binaryReader.ReadInt32();
+
                     boneList[i].transform.parent = parentIndex >= 0
                         ? boneList[parentIndex].transform
                         : modelParent.transform;
@@ -232,28 +261,32 @@ namespace MeidoPhotoStudio.Plugin
 
                 for (var i = 0; i < boneCount; i++)
                 {
-                    Transform transform = boneList[i].transform;
+                    var transform = boneList[i].transform;
+
                     transform.localPosition = binaryReader.ReadVector3();
                     transform.localRotation = binaryReader.ReadQuaternion();
+
                     if (modelVersion >= 2001 && binaryReader.ReadBoolean())
                         transform.localScale = binaryReader.ReadVector3();
                 }
 
                 // read mesh data
                 var meshRenderer = rootBone.AddComponent<SkinnedMeshRenderer>();
+
                 meshRenderer.updateWhenOffscreen = true;
                 meshRenderer.skinnedMotionVectors = false;
                 meshRenderer.lightProbeUsage = LightProbeUsage.Off;
                 meshRenderer.reflectionProbeUsage = ReflectionProbeUsage.Off;
                 meshRenderer.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
 
-                Mesh sharedMesh = meshRenderer.sharedMesh = new Mesh();
+                var sharedMesh = meshRenderer.sharedMesh = new();
 
                 var vertCount = binaryReader.ReadInt32();
                 var subMeshCount = binaryReader.ReadInt32();
                 var meshBoneCount = binaryReader.ReadInt32();
 
                 var meshBones = new Transform[meshBoneCount];
+
                 for (var i = 0; i < meshBoneCount; i++)
                 {
                     var boneName = binaryReader.ReadString();
@@ -263,7 +296,8 @@ namespace MeidoPhotoStudio.Plugin
                     else
                     {
                         var keyName = boneName + "$_SCL_";
-                        GameObject bone = boneDict.ContainsKey(keyName) ? boneDict[keyName] : boneDict[boneName];
+                        var bone = boneDict.ContainsKey(keyName) ? boneDict[keyName] : boneDict[boneName];
+
                         meshBones[i] = bone.transform;
                     }
                 }
@@ -271,7 +305,9 @@ namespace MeidoPhotoStudio.Plugin
                 meshRenderer.bones = meshBones;
 
                 var bindPoses = new Matrix4x4[meshBoneCount];
-                for (var i = 0; i < meshBoneCount; i++) bindPoses[i] = binaryReader.ReadMatrix4x4();
+
+                for (var i = 0; i < meshBoneCount; i++)
+                    bindPoses[i] = binaryReader.ReadMatrix4x4();
 
                 sharedMesh.bindposes = bindPoses;
 
@@ -291,14 +327,19 @@ namespace MeidoPhotoStudio.Plugin
                 sharedMesh.uv = uv;
 
                 var tangentCount = binaryReader.ReadInt32();
+
                 if (tangentCount > 0)
                 {
                     var tangents = new Vector4[tangentCount];
-                    for (var i = 0; i < tangentCount; i++) tangents[i] = binaryReader.ReadVector4();
+
+                    for (var i = 0; i < tangentCount; i++)
+                        tangents[i] = binaryReader.ReadVector4();
+
                     sharedMesh.tangents = tangents;
                 }
 
                 var boneWeights = new BoneWeight[vertCount];
+
                 for (var i = 0; i < vertCount; i++)
                 {
                     boneWeights[i].boneIndex0 = binaryReader.ReadUInt16();
@@ -318,7 +359,10 @@ namespace MeidoPhotoStudio.Plugin
                 {
                     var pointCount = binaryReader.ReadInt32();
                     var triangles = new int[pointCount];
-                    for (var j = 0; j < pointCount; j++) triangles[j] = binaryReader.ReadUInt16();
+
+                    for (var j = 0; j < pointCount; j++)
+                        triangles[j] = binaryReader.ReadUInt16();
+
                     sharedMesh.SetTriangles(triangles, i);
                 }
 
@@ -327,7 +371,8 @@ namespace MeidoPhotoStudio.Plugin
 
                 var materials = new Material[materialCount];
 
-                for (var i = 0; i < materialCount; i++) materials[i] = ImportCM.ReadMaterial(binaryReader);
+                for (var i = 0; i < materialCount; i++)
+                    materials[i] = ImportCM.ReadMaterial(binaryReader);
 
                 meshRenderer.materials = materials;
 
@@ -339,9 +384,11 @@ namespace MeidoPhotoStudio.Plugin
             {
                 Utility.LogError($"Could not load mesh for '{modelFilename}' because {e.Message}\n{e.StackTrace}");
 
-                foreach (GameObject bone in boneList.Where(bone => bone)) Object.Destroy(bone);
+                foreach (var bone in boneList.Where(bone => bone))
+                    Object.Destroy(bone);
 
-                if (modelParent) Object.Destroy(modelParent);
+                if (modelParent)
+                    Object.Destroy(modelParent);
 
                 modelParent = null;
 
@@ -352,11 +399,13 @@ namespace MeidoPhotoStudio.Plugin
         private static bool ProcScriptBin(byte[] menuBuf, out ModelInfo modelInfo)
         {
             modelInfo = null;
+
             using var binaryReader = new BinaryReader(new MemoryStream(menuBuf), Encoding.UTF8);
 
-            if (binaryReader.ReadString() != "CM3D2_MENU") return false;
+            if (binaryReader.ReadString() is not "CM3D2_MENU")
+                return false;
 
-            modelInfo = new ModelInfo();
+            modelInfo = new();
 
             binaryReader.ReadInt32(); // file version
             binaryReader.ReadString(); // txt path
@@ -369,34 +418,34 @@ namespace MeidoPhotoStudio.Plugin
             {
                 while (true)
                 {
-                    int numberOfProps = binaryReader.ReadByte();
+                    var numberOfProps = binaryReader.ReadByte();
                     var menuPropString = string.Empty;
 
-                    if (numberOfProps != 0)
+                    if (numberOfProps is not 0)
                     {
                         for (var i = 0; i < numberOfProps; i++)
-                        {
                             menuPropString = $"{menuPropString}\"{binaryReader.ReadString()}\"";
-                        }
 
                         if (menuPropString != string.Empty)
                         {
                             var header = UTY.GetStringCom(menuPropString);
-                            string[] menuProps = UTY.GetStringList(menuPropString);
+                            var menuProps = UTY.GetStringList(menuPropString);
 
-                            if (header == "end") break;
+                            if (header is "end")
+                                break;
 
                             switch (header)
                             {
                                 case "マテリアル変更":
-                                {
                                     var matNo = int.Parse(menuProps[2]);
                                     var materialFile = menuProps[3];
+
                                     modelInfo.MaterialChanges.Add(new MaterialChange(matNo, materialFile));
+
                                     break;
-                                }
                                 case "additem":
                                     modelInfo.ModelFile = menuProps[1];
+
                                     break;
                             }
                         }
@@ -405,7 +454,10 @@ namespace MeidoPhotoStudio.Plugin
                         break;
                 }
             }
-            catch { return false; }
+            catch
+            {
+                return false;
+            }
 
             return true;
         }
@@ -417,7 +469,8 @@ namespace MeidoPhotoStudio.Plugin
 
             using (var binaryReader = new BinaryReader(new MemoryStream(cd), Encoding.UTF8))
             {
-                if (binaryReader.ReadString() != "CM3D2_MOD") return;
+                if (binaryReader.ReadString() is not "CM3D2_MOD")
+                    return;
 
                 binaryReader.ReadInt32();
                 binaryReader.ReadString();
@@ -425,23 +478,29 @@ namespace MeidoPhotoStudio.Plugin
                 binaryReader.ReadString();
                 binaryReader.ReadString();
                 binaryReader.ReadString();
+
                 var mpnValue = binaryReader.ReadString();
                 var mpn = MPN.null_mpn;
-                try { mpn = (MPN) Enum.Parse(typeof(MPN), mpnValue, true); }
-                catch
+
+                try
                 {
-                    /* ignored */
+                    mpn = (MPN)Enum.Parse(typeof(MPN), mpnValue, true);
                 }
+                catch { /* ignored */ }
 
-                if (mpn != MPN.null_mpn) binaryReader.ReadString();
+                if (mpn is not MPN.null_mpn)
+                    binaryReader.ReadString();
 
                 modData = binaryReader.ReadString();
+
                 var entryCount = binaryReader.ReadInt32();
+
                 for (var i = 0; i < entryCount; i++)
                 {
                     var key = binaryReader.ReadString();
                     var count = binaryReader.ReadInt32();
-                    byte[] value = binaryReader.ReadBytes(count);
+                    var value = binaryReader.ReadBytes(count);
+
                     matDict.Add(key, value);
                 }
             }
@@ -458,86 +517,95 @@ namespace MeidoPhotoStudio.Plugin
 
             List<Renderer> renderers = null;
 
-            while ((line = stringReader.ReadLine()) != null)
+            while ((line = stringReader.ReadLine()) is not null)
             {
-                string[] data = line.Split(new[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
+                var data = line.Split(new[] { '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
 
                 switch (data[0])
                 {
                     case "アイテム変更":
                     case "マテリアル変更":
                         mode = IMode.ItemChange;
+
                         break;
                     case "テクスチャ変更":
                         mode = IMode.TexChange;
+
                         break;
                 }
 
                 switch (mode)
                 {
                     case IMode.ItemChange:
-                    {
-                        if (data[0] == "スロット名") materialChange = true;
+                        if (data[0] is "スロット名")
+                            materialChange = true;
 
                         if (materialChange)
                         {
-                            if (data[0] == "マテリアル番号")
+                            if (data[0] is "マテリアル番号")
                             {
                                 materialIndex = int.Parse(data[1]);
 
                                 renderers ??= GetRenderers(go).ToList();
 
-                                foreach (Renderer renderer in renderers)
-                                {
+                                foreach (var renderer in renderers)
                                     if (materialIndex < renderer.materials.Length)
                                         material = renderer.materials[materialIndex];
-                                }
                             }
 
-                            if (!material) continue;
+                            if (!material)
+                                continue;
 
                             switch (data[0])
                             {
                                 case "テクスチャ設定":
                                     ChangeTex(materialIndex, data[1], data[2].ToLower());
+
                                     break;
                                 case "色設定":
                                     material.SetColor(
-                                        data[1],
-                                        new Color(
-                                            float.Parse(data[2]) / 255f, float.Parse(data[3]) / 255f,
-                                            float.Parse(data[4]) / 255f, float.Parse(data[5]) / 255f
-                                        )
-                                    );
+                                            data[1],
+                                            new Color(
+                                                float.Parse(data[2]) / 255f, float.Parse(data[3]) / 255f,
+                                                float.Parse(data[4]) / 255f, float.Parse(data[5]) / 255f
+                                                )
+                                            );
+
                                     break;
                                 case "数値設定":
                                     material.SetFloat(data[1], float.Parse(data[2]));
+
                                     break;
                             }
                         }
 
                         break;
-                    }
                     case IMode.TexChange:
-                    {
                         var matno = int.Parse(data[2]);
+
                         ChangeTex(matno, data[3], data[4].ToLower());
+
                         break;
-                    }
-                    case IMode.None: break;
-                    default: throw new ArgumentOutOfRangeException();
+                    case IMode.None:
+                        break;
+                    default:
+                        throw new ArgumentOutOfRangeException();
                 }
             }
 
             void ChangeTex(int matno, string prop, string filename)
             {
-                byte[] buf = matDict[filename.ToLowerInvariant()];
+                var buf = matDict[filename.ToLowerInvariant()];
                 var textureResource = new TextureResource(2, 2, TextureFormat.ARGB32, null, buf);
+
                 renderers ??= GetRenderers(go).ToList();
-                foreach (Renderer r in renderers)
+
+                foreach (var r in renderers)
                 {
                     r.materials[matno].SetTexture(prop, null);
-                    Texture2D texture2D = textureResource.CreateTexture2D();
+
+                    var texture2D = textureResource.CreateTexture2D();
+
                     texture2D.name = filename;
                     r.materials[matno].SetTexture(prop, texture2D);
                 }
@@ -546,7 +614,7 @@ namespace MeidoPhotoStudio.Plugin
 
         private class ModelInfo
         {
-            public List<MaterialChange> MaterialChanges { get; } = new List<MaterialChange>();
+            public List<MaterialChange> MaterialChanges { get; } = new();
             public string ModelFile { get; set; }
         }
 

+ 58 - 32
src/MeidoPhotoStudio.Plugin/MyGui.cs

@@ -13,6 +13,7 @@ namespace MeidoPhotoStudio.Plugin
         public static readonly GUIStyle SliderTextBoxStyle;
         public static readonly GUIStyle SliderThumbStyle;
         public static readonly GUIStyle SliderResetButtonStyle;
+
         private static readonly GUIStyle lineStyleWhite;
         private static readonly GUIStyle lineStyleBlack;
         private static readonly GUIStyle textureBoxStyle;
@@ -22,64 +23,89 @@ namespace MeidoPhotoStudio.Plugin
         {
             GUI.skin = null;
 
-            lineStyleWhite = new GUIStyle(GUI.skin.box)
+            lineStyleWhite = new(GUI.skin.box)
             {
-                margin = new RectOffset(0, 0, 8, 8),
-                normal = { background = Utility.MakeTex(2, 2, new Color(1f, 1f, 1f, 0.2f)) }
+                margin = new(0, 0, 8, 8),
+                normal = {
+                    background = Utility.MakeTex(2, 2, new(1f, 1f, 1f, 0.2f)),
+                },
             };
-            lineStyleWhite.padding = lineStyleWhite.border = new RectOffset(0, 0, 1, 1);
 
-            lineStyleBlack = new GUIStyle(lineStyleWhite)
+            lineStyleWhite.padding = lineStyleWhite.border = new(0, 0, 1, 1);
+
+            lineStyleBlack = new(lineStyleWhite)
             {
-                normal = { background = Utility.MakeTex(2, 2, new Color(0f, 0f, 0f, 0.3f)) }
+                normal = {
+                    background = Utility.MakeTex(2, 2, new(0f, 0f, 0f, 0.3f)),
+                },
             };
 
-            textureBoxStyle = new GUIStyle(GUI.skin.box)
+            textureBoxStyle = new(GUI.skin.box)
             {
-                normal = { background = Utility.MakeTex(2, 2, new Color(0f, 0f, 0f, 0f)) }
+                normal = {
+                    background = Utility.MakeTex(2, 2, new(0f, 0f, 0f, 0f)),
+                },
             };
-            textureBoxStyle.padding = textureBoxStyle.margin = new RectOffset(0, 0, 0, 0);
 
-            headerLabelStyle = new GUIStyle(GUI.skin.label)
+            textureBoxStyle.padding = textureBoxStyle.margin = new(0, 0, 0, 0);
+
+            headerLabelStyle = new(GUI.skin.label)
             {
-                padding = new RectOffset(7, 0, 0, -5),
-                normal = { textColor = Color.white },
-                fontSize = 14
+                padding = new(7, 0, 0, -5),
+                normal = {
+                    textColor = Color.white,
+                },
+                fontSize = 14,
             };
 
-            SliderLabelStyle = new GUIStyle(GUI.skin.label)
+            SliderLabelStyle = new(GUI.skin.label)
             {
                 alignment = TextAnchor.LowerLeft,
                 fontSize = 13,
-                normal = { textColor = Color.white }
+                normal = {
+                    textColor = Color.white,
+                },
+            };
+
+            SliderStyle = new(GUI.skin.horizontalSlider);
+            SliderStyleNoLabel = new(SliderStyle)
+            {
+                margin = {
+                    top = 10,
+                },
+            };
+
+            SliderTextBoxStyle = new(GUI.skin.textField)
+            {
+                fontSize = 12,
             };
-            SliderStyle = new GUIStyle(GUI.skin.horizontalSlider);
-            SliderStyleNoLabel = new GUIStyle(SliderStyle) { margin = { top = 10 } };
-            SliderTextBoxStyle = new GUIStyle(GUI.skin.textField) { fontSize = 12, };
-            SliderResetButtonStyle = new GUIStyle(GUI.skin.button)
+
+            SliderResetButtonStyle = new(GUI.skin.button)
             {
                 alignment = TextAnchor.MiddleRight,
-                fontSize = 10
+                fontSize = 10,
             };
-            SliderThumbStyle = new GUIStyle(GUI.skin.horizontalSliderThumb);
-        }
 
-        private static void Line(GUIStyle style) => GUILayout.Box(GUIContent.none, style, GUILayout.Height(1));
+            SliderThumbStyle = new(GUI.skin.horizontalSliderThumb);
+        }
 
-        public static void WhiteLine() => Line(lineStyleWhite);
+        public static void WhiteLine() =>
+            Line(lineStyleWhite);
 
-        public static void BlackLine() => Line(lineStyleBlack);
+        public static void BlackLine() =>
+            Line(lineStyleBlack);
 
-        public static void DrawTexture(Texture texture, params GUILayoutOption[] layoutOptions)
-        {
+        public static void DrawTexture(Texture texture, params GUILayoutOption[] layoutOptions) =>
             GUILayout.Box(texture, textureBoxStyle, layoutOptions);
-        }
 
-        public static int ClampFont(int size, int min, int max) => Mathf.Clamp(Utility.GetPix(size), min, max);
+        public static int ClampFont(int size, int min, int max) =>
+            Mathf.Clamp(Utility.GetPix(size), min, max);
 
-        public static void Header(string text, params GUILayoutOption[] layoutOptions)
-        {
+        public static void Header(string text, params GUILayoutOption[] layoutOptions) =>
             GUILayout.Label(text, headerLabelStyle, layoutOptions);
-        }
+
+        private static void Line(GUIStyle style) =>
+            GUILayout.Box(GUIContent.none, style, GUILayout.Height(1));
+
     }
 }

+ 4 - 4
src/MeidoPhotoStudio.Plugin/Patchers/AllProcPropSeqStartPatcher.cs

@@ -10,15 +10,15 @@ namespace MeidoPhotoStudio.Plugin
 
         [HarmonyPatch(typeof(Maid), nameof(Maid.AllProcPropSeqStart))]
         [HarmonyPostfix]
-        private static void NotifyProcStart(Maid __instance)
-        {
+        private static void NotifyProcStart(Maid __instance) =>
             SequenceStart?.Invoke(null, new ProcStartEventArgs(__instance));
-        }
     }
 
     public class ProcStartEventArgs : EventArgs
     {
         public readonly Maid maid;
-        public ProcStartEventArgs(Maid maid) => this.maid = maid;
+
+        public ProcStartEventArgs(Maid maid) =>
+            this.maid = maid;
     }
 }

+ 4 - 2
src/MeidoPhotoStudio.Plugin/Patchers/BgMgrPatcher.cs

@@ -11,11 +11,13 @@ namespace MeidoPhotoStudio.Plugin
         [HarmonyPatch(typeof(BgMgr), nameof(BgMgr.ChangeBg))]
         [HarmonyPatch(typeof(BgMgr), nameof(BgMgr.ChangeBgMyRoom))]
         [HarmonyPrefix]
-        private static void NotifyBeginChangeBg() => ChangeBgBegin?.Invoke(null, EventArgs.Empty);
+        private static void NotifyBeginChangeBg() =>
+            ChangeBgBegin?.Invoke(null, EventArgs.Empty);
 
         [HarmonyPatch(typeof(BgMgr), nameof(BgMgr.ChangeBg))]
         [HarmonyPatch(typeof(BgMgr), nameof(BgMgr.ChangeBgMyRoom))]
         [HarmonyPostfix]
-        private static void NotifyEndChangeBg() => ChangeBgEnd?.Invoke(null, EventArgs.Empty);
+        private static void NotifyEndChangeBg() =>
+            ChangeBgEnd?.Invoke(null, EventArgs.Empty);
     }
 }

+ 1 - 1
src/MeidoPhotoStudio.Plugin/Serialization/ISerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {

+ 1 - 1
src/MeidoPhotoStudio.Plugin/Serialization/ISimpleSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {

+ 11 - 15
src/MeidoPhotoStudio.Plugin/Serialization/SceneMetadata.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -9,28 +9,24 @@ namespace MeidoPhotoStudio.Plugin
         public int MaidCount { get; set; }
         public bool MMConverted { get; set; }
 
-        public void WriteMetadata(BinaryWriter writer)
-        {
-            writer.Write(Version);
-            writer.Write(Environment);
-            writer.Write(MaidCount);
-            writer.Write(MMConverted);
-        }
-
-        public static SceneMetadata ReadMetadata(BinaryReader reader)
-        {
-            return new()
+        public static SceneMetadata ReadMetadata(BinaryReader reader) =>
+            new()
             {
                 Version = reader.ReadVersion(),
                 Environment = reader.ReadBoolean(),
                 MaidCount = reader.ReadInt32(),
                 MMConverted = reader.ReadBoolean()
             };
+
+        public void WriteMetadata(BinaryWriter writer)
+        {
+            writer.Write(Version);
+            writer.Write(Environment);
+            writer.Write(MaidCount);
+            writer.Write(MMConverted);
         }
 
-        public void Deconstruct(
-            out short version, out bool environment, out int maidCount, out bool mmConverted
-        )
+        public void Deconstruct(out short version, out bool environment, out int maidCount, out bool mmConverted)
         {
             version = Version;
             environment = Environment;

+ 20 - 13
src/MeidoPhotoStudio.Plugin/Serialization/Serialization.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
@@ -13,30 +13,37 @@ namespace MeidoPhotoStudio.Plugin
 
         static Serialization()
         {
-            var types = (from t in typeof(MeidoPhotoStudio).Assembly.GetTypes()
-                let baseType = t.BaseType
-                where !t.IsAbstract && !t.IsInterface && baseType?.IsGenericType == true
-                select new { type = t, baseType }).ToArray();
+            var types =
+                (from t in typeof(MeidoPhotoStudio).Assembly.GetTypes()
+                 let baseType = t.BaseType
+                 where !t.IsAbstract && !t.IsInterface && baseType?.IsGenericType == true
+                 select new { type = t, baseType }).ToArray();
 
             Serializers = types.Where(t => t.baseType.GetGenericTypeDefinition() == typeof(Serializer<>))
-                .Select(t => new {t.type, arg = t.baseType.GetGenericArguments()[0]})
+                .Select(t => new { t.type, arg = t.baseType.GetGenericArguments()[0] })
                 .ToDictionary(x => x.arg, x => (ISerializer)Activator.CreateInstance(x.type));
 
             SimpleSerializers = types.Where(t => t.baseType.GetGenericTypeDefinition() == typeof(SimpleSerializer<>))
-                .Select(t => new {t.type, arg = t.baseType.GetGenericArguments()[0]})
+                .Select(t => new { t.type, arg = t.baseType.GetGenericArguments()[0] })
                 .ToDictionary(x => x.arg, x => (ISimpleSerializer)Activator.CreateInstance(x.type));
         }
 
-        public static Serializer<T> Get<T>() => Serializers[typeof(T)] as Serializer<T>;
+        public static Serializer<T> Get<T>() =>
+            Serializers[typeof(T)] as Serializer<T>;
 
-        public static ISerializer Get(Type type) => Serializers[type];
+        public static ISerializer Get(Type type) =>
+            Serializers[type];
 
-        public static SimpleSerializer<T> GetSimple<T>() => SimpleSerializers[typeof(T)] as SimpleSerializer<T>;
+        public static SimpleSerializer<T> GetSimple<T>() =>
+            SimpleSerializers[typeof(T)] as SimpleSerializer<T>;
 
-        public static ISimpleSerializer GetSimple(Type type) => SimpleSerializers[type];
+        public static ISimpleSerializer GetSimple(Type type) =>
+            SimpleSerializers[type];
 
-        public static short ReadVersion(this BinaryReader reader) => reader.ReadInt16();
+        public static short ReadVersion(this BinaryReader reader) =>
+            reader.ReadInt16();
 
-        public static void WriteVersion(this BinaryWriter writer, short version) => writer.Write(version);
+        public static void WriteVersion(this BinaryWriter writer, short version) =>
+            writer.Write(version);
     }
 }

+ 6 - 4
src/MeidoPhotoStudio.Plugin/Serialization/Serializer.cs

@@ -1,15 +1,17 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public abstract class Serializer<T> : ISerializer
     {
-        void ISerializer.Serialize(object obj, BinaryWriter writer) => Serialize((T) obj, writer);
+        void ISerializer.Serialize(object obj, BinaryWriter writer) =>
+            Serialize((T)obj, writer);
 
-        void ISerializer.Deserialize(object obj, BinaryReader reader, SceneMetadata metadata)
-            => Deserialize((T) obj, reader, metadata);
+        void ISerializer.Deserialize(object obj, BinaryReader reader, SceneMetadata metadata) =>
+            Deserialize((T)obj, reader, metadata);
 
         public abstract void Serialize(T obj, BinaryWriter writer);
+
         public abstract void Deserialize(T obj, BinaryReader reader, SceneMetadata metadata);
     }
 }

+ 4 - 4
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/AttachPointInfoSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -10,7 +10,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             writer.WriteVersion(version);
 
-            writer.Write((int) info.AttachPoint);
+            writer.Write((int)info.AttachPoint);
             writer.Write(info.MaidIndex);
         }
 
@@ -18,10 +18,10 @@ namespace MeidoPhotoStudio.Plugin
         {
             _ = reader.ReadVersion();
 
-            var attachPoint = (AttachPoint) reader.ReadInt32();
+            var attachPoint = (AttachPoint)reader.ReadInt32();
             var maidIndex = reader.ReadInt32();
 
-            return new AttachPointInfo(attachPoint, string.Empty, maidIndex);
+            return new(attachPoint, string.Empty, maidIndex);
         }
     }
 }

+ 1 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/CameraInfoSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {

+ 16 - 12
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/DragPointLightSerializer.cs

@@ -1,22 +1,28 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public class DragPointLightSerializer : Serializer<DragPointLight>
     {
         private const short version = 1;
-        private static Serializer<LightProperty> LightPropertySerializer => Serialization.Get<LightProperty>();
+
+        private static Serializer<LightProperty> LightPropertySerializer =>
+            Serialization.Get<LightProperty>();
+
+        private static LightProperty[] GetLightProperties(DragPointLight light) =>
+            Utility.GetFieldValue<DragPointLight, LightProperty[]>(light, "LightProperties");
 
         public override void Serialize(DragPointLight light, BinaryWriter writer)
         {
             writer.WriteVersion(version);
 
-            LightProperty[] lightList = GetLightProperties(light);
+            var lightList = GetLightProperties(light);
 
-            for (var i = 0; i < 3; i++) LightPropertySerializer.Serialize(lightList[i], writer);
+            for (var i = 0; i < 3; i++)
+                LightPropertySerializer.Serialize(lightList[i], writer);
 
             writer.Write(light.MyObject.position);
-            writer.Write((int) light.SelectedLightType);
+            writer.Write((int)light.SelectedLightType);
             writer.Write(light.IsColourMode);
             writer.Write(light.IsDisabled);
         }
@@ -25,17 +31,15 @@ namespace MeidoPhotoStudio.Plugin
         {
             _ = reader.ReadVersion();
 
-            LightProperty[] lightList = GetLightProperties(light);
-            
-            for (var i = 0; i < 3; i++) LightPropertySerializer.Deserialize(lightList[i], reader, metadata);
+            var lightList = GetLightProperties(light);
+
+            for (var i = 0; i < 3; i++)
+                LightPropertySerializer.Deserialize(lightList[i], reader, metadata);
 
             light.MyObject.position = reader.ReadVector3();
-            light.SetLightType((DragPointLight.MPSLightType) reader.ReadInt32());
+            light.SetLightType((DragPointLight.MPSLightType)reader.ReadInt32());
             light.IsColourMode = reader.ReadBoolean();
             light.IsDisabled = reader.ReadBoolean();
         }
-
-        private static LightProperty[] GetLightProperties(DragPointLight light)
-            => Utility.GetFieldValue<DragPointLight, LightProperty[]>(light, "LightProperties");
     }
 }

+ 2 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/BloomEffectSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -23,6 +23,7 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var active = reader.ReadBoolean();
+
             effect.BloomValue = reader.ReadSingle();
             effect.BlurIterations = reader.ReadInt32();
             effect.BloomThresholdColour = reader.ReadColour();

+ 2 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/BlurEffectSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -20,6 +20,7 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var active = reader.ReadBoolean();
+
             effect.BlurSize = reader.ReadSingle();
 
             effect.SetEffectActive(active);

+ 2 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/DepthOfFieldEffectSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -24,6 +24,7 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var active = reader.ReadBoolean();
+
             effect.FocalLength = reader.ReadSingle();
             effect.FocalSize = reader.ReadSingle();
             effect.Aperture = reader.ReadSingle();

+ 2 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/FogEffectSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -24,6 +24,7 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var active = reader.ReadBoolean();
+
             effect.Distance = reader.ReadSingle();
             effect.Density = reader.ReadSingle();
             effect.HeightScale = reader.ReadSingle();

+ 2 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/SepiaToneEffectSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -9,6 +9,7 @@ namespace MeidoPhotoStudio.Plugin
         public override void Serialize(SepiaToneEffectManger effect, BinaryWriter writer)
         {
             writer.Write(SepiaToneEffectManger.header);
+
             writer.WriteVersion(version);
 
             writer.Write(effect.Active);

+ 2 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/EffectSerializers/VignetteEffectSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -23,6 +23,7 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var active = reader.ReadBoolean();
+
             manager.Intensity = reader.ReadSingle();
             manager.Blur = reader.ReadSingle();
             manager.BlurSpread = reader.ReadSingle();

+ 1 - 1
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/LightPropertySerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {

+ 16 - 9
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/CameraManagerSerializer.cs

@@ -1,24 +1,33 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public class CameraManagerSerializer : Serializer<CameraManager>
     {
         private const short version = 1;
-        private static Serializer<CameraInfo> InfoSerializer => Serialization.Get<CameraInfo>();
+
         private static readonly CameraInfo dummyInfo = new();
 
+        private static Serializer<CameraInfo> InfoSerializer =>
+            Serialization.Get<CameraInfo>();
+
+        private static CameraInfo[] GetCameraInfos(CameraManager manager) =>
+            Utility.GetFieldValue<CameraManager, CameraInfo[]>(manager, "cameraInfos");
+
         public override void Serialize(CameraManager manager, BinaryWriter writer)
         {
             writer.Write(CameraManager.header);
             writer.WriteVersion(version);
 
-            CameraInfo[] cameraInfos = GetCameraInfos(manager);
+            var cameraInfos = GetCameraInfos(manager);
+
             cameraInfos[manager.CurrentCameraIndex].UpdateInfo(CameraUtility.MainCamera);
 
             writer.Write(manager.CurrentCameraIndex);
             writer.Write(manager.CameraCount);
-            foreach (var info in cameraInfos) InfoSerializer.Serialize(info, writer);
+
+            foreach (var info in cameraInfos)
+                InfoSerializer.Serialize(info, writer);
 
             CameraUtility.StopAll();
         }
@@ -32,19 +41,17 @@ namespace MeidoPhotoStudio.Plugin
             manager.CurrentCameraIndex = reader.ReadInt32();
 
             var cameraCount = reader.ReadInt32();
+            var cameraInfos = GetCameraInfos(manager);
 
-            CameraInfo[] cameraInfos = GetCameraInfos(manager);
             for (var i = 0; i < cameraCount; i++)
                 InfoSerializer.Deserialize(i >= manager.CameraCount ? dummyInfo : cameraInfos[i], reader, metadata);
 
-            if (metadata.Environment) return;
+            if (metadata.Environment)
+                return;
 
             cameraInfos[manager.CurrentCameraIndex].Apply(camera);
 
             CameraUtility.StopAll();
         }
-
-        private static CameraInfo[] GetCameraInfos(CameraManager manager)
-            => Utility.GetFieldValue<CameraManager, CameraInfo[]>(manager, "cameraInfos");
     }
 }

+ 7 - 6
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/EffectManagerSerializer.cs

@@ -1,4 +1,4 @@
-using System;
+using System;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
@@ -9,6 +9,9 @@ namespace MeidoPhotoStudio.Plugin
     {
         private const short version = 1;
 
+        private static Dictionary<Type, IEffectManager> GetEffectManagers(EffectManager manager) =>
+            Utility.GetFieldValue<EffectManager, Dictionary<Type, IEffectManager>>(manager, "EffectManagers");
+
         public override void Serialize(EffectManager manager, BinaryWriter writer)
         {
             writer.Write(EffectManager.header);
@@ -24,20 +27,18 @@ namespace MeidoPhotoStudio.Plugin
         {
             _ = reader.ReadVersion();
 
-            Dictionary<string, IEffectManager> headerToManager = GetEffectManagers(manager).ToDictionary(
-                x => (string) x.Key.GetField("header").GetValue(null),
+            var headerToManager = GetEffectManagers(manager).ToDictionary(
+                x => (string)x.Key.GetField("header").GetValue(null),
                 y => y.Value
             );
 
             string header;
+
             while ((header = reader.ReadString()) != EffectManager.footer)
             {
                 var effectManager = headerToManager[header];
                 Serialization.Get(effectManager.GetType()).Deserialize(effectManager, reader, metadata);
             }
         }
-
-        private static Dictionary<Type, IEffectManager> GetEffectManagers(EffectManager manager)
-            => Utility.GetFieldValue<EffectManager, Dictionary<Type, IEffectManager>>(manager, "EffectManagers");
     }
 }

+ 14 - 12
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/EnvironmentManagerSerializer.cs

@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System;
 using System.IO;
 using UnityEngine;
 
@@ -9,7 +8,11 @@ namespace MeidoPhotoStudio.Plugin
     {
         private const short version = 1;
 
-        private static SimpleSerializer<TransformDTO> TransformDtoSerializer => Serialization.GetSimple<TransformDTO>();
+        private static SimpleSerializer<TransformDTO> TransformDtoSerializer =>
+            Serialization.GetSimple<TransformDTO>();
+
+        private static Transform GetBgTransform(EnvironmentManager manager) =>
+            Utility.GetFieldValue<EnvironmentManager, Transform>(manager, "bg");
 
         public override void Serialize(EnvironmentManager manager, BinaryWriter writer)
         {
@@ -29,12 +32,10 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var bgAsset = reader.ReadString();
-
             var transformDto = TransformDtoSerializer.Deserialize(reader, metadata);
-
             var creativeBg = Utility.IsGuidString(bgAsset);
 
-            List<string> bgList = creativeBg
+            var bgList = creativeBg
                 ? Constants.MyRoomCustomBGList.ConvertAll(kvp => kvp.Key)
                 : Constants.BGList;
 
@@ -44,7 +45,8 @@ namespace MeidoPhotoStudio.Plugin
 
             var validBg = assetIndex >= 0;
 
-            if (validBg) bgAsset = bgList[assetIndex];
+            if (validBg)
+                bgAsset = bgList[assetIndex];
             else
             {
                 Utility.LogWarning($"Could not load BG '{bgAsset}'");
@@ -54,18 +56,18 @@ namespace MeidoPhotoStudio.Plugin
 
             manager.ChangeBackground(bgAsset, creativeBg);
 
-            if (!validBg) return;
+            if (!validBg)
+                return;
 
             var bg = GetBgTransform(manager);
 
-            if (!bg) return;
+            if (!bg)
+                return;
 
+            // TODO: Use transform.SetPositionAndRotation
             bg.position = transformDto.Position;
             bg.rotation = transformDto.Rotation;
             bg.localScale = transformDto.LocalScale;
         }
-
-        private static Transform GetBgTransform(EnvironmentManager manager)
-            => Utility.GetFieldValue<EnvironmentManager, Transform>(manager, "bg");
     }
 }

+ 15 - 10
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/LightManagerSerializer.cs

@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
@@ -6,16 +6,24 @@ namespace MeidoPhotoStudio.Plugin
     public class LightManagerSerializer : Serializer<LightManager>
     {
         private const short version = 1;
-        private static Serializer<DragPointLight> LightSerializer => Serialization.Get<DragPointLight>();
+
+        private static Serializer<DragPointLight> LightSerializer =>
+            Serialization.Get<DragPointLight>();
+
+        private static List<DragPointLight> GetLightList(LightManager manager) =>
+            Utility.GetFieldValue<LightManager, List<DragPointLight>>(manager, "lightList");
 
         public override void Serialize(LightManager manager, BinaryWriter writer)
         {
             writer.Write(LightManager.header);
             writer.WriteVersion(version);
 
-            List<DragPointLight> list = GetLightList(manager);
+            var list = GetLightList(manager);
+
             writer.Write(list.Count);
-            foreach (var light in list) LightSerializer.Serialize(light, writer);
+
+            foreach (var light in list)
+                LightSerializer.Serialize(light, writer);
         }
 
         public override void Deserialize(LightManager manager, BinaryReader reader, SceneMetadata metadata)
@@ -26,18 +34,15 @@ namespace MeidoPhotoStudio.Plugin
 
             var lightCount = reader.ReadInt32();
 
-            List<DragPointLight> list = GetLightList(manager);
-            
-            
+            var list = GetLightList(manager);
+
             LightSerializer.Deserialize(list[0], reader, metadata);
+
             for (var i = 1; i < lightCount; i++)
             {
                 manager.AddLight();
                 LightSerializer.Deserialize(list[i], reader, metadata);
             }
         }
-
-        private static List<DragPointLight> GetLightList(LightManager manager)
-            => Utility.GetFieldValue<LightManager, List<DragPointLight>>(manager, "lightList");
     }
 }

+ 8 - 5
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/MeidoManagerSerializer.cs

@@ -1,4 +1,3 @@
-using System.Collections.Generic;
 using System.IO;
 using UnityEngine;
 
@@ -7,14 +6,16 @@ namespace MeidoPhotoStudio.Plugin
     public class MeidoManagerSerializer : Serializer<MeidoManager>
     {
         private const short version = 1;
-        private static Serializer<Meido> MeidoSerializer => Serialization.Get<Meido>();
+
+        private static Serializer<Meido> MeidoSerializer =>
+            Serialization.Get<Meido>();
 
         public override void Serialize(MeidoManager manager, BinaryWriter writer)
         {
             writer.Write(MeidoManager.header);
             writer.WriteVersion(version);
 
-            List<Meido> meidoList = manager.ActiveMeidoList;
+            var meidoList = manager.ActiveMeidoList;
 
             var meidoCount = meidoList.Count;
 
@@ -31,7 +32,8 @@ namespace MeidoPhotoStudio.Plugin
             {
                 MeidoSerializer.Serialize(meido, writer);
 
-                if (!globalGravity || meidoCount <= 0) continue;
+                if (!globalGravity || meidoCount <= 0)
+                    continue;
 
                 // Get gravity and skirt control positions to apply to meidos past the meido count
                 if (!hairMeidoFound && meido.HairGravityControl.Valid)
@@ -72,7 +74,8 @@ namespace MeidoPhotoStudio.Plugin
             var skirtPosition = reader.ReadVector3();
             Utility.SetFieldValue(manager, "globalGravity", globalGravity);
 
-            if (!globalGravity) return;
+            if (!globalGravity)
+                return;
 
             foreach (var meido in manager.ActiveMeidoList)
             {

+ 6 - 2
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/MessageWindowManagerSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -24,10 +24,14 @@ namespace MeidoPhotoStudio.Plugin
             _ = reader.ReadVersion();
 
             var showingMessage = reader.ReadBoolean();
+
             manager.FontSize = reader.ReadInt32();
+
             var messageName = reader.ReadString();
             var messageText = reader.ReadString();
-            if (showingMessage) manager.ShowMessage(messageName, messageText);
+
+            if (showingMessage)
+                manager.ShowMessage(messageName, messageText);
         }
     }
 }

+ 35 - 31
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/ManagerSerializers/PropManagerSerializer.cs

@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
@@ -7,18 +7,44 @@ namespace MeidoPhotoStudio.Plugin
     {
         private const short version = 1;
 
-        private static SimpleSerializer<DragPointPropDTO> DragPointDtoSerializer
-            => Serialization.GetSimple<DragPointPropDTO>();
+        private static SimpleSerializer<DragPointPropDTO> DragPointDtoSerializer =>
+            Serialization.GetSimple<DragPointPropDTO>();
+
+        private static List<DragPointProp> GetPropList(PropManager manager) =>
+            Utility.GetFieldValue<PropManager, List<DragPointProp>>(manager, "propList");
+
+        private static void Apply(PropManager manager, DragPointProp prop, DragPointPropDTO dto)
+        {
+            var (transformDto, attachPointInfo, shadowCasting) = dto;
+
+            prop.ShadowCasting = shadowCasting;
+
+            var transform = prop.MyObject;
+
+            if (attachPointInfo.AttachPoint != AttachPoint.None)
+            {
+                manager.AttachProp(prop, attachPointInfo.AttachPoint, attachPointInfo.MaidIndex);
+                transform.localPosition = transformDto.LocalPosition;
+                transform.localRotation = transformDto.LocalRotation;
+            }
+
+            // TODO: Use transform.SetRotationAndPosition or whatever it's called.
+            transform.position = transformDto.Position;
+            transform.rotation = transformDto.Rotation;
+            transform.localScale = transformDto.LocalScale;
+        }
 
         public override void Serialize(PropManager manager, BinaryWriter writer)
         {
             writer.Write(PropManager.header);
             writer.WriteVersion(version);
 
-            List<DragPointProp> propList = GetPropList(manager);
+            var propList = GetPropList(manager);
 
             writer.Write(propList.Count);
-            foreach (var prop in propList) DragPointDtoSerializer.Serialize(new DragPointPropDTO(prop), writer);
+
+            foreach (var prop in propList)
+                DragPointDtoSerializer.Serialize(new DragPointPropDTO(prop), writer);
         }
 
         public override void Deserialize(PropManager manager, BinaryReader reader, SceneMetadata metadata)
@@ -27,43 +53,21 @@ namespace MeidoPhotoStudio.Plugin
 
             manager.DeleteAllProps();
 
-            List<DragPointProp> propList = GetPropList(manager);
-
+            var propList = GetPropList(manager);
             var propCount = reader.ReadInt32();
             var propIndex = 0;
+
             for (var i = 0; i < propCount; i++)
             {
                 var dragPointPropDto = DragPointDtoSerializer.Deserialize(reader, metadata);
 
-                if (!manager.AddFromPropInfo(dragPointPropDto.PropInfo)) continue;
+                if (!manager.AddFromPropInfo(dragPointPropDto.PropInfo))
+                    continue;
 
                 Apply(manager, propList[propIndex], dragPointPropDto);
 
                 propIndex++;
             }
         }
-
-        private static void Apply(PropManager manager, DragPointProp prop, DragPointPropDTO dto)
-        {
-            var (transformDto, attachPointInfo, shadowCasting) = dto;
-
-            prop.ShadowCasting = shadowCasting;
-
-            var transform = prop.MyObject;
-
-            if (attachPointInfo.AttachPoint != AttachPoint.None)
-            {
-                manager.AttachProp(prop, attachPointInfo.AttachPoint, attachPointInfo.MaidIndex);
-                transform.localPosition = transformDto.LocalPosition;
-                transform.localRotation = transformDto.LocalRotation;
-            }
-
-            transform.position = transformDto.Position;
-            transform.rotation = transformDto.Rotation;
-            transform.localScale = transformDto.LocalScale;
-        }
-
-        private static List<DragPointProp> GetPropList(PropManager manager)
-            => Utility.GetFieldValue<PropManager, List<DragPointProp>>(manager, "propList");
     }
 }

+ 107 - 70
src/MeidoPhotoStudio.Plugin/Serialization/Serializers/MeidoSerializer.cs

@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.IO;
 using System.Linq;
 using System.Text;
@@ -13,57 +13,11 @@ namespace MeidoPhotoStudio.Plugin
         private const short bodyVersion = 2;
         private const short clothingVersion = 1;
 
-        private static SimpleSerializer<PoseInfo> PoseInfoSerializer => Serialization.GetSimple<PoseInfo>();
+        private static SimpleSerializer<PoseInfo> PoseInfoSerializer =>
+            Serialization.GetSimple<PoseInfo>();
 
-        private static SimpleSerializer<TransformDTO> TransformDtoSerializer => Serialization.GetSimple<TransformDTO>();
-
-        public override void Serialize(Meido meido, BinaryWriter writer)
-        {
-            var maid = meido.Maid;
-
-            using var memoryStream = new MemoryStream();
-            using var tempWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
-
-            tempWriter.WriteVersion(version);
-
-            TransformDtoSerializer.Serialize(new TransformDTO(maid.transform), tempWriter);
-
-            SerializeHead(meido, tempWriter);
-
-            SerializeBody(meido, tempWriter);
-
-            SerializeClothing(meido, tempWriter);
-
-            writer.Write(memoryStream.Length);
-            writer.Write(memoryStream.ToArray());
-        }
-
-        public override void Deserialize(Meido meido, BinaryReader reader, SceneMetadata metadata)
-        {
-            var maid = meido.Maid;
-
-            maid.GetAnimation().Stop();
-            meido.DetachAllMpnAttach();
-            meido.StopBlink();
-
-            reader.ReadInt64(); // data length
-
-            _ = reader.ReadVersion();
-
-            var transformDto = TransformDtoSerializer.Deserialize(reader, metadata);
-            var maidTransform = maid.transform;
-            maidTransform.position = transformDto.Position;
-            maidTransform.rotation = transformDto.Rotation;
-            maidTransform.localScale = transformDto.LocalScale;
-
-            meido.IKManager.SetDragPointScale(maidTransform.localScale.x);
-
-            DeserializeHead(meido, reader, metadata);
-
-            DeserializeBody(meido, reader, metadata);
-
-            DeserializeClothing(meido, reader, metadata);
-        }
+        private static SimpleSerializer<TransformDTO> TransformDtoSerializer =>
+            Serialization.GetSimple<TransformDTO>();
 
         private static void SerializeHead(Meido meido, BinaryWriter writer)
         {
@@ -85,8 +39,10 @@ namespace MeidoPhotoStudio.Plugin
             writer.Write(meido.EyeToCam);
 
             // face
-            Dictionary<string, float> faceDict = meido.SerializeFace();
+            var faceDict = meido.SerializeFace();
+
             writer.Write(faceDict.Count);
+
             foreach (var (hash, value) in faceDict)
             {
                 writer.Write(hash);
@@ -100,17 +56,20 @@ namespace MeidoPhotoStudio.Plugin
 
             // pose
             var poseBuffer = meido.SerializePose(true);
+
             writer.Write(poseBuffer.Length);
             writer.Write(poseBuffer);
 
             PoseInfoSerializer.Serialize(meido.CachedPose, writer);
 
-            // v2 start
+            // TODO: Think about how to indicate code for new versions of serialization.
+            #region v2
             // sub mune rotation
             var body = meido.Body;
+
             writer.WriteQuaternion(body.GetBone("Mune_L_sub").localRotation);
             writer.WriteQuaternion(body.GetBone("Mune_R_sub").localRotation);
-            // v2 end
+            #endregion
         }
 
         private static void SerializeClothing(Meido meido, BinaryWriter writer)
@@ -127,19 +86,21 @@ namespace MeidoPhotoStudio.Plugin
             foreach (var clothingSlot in MaidDressingPane.ClothingSlots)
             {
                 var value = true;
+
                 if (clothingSlot == TBody.SlotID.wear)
                 {
                     if (MaidDressingPane.WearSlots.Any(slot => body.GetSlotLoaded(slot)))
-                    {
                         value = MaidDressingPane.WearSlots.Any(slot => body.GetMask(slot));
-                    }
                 }
                 else if (clothingSlot == TBody.SlotID.megane)
                 {
                     var slots = new[] { TBody.SlotID.megane, TBody.SlotID.accHead };
-                    if (slots.Any(slot => body.GetSlotLoaded(slot))) { value = slots.Any(slot => body.GetMask(slot)); }
+
+                    if (slots.Any(slot => body.GetSlotLoaded(slot)))
+                        value = slots.Any(slot => body.GetMask(slot));
                 }
-                else if (body.GetSlotLoaded(clothingSlot)) value = body.GetMask(clothingSlot);
+                else if (body.GetSlotLoaded(clothingSlot))
+                    value = body.GetMask(clothingSlot);
 
                 writer.Write(value);
             }
@@ -151,10 +112,12 @@ namespace MeidoPhotoStudio.Plugin
 
             // mpn attach props
             var hasKousokuUpper = body.GetSlotLoaded(TBody.SlotID.kousoku_upper);
+
             writer.Write(hasKousokuUpper);
             writer.Write(maid.GetProp(MPN.kousoku_upper).strTempFileName);
 
             var hasKousokuLower = body.GetSlotLoaded(TBody.SlotID.kousoku_lower);
+
             writer.Write(hasKousokuLower);
             writer.Write(maid.GetProp(MPN.kousoku_lower).strTempFileName);
 
@@ -190,7 +153,8 @@ namespace MeidoPhotoStudio.Plugin
             var offsetLookTarget = reader.ReadVector3();
             var headEulerAngle = reader.ReadVector3();
 
-            if (freeLook) body.offsetLookTarget = offsetLookTarget;
+            if (freeLook)
+                body.offsetLookTarget = offsetLookTarget;
 
             if (!metadata.MMConverted)
             {
@@ -202,10 +166,12 @@ namespace MeidoPhotoStudio.Plugin
             meido.EyeToCam = reader.ReadBoolean();
 
             var faceBlendCount = reader.ReadInt32();
+
             for (var i = 0; i < faceBlendCount; i++)
             {
                 var hash = reader.ReadString();
                 var value = reader.ReadSingle();
+
                 meido.SetFaceBlendValue(hash, value);
             }
         }
@@ -215,17 +181,21 @@ namespace MeidoPhotoStudio.Plugin
             var version = reader.ReadVersion();
 
             var muneSetting = new KeyValuePair<bool, bool>(true, true);
-            if (metadata.MMConverted) meido.IKManager.Deserialize(reader);
+
+            if (metadata.MMConverted)
+                meido.IKManager.Deserialize(reader);
             else
             {
                 var poseBufferLength = reader.ReadInt32();
-                byte[] poseBuffer = reader.ReadBytes(poseBufferLength);
+                var poseBuffer = reader.ReadBytes(poseBufferLength);
+
                 muneSetting = meido.SetFrameBinary(poseBuffer);
             }
 
             var poseInfo = PoseInfoSerializer.Deserialize(reader, metadata);
+
             Utility.SetPropertyValue(meido, nameof(Meido.CachedPose), poseInfo);
-            
+
             meido.SetMune(!muneSetting.Key, true);
             meido.SetMune(!muneSetting.Value);
 
@@ -255,7 +225,9 @@ namespace MeidoPhotoStudio.Plugin
             foreach (var clothingSlot in MaidDressingPane.ClothingSlots)
             {
                 var value = reader.ReadBoolean();
-                if (metadata.MMConverted) continue;
+
+                if (metadata.MMConverted)
+                    continue;
 
                 if (clothingSlot == TBody.SlotID.wear)
                 {
@@ -268,7 +240,8 @@ namespace MeidoPhotoStudio.Plugin
                     body.SetMask(TBody.SlotID.megane, value);
                     body.SetMask(TBody.SlotID.accHead, value);
                 }
-                else if (body.GetSlotLoaded(clothingSlot)) body.SetMask(clothingSlot, value);
+                else if (body.GetSlotLoaded(clothingSlot))
+                    body.SetMask(clothingSlot, value);
             }
 
             // zurashi and mekure
@@ -278,32 +251,96 @@ namespace MeidoPhotoStudio.Plugin
 
             if (!metadata.MMConverted)
             {
-                if (meido.CurlingFront != curlingFront) meido.SetCurling(Meido.Curl.Front, curlingFront);
-                if (meido.CurlingBack != curlingBack) meido.SetCurling(Meido.Curl.Back, curlingBack);
+                if (meido.CurlingFront != curlingFront)
+                    meido.SetCurling(Meido.Curl.Front, curlingFront);
+
+                if (meido.CurlingBack != curlingBack)
+                    meido.SetCurling(Meido.Curl.Back, curlingBack);
+
                 meido.SetCurling(Meido.Curl.Shift, curlingPantsu);
             }
 
             // MPN attach upper prop
             var hasKousokuUpper = reader.ReadBoolean();
             var upperMenuFile = reader.ReadString();
-            if (hasKousokuUpper) meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_upper, upperMenuFile), false);
+
+            if (hasKousokuUpper)
+                meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_upper, upperMenuFile), false);
 
             // MPN attach lower prop
             var hasKousokuLower = reader.ReadBoolean();
             var lowerMenuFile = reader.ReadString();
-            if (hasKousokuLower) meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_lower, lowerMenuFile), false);
+
+            if (hasKousokuLower)
+                meido.SetMpnProp(new MpnAttachProp(MPN.kousoku_lower, lowerMenuFile), false);
 
             // hair gravity
             var hairGravityActive = reader.ReadBoolean();
             var hairPosition = reader.ReadVector3();
+
             meido.HairGravityActive = hairGravityActive;
-            if (meido.HairGravityActive) meido.ApplyGravity(hairPosition);
+
+            if (meido.HairGravityActive)
+                meido.ApplyGravity(hairPosition);
 
             // skirt gravity
             var skirtGravityActive = reader.ReadBoolean();
             var skirtPosition = reader.ReadVector3();
+
             meido.SkirtGravityActive = skirtGravityActive;
-            if (meido.SkirtGravityActive) meido.ApplyGravity(skirtPosition, true);
+
+            if (meido.SkirtGravityActive)
+                meido.ApplyGravity(skirtPosition, true);
+        }
+
+        public override void Serialize(Meido meido, BinaryWriter writer)
+        {
+            var maid = meido.Maid;
+
+            using var memoryStream = new MemoryStream();
+            using var tempWriter = new BinaryWriter(memoryStream, Encoding.UTF8);
+
+            tempWriter.WriteVersion(version);
+
+            TransformDtoSerializer.Serialize(new TransformDTO(maid.transform), tempWriter);
+
+            SerializeHead(meido, tempWriter);
+
+            SerializeBody(meido, tempWriter);
+
+            SerializeClothing(meido, tempWriter);
+
+            writer.Write(memoryStream.Length);
+            writer.Write(memoryStream.ToArray());
+        }
+
+        public override void Deserialize(Meido meido, BinaryReader reader, SceneMetadata metadata)
+        {
+            var maid = meido.Maid;
+
+            maid.GetAnimation().Stop();
+            meido.DetachAllMpnAttach();
+            meido.StopBlink();
+
+            reader.ReadInt64(); // data length
+
+            _ = reader.ReadVersion();
+
+            var transformDto = TransformDtoSerializer.Deserialize(reader, metadata);
+            var maidTransform = maid.transform;
+
+            // TODO: use transform.SetRotationAndPosition
+            maidTransform.position = transformDto.Position;
+            maidTransform.rotation = transformDto.Rotation;
+            maidTransform.localScale = transformDto.LocalScale;
+
+            meido.IKManager.SetDragPointScale(maidTransform.localScale.x);
+
+            DeserializeHead(meido, reader, metadata);
+
+            DeserializeBody(meido, reader, metadata);
+
+            DeserializeClothing(meido, reader, metadata);
         }
     }
 }

+ 6 - 4
src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializer.cs

@@ -1,15 +1,17 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public abstract class SimpleSerializer<T> : ISimpleSerializer
     {
-        void ISimpleSerializer.Serialize(object obj, BinaryWriter writer) => Serialize((T) obj, writer);
+        void ISimpleSerializer.Serialize(object obj, BinaryWriter writer) =>
+            Serialize((T)obj, writer);
 
-        object ISimpleSerializer.Deserialize(BinaryReader reader, SceneMetadata metadata)
-            => Deserialize(reader, metadata);
+        object ISimpleSerializer.Deserialize(BinaryReader reader, SceneMetadata metadata) =>
+            Deserialize(reader, metadata);
 
         public abstract void Serialize(T obj, BinaryWriter writer);
+
         public abstract T Deserialize(BinaryReader reader, SceneMetadata metadata);
     }
 }

+ 8 - 5
src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/DragPointPropDTOSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -6,11 +6,14 @@ namespace MeidoPhotoStudio.Plugin
     {
         private const short version = 1;
 
-        private static SimpleSerializer<PropInfo> PropInfoSerializer => Serialization.GetSimple<PropInfo>();
-        private static SimpleSerializer<TransformDTO> TransformSerializer => Serialization.GetSimple<TransformDTO>();
+        private static SimpleSerializer<PropInfo> PropInfoSerializer =>
+            Serialization.GetSimple<PropInfo>();
 
-        private static SimpleSerializer<AttachPointInfo> AttachPointSerializer
-            => Serialization.GetSimple<AttachPointInfo>();
+        private static SimpleSerializer<TransformDTO> TransformSerializer =>
+            Serialization.GetSimple<TransformDTO>();
+
+        private static SimpleSerializer<AttachPointInfo> AttachPointSerializer =>
+            Serialization.GetSimple<AttachPointInfo>();
 
         public override void Serialize(DragPointPropDTO dragPointDto, BinaryWriter writer)
         {

+ 2 - 2
src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/PoseInfoSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -19,7 +19,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             _ = reader.ReadVersion();
 
-            return new PoseInfo(reader.ReadString(), reader.ReadString(), reader.ReadBoolean());
+            return new(reader.ReadString(), reader.ReadString(), reader.ReadBoolean());
         }
     }
 }

+ 3 - 3
src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/PropInfoSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 
 namespace MeidoPhotoStudio.Plugin
 {
@@ -10,7 +10,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             writer.WriteVersion(version);
 
-            writer.Write((int) info.Type);
+            writer.Write((int)info.Type);
             writer.WriteNullableString(info.Filename);
             writer.WriteNullableString(info.SubFilename);
             writer.Write(info.MyRoomID);
@@ -21,7 +21,7 @@ namespace MeidoPhotoStudio.Plugin
         {
             _ = reader.ReadVersion();
 
-            return new PropInfo ((PropInfo.PropType) reader.ReadInt32())
+            return new PropInfo((PropInfo.PropType)reader.ReadInt32())
             {
                 Filename = reader.ReadNullableString(),
                 SubFilename = reader.ReadNullableString(),

+ 1 - 1
src/MeidoPhotoStudio.Plugin/Serialization/SimpleSerializers/TransformDTOSerializer.cs

@@ -1,4 +1,4 @@
-using System.IO;
+using System.IO;
 using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin

+ 36 - 36
src/MeidoPhotoStudio.Plugin/Translation.cs

@@ -1,21 +1,26 @@
 using System;
-using System.Linq;
-using System.IO;
 using System.Collections.Generic;
-using Newtonsoft.Json.Linq;
+using System.IO;
+using System.Linq;
 using BepInEx.Configuration;
+using Newtonsoft.Json.Linq;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public static class Translation
     {
         private const string settingsHeader = "Translation";
+
         private static readonly string[] props = { "ui", "props", "bg", "face" };
-        private static Dictionary<string, Dictionary<string, string>> Translations;
         private static readonly ConfigEntry<string> currentLanguage;
         private static readonly ConfigEntry<bool> suppressWarnings;
+
+        private static Dictionary<string, Dictionary<string, string>> Translations;
         private static bool forceSuppressWarnings;
         private static bool suppressWarningsCached;
+
+        public static event EventHandler ReloadTranslationEvent;
+
         public static bool SuppressWarnings
         {
             get => suppressWarningsCached;
@@ -25,12 +30,12 @@ namespace MeidoPhotoStudio.Plugin
                 suppressWarnings.Value = value;
             }
         }
+
         public static string CurrentLanguage
         {
             get => currentLanguage.Value;
             set => currentLanguage.Value = value;
         }
-        public static event EventHandler ReloadTranslationEvent;
 
         static Translation()
         {
@@ -54,37 +59,34 @@ namespace MeidoPhotoStudio.Plugin
         {
             forceSuppressWarnings = false;
 
-            string rootTranslationPath = Path.Combine(Constants.configPath, Constants.translationDirectory);
-            string currentTranslationPath = Path.Combine(rootTranslationPath, language);
+            var rootTranslationPath = Path.Combine(Constants.configPath, Constants.translationDirectory);
+            var currentTranslationPath = Path.Combine(rootTranslationPath, language);
 
-            Translations = new Dictionary<string, Dictionary<string, string>>(
-                StringComparer.InvariantCultureIgnoreCase
-            );
+            Translations = new(StringComparer.InvariantCultureIgnoreCase);
 
             if (!Directory.Exists(currentTranslationPath))
             {
-                Utility.LogError(
-                    $"No translations found for '{language}' in '{currentTranslationPath}'"
-                );
+                Utility.LogError($"No translations found for '{language}' in '{currentTranslationPath}'");
                 forceSuppressWarnings = true;
+
                 return;
             }
 
-            foreach (string prop in props)
+            foreach (var prop in props)
             {
-                string translationFile = $"translation.{prop}.json";
+                var translationFile = $"translation.{prop}.json";
+
                 try
                 {
-                    string translationPath = Path.Combine(currentTranslationPath, translationFile);
-
-                    string translationJson = File.ReadAllText(translationPath);
-
-                    JObject translation = JObject.Parse(translationJson);
+                    var translationPath = Path.Combine(currentTranslationPath, translationFile);
+                    var translationJson = File.ReadAllText(translationPath);
+                    var translation = JObject.Parse(translationJson);
 
-                    foreach (JProperty translationProp in translation.AsJEnumerable())
+                    foreach (var translationProp in translation.AsJEnumerable().Cast<JProperty>())
                     {
-                        JToken token = translationProp.Value;
-                        Translations[translationProp.Path] = new Dictionary<string, string>(
+                        var token = translationProp.Value;
+
+                        Translations[translationProp.Path] = new(
                             token.ToObject<Dictionary<string, string>>(), StringComparer.InvariantCultureIgnoreCase
                         );
                     }
@@ -106,9 +108,12 @@ namespace MeidoPhotoStudio.Plugin
         public static bool Has(string category, string text, bool warn = false)
         {
             warn = !forceSuppressWarnings && !SuppressWarnings && warn;
+
             if (!Translations.ContainsKey(category))
             {
-                if (warn) Utility.LogWarning($"Could not translate '{text}': category '{category}' was not found");
+                if (warn)
+                    Utility.LogWarning($"Could not translate '{text}': category '{category}' was not found");
+
                 return false;
             }
 
@@ -120,25 +125,20 @@ namespace MeidoPhotoStudio.Plugin
                         $"Could not translate '{text}': '{text}' was not found in category '{category}'"
                     );
                 }
+
                 return false;
             }
 
             return true;
         }
 
-        public static string Get(string category, string text, bool warn = true)
-        {
-            return Has(category, text, warn) ? Translations[category][text] : text;
-        }
+        public static string Get(string category, string text, bool warn = true) =>
+            Has(category, text, warn) ? Translations[category][text] : text;
 
-        public static string[] GetArray(string category, IEnumerable<string> list)
-        {
-            return GetList(category, list).ToArray();
-        }
+        public static string[] GetArray(string category, IEnumerable<string> list) =>
+            GetList(category, list).ToArray();
 
-        public static IEnumerable<string> GetList(string category, IEnumerable<string> list)
-        {
-            return list.Select(uiName => Get(category, uiName));
-        }
+        public static IEnumerable<string> GetList(string category, IEnumerable<string> list) =>
+            list.Select(uiName => Get(category, uiName));
     }
 }

+ 165 - 135
src/MeidoPhotoStudio.Plugin/Utility.cs

@@ -1,237 +1,274 @@
 using System;
 using System.Collections.Generic;
-using System.Text.RegularExpressions;
 using System.IO;
-using System.Reflection;
-using UnityEngine;
 using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
 using Ionic.Zlib;
+using UnityEngine;
 
 namespace MeidoPhotoStudio.Plugin
 {
     public static class Utility
     {
+        public enum ModKey { Control, Shift, Alt }
+
         private const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
             | BindingFlags.Static;
+
+        public static readonly BepInEx.Logging.ManualLogSource Logger =
+            BepInEx.Logging.Logger.CreateLogSource(MeidoPhotoStudio.pluginName);
+
+        public static string Timestamp =>
+            $"{DateTime.Now:yyyyMMddHHmmss}";
+
+        public static Vector3 MousePosition =>
+            mousePosition.Position;
+
         internal static readonly byte[] pngHeader = { 137, 80, 78, 71, 13, 10, 26, 10 };
         internal static readonly byte[] pngEnd = System.Text.Encoding.ASCII.GetBytes("IEND");
-        internal static readonly Regex guidRegEx = new Regex(
+        internal static readonly Regex guidRegEx = new(
             @"^[a-f0-9]{8}(\-[a-f0-9]{4}){3}\-[a-f0-9]{12}$", RegexOptions.IgnoreCase
         );
         internal static readonly GameObject mousePositionGo;
         internal static readonly MousePosition mousePosition;
-        public static readonly BepInEx.Logging.ManualLogSource Logger
-            = BepInEx.Logging.Logger.CreateLogSource(MeidoPhotoStudio.pluginName);
-        public enum ModKey
-        {
-            Control, Shift, Alt
-        }
-        public static string Timestamp => $"{DateTime.Now:yyyyMMddHHmmss}";
-        public static Vector3 MousePosition => mousePosition.Position;
 
         static Utility()
         {
-            mousePositionGo = new GameObject();
+            mousePositionGo = new();
             mousePosition = mousePositionGo.AddComponent<MousePosition>();
         }
 
-        public static void LogInfo(object data) => Logger.LogInfo(data);
+        public static void LogInfo(object data) =>
+            Logger.LogInfo(data);
 
-        public static void LogMessage(object data) => Logger.LogMessage(data);
+        public static void LogMessage(object data) =>
+            Logger.LogMessage(data);
 
-        public static void LogWarning(object data) => Logger.LogWarning(data);
+        public static void LogWarning(object data) =>
+            Logger.LogWarning(data);
 
-        public static void LogError(object data) => Logger.LogError(data);
+        public static void LogError(object data) =>
+            Logger.LogError(data);
 
-        public static void LogDebug(object data) => Logger.LogDebug(data);
+        public static void LogDebug(object data) =>
+            Logger.LogDebug(data);
 
         public static int Wrap(int value, int min, int max)
         {
             max--;
+
             return value < min ? max : value > max ? min : value;
         }
 
-        public static int GetPix(int num) => (int)((1f + (((Screen.width / 1280f) - 1f) * 0.6f)) * num);
+        public static int GetPix(int num) =>
+            (int)((1f + (Screen.width / 1280f - 1f) * 0.6f) * num);
 
-        public static float Bound(float value, float left, float right)
-        {
-            return left > (double)right ? Mathf.Clamp(value, right, left) : Mathf.Clamp(value, left, right);
-        }
+        public static float Bound(float value, float left, float right) =>
+            left > (double)right ? Mathf.Clamp(value, right, left) : Mathf.Clamp(value, left, right);
 
-        public static int Bound(int value, int left, int right)
-        {
-            return left > right ? Mathf.Clamp(value, right, left) : Mathf.Clamp(value, left, right);
-        }
+        public static int Bound(int value, int left, int right) =>
+            left > right ? Mathf.Clamp(value, right, left) : Mathf.Clamp(value, left, right);
 
         public static Texture2D MakeTex(int width, int height, Color color)
         {
-            Color[] colors = new Color[width * height];
-            for (int i = 0; i < colors.Length; i++)
-            {
+            var colors = new Color32[width * height];
+
+            for (var i = 0; i < colors.Length; i++)
                 colors[i] = color;
-            }
-            Texture2D texture2D = new Texture2D(width, height);
-            texture2D.SetPixels(colors);
+
+            var texture2D = new Texture2D(width, height);
+
+            texture2D.SetPixels32(colors);
             texture2D.Apply();
+
             return texture2D;
         }
 
-        public static FieldInfo GetFieldInfo<T>(string field) => typeof(T).GetField(field, bindingFlags);
+        public static FieldInfo GetFieldInfo<T>(string field) =>
+            typeof(T).GetField(field, bindingFlags);
 
         public static TValue GetFieldValue<TType, TValue>(TType instance, string field)
         {
-            FieldInfo fieldInfo = GetFieldInfo<TType>(field);
-            if (fieldInfo == null || (!fieldInfo.IsStatic && instance == null)) return default;
-            return (TValue)fieldInfo.GetValue(instance);
+            var fieldInfo = GetFieldInfo<TType>(field);
+
+            return fieldInfo is null || !fieldInfo.IsStatic && instance == null
+                ? default :
+                (TValue)fieldInfo.GetValue(instance);
         }
 
-        public static void SetFieldValue<TType, TValue>(TType instance, string name, TValue value)
-        {
+        public static void SetFieldValue<TType, TValue>(TType instance, string name, TValue value) =>
             GetFieldInfo<TType>(name).SetValue(instance, value);
-        }
 
-        public static PropertyInfo GetPropertyInfo<T>(string field) => typeof(T).GetProperty(field, bindingFlags);
+        public static PropertyInfo GetPropertyInfo<T>(string field) =>
+            typeof(T).GetProperty(field, bindingFlags);
 
         public static TValue GetPropertyValue<TType, TValue>(TType instance, string property)
         {
             var propertyInfo = GetPropertyInfo<TType>(property);
-            return propertyInfo == null ? default : (TValue) propertyInfo.GetValue(instance, null);
-        }
-        
-        public static void SetPropertyValue<TType, TValue>(TType instance, string name, TValue value) 
-            => GetPropertyInfo<TType>(name).SetValue(instance, value, null);
 
-        public static bool AnyMouseDown()
-        {
-            return Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2);
+            return propertyInfo is null
+                ? default
+                : (TValue)propertyInfo.GetValue(instance, null);
         }
 
+        public static void SetPropertyValue<TType, TValue>(TType instance, string name, TValue value) =>
+            GetPropertyInfo<TType>(name).SetValue(instance, value, null);
+
+        public static bool AnyMouseDown() =>
+            Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1) || Input.GetMouseButtonDown(2);
+
         public static string ScreenshotFilename()
         {
-            string screenShotDir = Path.Combine(
+            var screenShotDir = Path.Combine(
                 GameMain.Instance.SerializeStorageManager.StoreDirectoryPath, "ScreenShot"
             );
-            if (!Directory.Exists(screenShotDir)) Directory.CreateDirectory(screenShotDir);
+
+            if (!Directory.Exists(screenShotDir))
+                Directory.CreateDirectory(screenShotDir);
+
             return Path.Combine(screenShotDir, $"img{Timestamp}.png");
         }
 
-        public static string TempScreenshotFilename()
-        {
-            return Path.Combine(Path.GetTempPath(), $"cm3d2_{Guid.NewGuid()}.png");
-        }
+        public static string TempScreenshotFilename() =>
+            Path.Combine(Path.GetTempPath(), $"cm3d2_{Guid.NewGuid()}.png");
 
         public static void ShowMouseExposition(string text, float time = 2f)
         {
-            MouseExposition mouseExposition = MouseExposition.GetObject();
+            var mouseExposition = MouseExposition.GetObject();
+
             mouseExposition.SetText(text, time);
         }
 
-        public static bool IsGuidString(string guid)
-        {
-            if (string.IsNullOrEmpty(guid) || guid.Length != 36) return false;
-            return guidRegEx.IsMatch(guid);
-        }
+        public static bool IsGuidString(string guid) =>
+            !string.IsNullOrEmpty(guid) && guid.Length is 36 && guidRegEx.IsMatch(guid);
 
         public static string HandItemToOdogu(string menu)
         {
             menu = menu.Substring(menu.IndexOf('_') + 1);
             menu = menu.Substring(0, menu.IndexOf("_i_.menu", StringComparison.OrdinalIgnoreCase));
             menu = $"odogu_{menu}";
+
             return menu;
         }
 
         public static void FixGameObjectScale(GameObject go)
         {
-            Vector3 scale = go.transform.localScale;
-            float largest = Mathf.Max(scale.x, Mathf.Max(scale.y, scale.z));
+            var scale = go.transform.localScale;
+            var largest = Mathf.Max(scale.x, Mathf.Max(scale.y, scale.z));
+
             go.transform.localScale = Vector3.one * (float)Math.Round(largest, 3);
         }
 
         public static string SanitizePathPortion(string path)
         {
-            char[] invalid = Path.GetInvalidFileNameChars();
+            var invalid = Path.GetInvalidFileNameChars();
+
             path = path.Trim();
             path = string.Join("_", path.Split(invalid)).Replace(".", "").Trim('_');
+
             return path;
         }
 
         public static string GP01FbFaceHash(TMorph face, string hash)
         {
-            if ((face.bodyskin.PartsVersion >= 120) && (hash != "eyeclose3") && hash.StartsWith("eyeclose"))
+            if (face.bodyskin.PartsVersion >= 120 && hash is not "eyeclose3" && hash.StartsWith("eyeclose"))
             {
-                if (hash == "eyeclose") hash += '1';
+                if (hash is "eyeclose")
+                    hash += '1';
+
                 hash += TMorph.crcFaceTypesStr[(int)face.GetFaceTypeGP01FB()];
             }
+
             return hash;
         }
 
         public static void ResizeToFit(Texture2D texture, int maxWidth, int maxHeight)
         {
-            int width = texture.width;
-            int height = texture.height;
-            if (width != maxWidth || height != maxHeight)
-            {
-                float scale = Mathf.Min(maxWidth / (float)width, maxHeight / (float)height);
-                width = Mathf.RoundToInt(width * scale);
-                height = Mathf.RoundToInt(height * scale);
-                TextureScale.Bilinear(texture, width, height);
-            }
+            var width = texture.width;
+            var height = texture.height;
+
+            if (width == maxWidth && height == maxHeight)
+                return;
+
+            var scale = Mathf.Min(maxWidth / (float)width, maxHeight / (float)height);
+
+            width = Mathf.RoundToInt(width * scale);
+            height = Mathf.RoundToInt(height * scale);
+            TextureScale.Bilinear(texture, width, height);
         }
 
         public static bool BytesEqual(byte[] buffer, byte[] other)
         {
-            if (buffer.Length != other.Length) return false;
-            for (int i = 0; i < buffer.Length; i++)
-            {
-                if (buffer[i] != other[i]) return false;
-            }
+            if (buffer.Length != other.Length)
+                return false;
+
+            for (var i = 0; i < buffer.Length; i++)
+                if (buffer[i] != other[i])
+                    return false;
+
             return true;
         }
 
         public static bool IsPngFile(Stream stream)
         {
-            byte[] buffer = new byte[8];
+            var buffer = new byte[8];
+
             stream.Read(buffer, 0, 8);
+
             return BytesEqual(buffer, pngHeader);
         }
 
         public static bool SeekPngEnd(Stream stream)
         {
-            byte[] buffer = new byte[8];
+            var buffer = new byte[8];
+
             stream.Read(buffer, 0, 8);
-            if (!BytesEqual(buffer, pngHeader)) return false;
+
+            if (!BytesEqual(buffer, pngHeader))
+                return false;
+
             buffer = new byte[4];
+
             do
             {
                 stream.Read(buffer, 0, 4);
-                if (BitConverter.IsLittleEndian) Array.Reverse(buffer);
-                uint length = BitConverter.ToUInt32(buffer, 0);
+
+                if (BitConverter.IsLittleEndian)
+                    Array.Reverse(buffer);
+
+                var length = BitConverter.ToUInt32(buffer, 0);
+
                 stream.Read(buffer, 0, 4);
                 stream.Seek(length + 4L, SeekOrigin.Current);
             } while (!BytesEqual(buffer, pngEnd));
+
             return true;
         }
 
-        public static void WriteToFile(string name, System.Collections.Generic.IEnumerable<string> list)
+        public static void WriteToFile(string name, IEnumerable<string> list)
         {
-            if (Path.GetExtension(name) != ".txt") name += ".txt";
+            if (Path.GetExtension(name) is not ".txt")
+                name += ".txt";
+
             File.WriteAllLines(Path.Combine(Constants.configPath, name), list.ToArray());
         }
 
-        public static void WriteToFile(string name, byte[] data)
-        {
+        public static void WriteToFile(string name, byte[] data) =>
             File.WriteAllBytes(Path.Combine(Constants.configPath, name), data);
-        }
     }
 
     public class MousePosition : MonoBehaviour
     {
+        public Vector3 Position =>
+            mousePosition;
+
         private Vector3 mousePosition;
-        public Vector3 Position => mousePosition;
 
         private void Awake()
         {
             DontDestroyOnLoad(this);
+
             mousePosition = Input.mousePosition;
         }
 
@@ -242,7 +279,8 @@ namespace MeidoPhotoStudio.Plugin
                 mousePosition.x += Input.GetAxis("Mouse X") * 20;
                 mousePosition.y += Input.GetAxis("Mouse Y") * 20;
             }
-            else mousePosition = Input.mousePosition;
+            else
+                mousePosition = Input.mousePosition;
         }
     }
 
@@ -262,14 +300,17 @@ namespace MeidoPhotoStudio.Plugin
         public static void CopyTo(this Stream stream, Stream outStream)
         {
             var buf = new byte[1024 * 32];
+
             int length;
-            while ((length = stream.Read(buf, 0, buf.Length)) > 0) 
+
+            while ((length = stream.Read(buf, 0, buf.Length)) > 0)
                 outStream.Write(buf, 0, length);
         }
 
         public static MemoryStream Decompress(this MemoryStream stream)
         {
             var dataMemoryStream = new MemoryStream();
+
             using var compressionStream = new DeflateStream(stream, CompressionMode.Decompress, true);
 
             compressionStream.CopyTo(dataMemoryStream);
@@ -280,8 +321,8 @@ namespace MeidoPhotoStudio.Plugin
             return dataMemoryStream;
         }
 
-        public static DeflateStream GetCompressionStream(this MemoryStream stream)
-            => new(stream, CompressionMode.Compress);
+        public static DeflateStream GetCompressionStream(this MemoryStream stream) =>
+            new(stream, CompressionMode.Compress);
     }
 
     public static class CameraUtility
@@ -289,14 +330,15 @@ namespace MeidoPhotoStudio.Plugin
         public static CameraMain MainCamera => GameMain.Instance.MainCamera;
         public static UltimateOrbitCamera UOCamera { get; } =
             GameMain.Instance.MainCamera.GetComponent<UltimateOrbitCamera>();
-        
+
         public static void StopSpin()
         {
             Utility.SetFieldValue(UOCamera, "xVelocity", 0f);
             Utility.SetFieldValue(UOCamera, "yVelocity", 0f);
         }
 
-        public static void StopMovement() => MainCamera.SetTargetPos(MainCamera.GetTargetPos());
+        public static void StopMovement() =>
+            MainCamera.SetTargetPos(MainCamera.GetTargetPos());
 
         public static void StopAll()
         {
@@ -313,7 +355,9 @@ namespace MeidoPhotoStudio.Plugin
 
         public static void ResetCalcNearClip(this CameraMain camera)
         {
-            if (camera.m_bCalcNearClip) return;
+            if (camera.m_bCalcNearClip)
+                return;
+
             camera.StopAllCoroutines();
             camera.m_bCalcNearClip = true;
             camera.Start();
@@ -322,15 +366,15 @@ namespace MeidoPhotoStudio.Plugin
 
     public static class BinaryExtensions
     {
-        public static string ReadNullableString(this BinaryReader binaryReader)
-        {
-            return binaryReader.ReadBoolean() ? binaryReader.ReadString() : null;
-        }
+        public static string ReadNullableString(this BinaryReader binaryReader) =>
+            binaryReader.ReadBoolean() ? binaryReader.ReadString() : null;
 
         public static void WriteNullableString(this BinaryWriter binaryWriter, string str)
         {
-            binaryWriter.Write(str != null);
-            if (str != null) binaryWriter.Write(str);
+            binaryWriter.Write(str is not null);
+
+            if (str is not null)
+                binaryWriter.Write(str);
         }
 
         public static void Write(this BinaryWriter binaryWriter, Vector3 vector3)
@@ -347,25 +391,16 @@ namespace MeidoPhotoStudio.Plugin
             binaryWriter.Write(vector3.z);
         }
 
-        public static Vector2 ReadVector2(this BinaryReader binaryReader)
-        {
-            return new Vector2(binaryReader.ReadSingle(), binaryReader.ReadSingle());
-        }
+        public static Vector2 ReadVector2(this BinaryReader binaryReader) =>
+            new(binaryReader.ReadSingle(), binaryReader.ReadSingle());
 
-        public static Vector3 ReadVector3(this BinaryReader binaryReader)
-        {
-            return new Vector3(
-                binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle()
-            );
-        }
+        public static Vector3 ReadVector3(this BinaryReader binaryReader) =>
+            new(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle());
 
-        public static Vector4 ReadVector4(this BinaryReader binaryReader)
-        {
-            return new Vector4(
-                binaryReader.ReadSingle(), binaryReader.ReadSingle(),
-                binaryReader.ReadSingle(), binaryReader.ReadSingle()
+        public static Vector4 ReadVector4(this BinaryReader binaryReader) =>
+            new(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(),
+                binaryReader.ReadSingle()
             );
-        }
 
         public static void Write(this BinaryWriter binaryWriter, Quaternion quaternion)
         {
@@ -383,14 +418,10 @@ namespace MeidoPhotoStudio.Plugin
             binaryWriter.Write(quaternion.w);
         }
 
-        public static Quaternion ReadQuaternion(this BinaryReader binaryReader)
-        {
-            return new Quaternion
-            (
-                binaryReader.ReadSingle(), binaryReader.ReadSingle(),
-                binaryReader.ReadSingle(), binaryReader.ReadSingle()
+        public static Quaternion ReadQuaternion(this BinaryReader binaryReader) =>
+            new(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(),
+                binaryReader.ReadSingle()
             );
-        }
 
         public static void Write(this BinaryWriter binaryWriter, Color colour)
         {
@@ -408,19 +439,18 @@ namespace MeidoPhotoStudio.Plugin
             binaryWriter.Write(colour.a);
         }
 
-        public static Color ReadColour(this BinaryReader binaryReader)
-        {
-            return new Color
-            (
-                binaryReader.ReadSingle(), binaryReader.ReadSingle(),
-                binaryReader.ReadSingle(), binaryReader.ReadSingle()
+        public static Color ReadColour(this BinaryReader binaryReader) =>
+            new(binaryReader.ReadSingle(), binaryReader.ReadSingle(), binaryReader.ReadSingle(),
+                binaryReader.ReadSingle()
             );
-        }
 
         public static Matrix4x4 ReadMatrix4x4(this BinaryReader binaryReader)
         {
             Matrix4x4 matrix = default;
-            for (var i = 0; i < 16; i++) matrix[i] = binaryReader.ReadSingle();
+
+            for (var i = 0; i < 16; i++)
+                matrix[i] = binaryReader.ReadSingle();
+
             return matrix;
         }
     }

+ 1 - 1
src/MeidoPhotoStudio.Plugin/WindowsLogicalComparer.cs

@@ -1,4 +1,4 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
 using System.Runtime.InteropServices;
 
 namespace MeidoPhotoStudio.Plugin